From eabb1c5aa6a15f5082397542bd4f28ed70d4bf44 Mon Sep 17 00:00:00 2001 From: medley Date: Sat, 3 Jan 2026 12:53:38 -0700 Subject: [PATCH] fix(done): detect default branch instead of hardcoding 'main' (#42) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds RemoteDefaultBranch() to git.go that detects the repo's actual default branch by checking origin/HEAD, then falling back to checking for origin/master or origin/main. Updates done.go to use this detection instead of hardcoded "main": - Line 168: CommitsAhead now uses detected default branch - Line 173: Error message uses detected branch name - Line 187: Target branch defaults to detected branch Fixes repos using 'master' as default branch (pre-2020 repos). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.5 Co-authored-by: Steve Yegge --- internal/cmd/done.go | 13 ++++++++----- internal/git/git.go | 30 ++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/internal/cmd/done.go b/internal/cmd/done.go index 45f55f77..c841e63c 100644 --- a/internal/cmd/done.go +++ b/internal/cmd/done.go @@ -164,13 +164,16 @@ func runDone(cmd *cobra.Command, args []string) error { return fmt.Errorf("branch has %d unpushed commit(s); run 'git push -u origin %s' first", unpushedCount, branch) } - // Check that branch has commits ahead of main (prevents submitting stale branches) - aheadCount, err := g.CommitsAhead("main", branch) + // Detect the repo's default branch (main vs master) + defaultBranch := g.RemoteDefaultBranch() + + // Check that branch has commits ahead of default branch (prevents submitting stale branches) + aheadCount, err := g.CommitsAhead(defaultBranch, branch) if err != nil { - return fmt.Errorf("checking commits ahead of main: %w", err) + return fmt.Errorf("checking commits ahead of %s: %w", defaultBranch, err) } if aheadCount == 0 { - return fmt.Errorf("branch '%s' has 0 commits ahead of main; nothing to merge", branch) + return fmt.Errorf("branch '%s' has 0 commits ahead of %s; nothing to merge", branch, defaultBranch) } if issueID == "" { @@ -181,7 +184,7 @@ func runDone(cmd *cobra.Command, args []string) error { bd := beads.New(cwd) // Determine target branch (auto-detect integration branch if applicable) - target := "main" + target := defaultBranch autoTarget, err := detectIntegrationBranch(bd, g, issueID) if err == nil && autoTarget != "" { target = autoTarget diff --git a/internal/git/git.go b/internal/git/git.go index e04d9998..28ff3ac5 100644 --- a/internal/git/git.go +++ b/internal/git/git.go @@ -255,6 +255,36 @@ func (g *Git) DefaultBranch() string { return "main" } +// RemoteDefaultBranch returns the default branch from the remote (origin). +// This is useful in worktrees where HEAD may not reflect the repo's actual default. +// Checks origin/HEAD first, then falls back to checking if master/main exists. +// Returns "main" as final fallback. +func (g *Git) RemoteDefaultBranch() string { + // Try to get from origin/HEAD symbolic ref + out, err := g.run("symbolic-ref", "refs/remotes/origin/HEAD") + if err == nil && out != "" { + // Returns refs/remotes/origin/main -> extract branch name + parts := strings.Split(out, "/") + if len(parts) > 0 { + return parts[len(parts)-1] + } + } + + // Fallback: check if origin/master exists + _, err = g.run("rev-parse", "--verify", "origin/master") + if err == nil { + return "master" + } + + // Fallback: check if origin/main exists + _, err = g.run("rev-parse", "--verify", "origin/main") + if err == nil { + return "main" + } + + return "main" // final fallback +} + // HasUncommittedChanges returns true if there are uncommitted changes. func (g *Git) HasUncommittedChanges() (bool, error) { status, err := g.Status()