()
| 575 | * Priority: tracking branch > origin/main > origin/staging > origin/master |
| 576 | */ |
| 577 | export async function findRemoteBase(): Promise<string | null> { |
| 578 | // First try: get the tracking branch for the current branch |
| 579 | const { stdout: trackingBranch, code: trackingCode } = await execFileNoThrow( |
| 580 | gitExe(), |
| 581 | ['rev-parse', '--abbrev-ref', '--symbolic-full-name', '@{u}'], |
| 582 | { preserveOutputOnError: false }, |
| 583 | ) |
| 584 | |
| 585 | if (trackingCode === 0 && trackingBranch.trim()) { |
| 586 | return trackingBranch.trim() |
| 587 | } |
| 588 | |
| 589 | // Second try: check for common default branch names on origin |
| 590 | const { stdout: remoteRefs, code: remoteCode } = await execFileNoThrow( |
| 591 | gitExe(), |
| 592 | ['remote', 'show', 'origin', '--', 'HEAD'], |
| 593 | { preserveOutputOnError: false }, |
| 594 | ) |
| 595 | |
| 596 | if (remoteCode === 0) { |
| 597 | // Parse the default branch from remote show output |
| 598 | const match = remoteRefs.match(/HEAD branch: (\S+)/) |
| 599 | if (match && match[1]) { |
| 600 | return `origin/${match[1]}` |
| 601 | } |
| 602 | } |
| 603 | |
| 604 | // Third try: check which common branches exist |
| 605 | const candidates = ['origin/main', 'origin/staging', 'origin/master'] |
| 606 | for (const candidate of candidates) { |
| 607 | const { code } = await execFileNoThrow( |
| 608 | gitExe(), |
| 609 | ['rev-parse', '--verify', candidate], |
| 610 | { preserveOutputOnError: false }, |
| 611 | ) |
| 612 | if (code === 0) { |
| 613 | return candidate |
| 614 | } |
| 615 | } |
| 616 | |
| 617 | return null |
| 618 | } |
| 619 | |
| 620 | /** |
| 621 | * Check if we're in a shallow clone by looking for <gitDir>/shallow. |
no test coverage detected