diff --git a/internal/doctor/branch_check.go b/internal/doctor/branch_check.go index 23531aca..bd3e30d3 100644 --- a/internal/doctor/branch_check.go +++ b/internal/doctor/branch_check.go @@ -1,11 +1,13 @@ package doctor import ( + "context" "fmt" "os" "os/exec" "path/filepath" "strings" + "time" ) // BranchCheck detects persistent roles (crew, witness, refinery) that are @@ -103,13 +105,16 @@ func (c *BranchCheck) Fix(ctx *CheckContext) error { continue } - // git pull --rebase - cmd = exec.Command("git", "pull", "--rebase") + // git pull --rebase (with timeout to prevent hanging on network issues) + pullCtx, pullCancel := context.WithTimeout(context.Background(), 30*time.Second) + cmd = exec.CommandContext(pullCtx, "git", "pull", "--rebase") cmd.Dir = dir if err := cmd.Run(); err != nil { // Pull failure is not fatal, just warn + pullCancel() continue } + pullCancel() } return lastErr @@ -527,7 +532,15 @@ func (c *CloneDivergenceCheck) getCloneInfo(path string) (cloneInfo, error) { } info.headSHA = strings.TrimSpace(string(out)) - // Count commits behind origin/main (uses existing refs, may be stale) + // Fetch to make sure we have latest refs (silent, ignore errors) + // Use a short timeout to prevent hanging on network issues, SSH prompts, or credential dialogs + fetchCtx, fetchCancel := context.WithTimeout(context.Background(), 5*time.Second) + defer fetchCancel() + cmd = exec.CommandContext(fetchCtx, "git", "fetch", "--quiet") + cmd.Dir = path + _ = cmd.Run() + + // Count commits behind origin/main cmd = exec.Command("git", "rev-list", "--count", "HEAD..origin/main") cmd.Dir = path out, err = cmd.Output()