surshar / claude-code
Claude Code is an agentic coding tool that lives in your terminal, understands your codebase, and helps you code faster by executing routine tasks, explaining complex code, and handling git workflows - all through natural language commands.
Built by Anthropic · github.com/anthropics
| 1 | import Argv from '../../argv' |
| 2 | import type Types from '../../types' |
| 3 | import { currentBranchOf } from '../current-branch-of' |
| 4 | import { defaultBranchOf } from '../default-branch-of' |
| 5 | import { mergeBaseCandidatesOf } from '../merge-base-candidates-of' |
| 6 | import { missingBaseOf } from '../missing-base-of' |
| 7 | |
| 8 | /** |
| 9 | * What branch mode compares against, resolved as the built-in panel does: |
| 10 | * the merge-base of HEAD and the default branch, HEAD itself, or none. |
| 11 | * |
| 12 | * `origin/<default>` wins unless the local ref's base descends from it; a |
| 13 | * detached HEAD, a `-`-led default name or no common ancestor is `none`; |
| 14 | * a failure that may pass (a ref still there, a failed rev-parse) `error`. |
| 15 | * |
| 16 | * @param run runs git |
| 17 | * @returns the base |
| 18 | */ |
| 19 | export async function branchBaseOf( |
| 20 | run: Types.GitRun, |
| 21 | ): Promise<Types.BranchBase> { |
| 22 | const [branch, defaultBranch] = await Promise.all([ |
| 23 | currentBranchOf(run), |
| 24 | defaultBranchOf(run), |
| 25 | ]) |
| 26 | |
| 27 | const isUnrelated = branch === 'HEAD' || defaultBranch.startsWith('-') |
| 28 | |
| 29 | if (isUnrelated) { |
| 30 | return { kind: 'none' } |
| 31 | } |
| 32 | |
| 33 | if (branch === defaultBranch) { |
| 34 | return { kind: 'head-is-base', baseBranch: defaultBranch } |
| 35 | } |
| 36 | |
| 37 | const { candidates, hasNoCommonAncestor } = await mergeBaseCandidatesOf( |
| 38 | run, |
| 39 | defaultBranch, |
| 40 | ) |
| 41 | |
| 42 | const [first, second] = candidates |
| 43 | |
| 44 | if (first === undefined) { |
| 45 | return hasNoCommonAncestor |
| 46 | ? { kind: 'none' } |
| 47 | : missingBaseOf(run, defaultBranch) |
| 48 | } |
| 49 | |
| 50 | const isLocalBaseNewer = |
| 51 | second !== undefined && |
| 52 | second !== first && |
| 53 | ( |
| 54 | await run([ |
| 55 | Argv.NO_OPTIONAL_LOCKS, |
| 56 | 'merge-base', |
| 57 | '--is-ancestor', |
| 58 | first, |
| 59 | second, |
| 60 | ]) |
| 61 | ).exitCode === 0 |
| 62 | |
| 63 | const mergeBase = isLocalBaseNewer ? second : first |
| 64 | const head = await run([Argv.NO_OPTIONAL_LOCKS, 'rev-parse', 'HEAD']) |
| 65 | |
| 66 | if (head.exitCode !== 0) { |
| 67 | return { kind: 'error', reason: 'head_rev_parse_failed' } |
| 68 | } |
| 69 | |
| 70 | const isHeadTheBase = head.stdout.trim() === mergeBase |
| 71 | |
| 72 | return isHeadTheBase |
| 73 | ? { kind: 'head-is-base', baseBranch: defaultBranch } |
| 74 | : { kind: 'merge-base', mergeBase, baseBranch: defaultBranch } |
| 75 | } |