From b9ad30a4a93a10350668a979ee25fb7750c6d601 Mon Sep 17 00:00:00 2001 From: Steve Yegge Date: Thu, 25 Dec 2025 19:36:19 -0800 Subject: [PATCH] fix(spawn): reset stale polecat branches to origin/main MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When recreating a polecat worktree, the branch deletion might fail silently, leaving a stale branch with old commits. The worktree would then be created from this stale branch, missing recent main changes. Fix: - Add ResetBranch() method to git package for force-updating branches - Fetch from origin before recreation to ensure fresh commits - If branch deletion fails, force-reset the branch to origin/main - This ensures polecats always start with the latest code Discovered during gt-8tmz swarm when nux polecat was missing the internal/formula/ directory that was added after its branch diverged. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- internal/git/git.go | 7 +++++++ internal/polecat/manager.go | 12 +++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/internal/git/git.go b/internal/git/git.go index a575363c..f71325e4 100644 --- a/internal/git/git.go +++ b/internal/git/git.go @@ -401,6 +401,13 @@ func (g *Git) DeleteBranch(name string, force bool) error { return err } +// ResetBranch force-updates a branch to point to a ref. +// This is useful for resetting stale polecat branches to main. +func (g *Git) ResetBranch(name, ref string) error { + _, err := g.run("branch", "-f", name, ref) + return err +} + // Rev returns the commit hash for the given ref. func (g *Git) Rev(ref string) (string, error) { return g.run("rev-parse", ref) diff --git a/internal/polecat/manager.go b/internal/polecat/manager.go index 72f64f8d..39ec3d35 100644 --- a/internal/polecat/manager.go +++ b/internal/polecat/manager.go @@ -304,6 +304,9 @@ func (m *Manager) Recreate(name string, force bool) (*Polecat, error) { // Prune stale worktree entries _ = repoGit.WorktreePrune() + // Fetch latest from origin to ensure we have fresh commits + _ = repoGit.Fetch("origin") + // Delete the old branch so worktree starts fresh from current HEAD // Ignore error - branch may not exist (first recreate) or may fail to delete _ = repoGit.DeleteBranch(branchName, true) @@ -316,10 +319,13 @@ func (m *Manager) Recreate(name string, force bool) (*Polecat, error) { // Create worktree - handle both cases like Add() does if branchExists { - // Branch still exists, create worktree using existing branch - // This happens if delete failed (e.g., protected branch) + // Branch still exists after deletion attempt - force-reset to origin/main + // This ensures the polecat starts with fresh code, not stale commits + if err := repoGit.ResetBranch(branchName, "origin/main"); err != nil { + return nil, fmt.Errorf("resetting stale branch to origin/main: %w", err) + } if err := repoGit.WorktreeAddExisting(polecatPath, branchName); err != nil { - return nil, fmt.Errorf("creating worktree with existing branch: %w", err) + return nil, fmt.Errorf("creating worktree with reset branch: %w", err) } } else { // Branch was deleted, create fresh worktree with new branch from HEAD