Skip to content

feat(log-tui): D on the worktrees view removes worktree + branch (#838)#843

Merged
gfargo merged 1 commit intomainfrom
feat/worktree-delete-with-branch-838
May 4, 2026
Merged

feat(log-tui): D on the worktrees view removes worktree + branch (#838)#843
gfargo merged 1 commit intomainfrom
feat/worktree-delete-with-branch-838

Conversation

@gfargo
Copy link
Copy Markdown
Owner

@gfargo gfargo commented May 4, 2026

Closes #838.

Summary

Two delete actions in the worktrees view, with W keeping its existing semantics so muscle memory carries:

Key Behavior
W (existing) Remove worktree only. Leaves the branch in place for the user to re-attach later or delete separately from the branches view.
D (new) Remove worktree and delete the branch it was tracking. Chains git worktree removegit branch -d.

Both pre-flight guards inherit from the underlying helpers:

  • removeWorktree refuses the current worktree and dirty worktrees.
  • deleteBranch refuses the current branch and uses safe -d (so unmerged branches don't silently lose work).

Why per-view scoping for D

The global workflow-by-key dispatcher already routes D to delete-branch from anywhere in the TUI. Without per-view interception, pressing D on a worktree would silently target whatever was last cursored on the branches view rather than acting on the worktree under the cursor. The inkInput per-view scope (isWorktreeActionTarget(state) && context.worktreeListCount) catches D on the worktrees surface and routes it to the new remove-worktree-and-branch workflow before the global fallback sees it. From any other surface, D keeps doing what it always did.

Failure modes

  • Worktree pre-flight fails (current / dirty): the chained action aborts before touching the branch. User sees the worktree-level error message.
  • Branch delete fails (current branch / unmerged commits): the worktree was already removed; the user sees Removed worktree X, but branch delete failed: <git error>. Manual recovery: re-create the worktree if needed, then handle the branch separately.
  • Detached HEAD (worktree had no branch): worktree removal succeeds, branch step is silently skipped with a (no branch to delete) success message.
  • Branch missing from local refs (rare race): same skip-with-message path.

Test plan

  • npm run lint
  • npm run test:jest (1154 tests pass — added 5 new helper tests covering the happy path + partial-failure + 3 skip-the-branch-step paths, plus 4 input dispatch tests covering the per-view interception)
  • npm run build
  • npm run test:cli
  • Manual: git worktree add ../foo feat/foo, coco ui, g w, cursor the new worktree, press D, confirm y, verify both the worktree directory and the feat/foo branch are gone

Follow-up (not in this PR)

The cross-surface case from the original issue (pressing D on a branch in the branches view that has an attached worktree fails) isn't fully closed. With the worktrees view as the canonical place to do worktree-lifecycle ops, the branches view's D could grow a clearer error pointing the user at "press g w then D". Left for a separate small PR if the new flow doesn't make the cross-surface confusion fade naturally.

🤖 Generated with Claude Code

Two delete actions in the worktrees view, with W keeping its
existing semantics so muscle memory carries:

- W (existing): remove worktree only. Leaves the branch in place
  for the user to re-attach later or delete separately.
- D (new): remove worktree AND delete the branch it was tracking.
  Chains git worktree remove → git branch -d, with both
  pre-flight guards inherited from the underlying helpers
  (refuses current/dirty worktrees; uses safe -d so unmerged
  branches don't lose work).

Per-view scoping in inkInput intercepts D on the worktrees surface
before the global workflow-by-key dispatcher would otherwise route
it to delete-branch (which would target whatever was last cursored
on the branches view rather than acting on the worktree under the
cursor here). D from elsewhere keeps doing what it always did.

The chained helper handles partial failures with named-step
messages so the user knows exactly which step broke if anything
does. Detached worktrees and worktrees whose tracked branch isn't
in the local ref list both skip the branch step cleanly with a
"removed worktree (no branch to delete)" success.

Closes #838.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@gfargo gfargo merged commit 7d6b27f into main May 4, 2026
9 checks passed
@gfargo gfargo deleted the feat/worktree-delete-with-branch-838 branch May 4, 2026 03:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TUI: deleting a branch with an attached worktree fails with no recovery path

1 participant