Skip to content

Commit 5f335ce

Browse files
authored
fix(sync): include git stderr in branch-delete fatal error message (#719)
## Summary Partially addresses #656. When `av sync --prune` (or any code path hitting `runDelete` in `internal/git/gitui/prune.go`) fails to delete a merged branch for a reason *other than* worktree ownership, the error message now includes the git stderr instead of the opaque `exit status 1`. ## Why this matters Issue #656 reports the user-facing error: ``` error: cannot delete merged branch "more_ci_improvements": git branch: exit status 1 ``` The "cannot delete merged branch" wrapper text traces to line 235 of `prune.go`, where the fatal-error path formatted the underlying error with `%v`. Since the error is an `*exec.ExitError`, `%v` resolves to `exit status 1` — stripping off the stderr git wrote to explain the failure. PR #660 already handled the specific "used by worktree" phrasing by catching that stderr and producing a recovery-oriented message, but any other failure reason still fell into this opaque path. ## What changed `internal/git/gitui/prune.go` — inside `runDelete()`, the `else` branch (non-worktree fatal error) now pulls `exiterr.Stderr` off the `*exec.ExitError` (same `errutils.As` helper the worktree check above already uses) and passes it to the error message: ```go errMsg := err.Error() if exiterr, ok := errutils.As[*exec.ExitError](err); ok { if stderr := strings.TrimSpace(string(exiterr.Stderr)); stderr != "" { errMsg = stderr } } deletionErr = errors.Errorf("cannot delete merged branch %q: %s", branch.branch.Short(), errMsg) ``` So the user now sees whatever git actually said rather than the wrapped shell status. ## Scope notes - The existing worktree-error handling (added in #660) is untouched; its friendlier recovery message still applies to "used by worktree" stderr. - The detached-HEAD concern from #656's second paragraph is already handled by the unconditional `CheckoutInitialState()` call after the delete loop; no change needed there. - Marking this as `Part of #656` rather than `Closes` because the issue's language covers worktree-specific UX that was delivered in #660, and this PR fills the remaining surface for non-worktree failures. ## Testing ``` go vet ./... # pass go build ./... # pass go test ./internal/git/... ./cmd/av/... # pass ``` Part of #656 This contribution was developed with AI assistance (Codex).
1 parent 0bf7c8f commit 5f335ce

1 file changed

Lines changed: 14 additions & 8 deletions

File tree

internal/git/gitui/prune.go

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -227,17 +227,23 @@ func (vm *PruneBranchModel) runDelete() tea.Msg {
227227
for i := len(vm.deleteCandidates) - 1; i >= 0; i-- {
228228
branch := vm.deleteCandidates[i]
229229
if err := vm.repo.BranchDelete(context.Background(), branch.branch.Short()); err != nil {
230-
// Check if the error is due to the branch being checked out in a worktree
231-
if exiterr, ok := errutils.As[*exec.ExitError](err); ok &&
232-
strings.Contains(string(exiterr.Stderr), "used by worktree") {
233-
// Collect worktree branches but continue deleting others
230+
var stderr string
231+
if exiterr, ok := errutils.As[*exec.ExitError](err); ok {
232+
stderr = strings.TrimSpace(string(exiterr.Stderr))
233+
}
234+
// Branches checked out in a worktree fail here; collect them and keep going.
235+
if strings.Contains(stderr, "used by worktree") {
234236
worktreeBranches = append(worktreeBranches, branch.branch.Short())
235237
continue
236-
} else {
237-
// Other errors are fatal
238-
deletionErr = errors.Errorf("cannot delete merged branch %q: %v", branch.branch.Short(), err)
239-
break
240238
}
239+
// Other errors are fatal. Surface the git stderr so users see the
240+
// actual cause rather than just "exit status 1".
241+
errMsg := err.Error()
242+
if stderr != "" {
243+
errMsg = stderr
244+
}
245+
deletionErr = errors.Errorf("cannot delete merged branch %q: %s", branch.branch.Short(), errMsg)
246+
break
241247
}
242248
tx := vm.db.WriteTx()
243249
tx.DeleteBranch(branch.branch.Short())

0 commit comments

Comments
 (0)