Skip to content

Worktree cleanup on finish and delete #175

Description

@alexrinass

Closes the worktree lifecycle: finish and delete free a branch's worktree as part of their operation — removing the ones git-flow created, detaching the ones it did not — with guards against data loss and safe navigation when the user is inside a worktree being removed. Part of #171. Refs #45.

Goal

When a branch goes away, clean up the worktree git-flow created for it, leave a worktree the user created themselves in place, and move the user somewhere valid if they were working inside a directory that is being removed.

Expected Behavior

finish and delete gain:

Flag Short Description
--keep-worktree Keep the worktree; detach it from the branch instead of removing it
--force-worktree -W Remove a git-flow-created worktree even with uncommitted or untracked changes

Because a branch checked out in a linked worktree cannot be deleted while it is checked out, worktree handling and branch deletion are coupled: the worktree has to be freed before the branch can go. What freeing it means depends on provenance (#172):

  • git-flow created the worktree — it is removed, and its marker cleared.
  • the user created it — it is kept, and its HEAD is detached off the branch. The directory and every file in it stay exactly as they were, including uncommitted work, because detaching at the same commit does not touch the working tree. The command reports what it did.

--keep-worktree applies the detach path to a git-flow-created worktree as well: the directory is kept, detached, and the branch is still deleted.

Both commands pre-flight the worktree before any destructive step, so a refused cleanup can never follow a completed merge. If a git-flow-created worktree has uncommitted or untracked changes and --force-worktree is not given, the command aborts early and leaves both the worktree and the branch intact, with guidance. Detaching never needs a force, since it changes no files — but if the worktree has an operation in progress (merge, rebase, bisect) it cannot be detached, and the command aborts the same way.

finish: once the pre-flight passes, perform the merge/rebase, then free the worktree and delete the branch. delete: the same, without the merge.

If the user is currently inside a worktree that is being removed, the parent branch's worktree — or the main worktree when the parent has none — is written to the navigation channel from #172 before the removal. The detach path never moves the user, because the directory stays where it is.

Branches with no worktree behave exactly as today, and so does a branch checked out in the main worktree; the flags are no-ops in both cases.

Test Scenarios

  1. feature finish x where feature/x has a clean git-flow-created worktree — merges per config, removes the worktree, clears its marker, deletes the branch.
  2. feature finish x where the worktree was created by hand with git worktree add — merges, detaches the worktree's HEAD, deletes the branch; the directory and its files are untouched and git worktree list still shows the path, now detached.
  3. feature finish x --keep-worktree on a git-flow-created worktree — merges, detaches, deletes the branch, and keeps the directory.
  4. feature finish x where a git-flow-created worktree has uncommitted changes and no -W — aborts before merging; worktree and branch left intact, with guidance. With -W, the merge proceeds and the worktree is removed.
  5. feature finish x where a hand-made worktree has uncommitted changes — no force needed; merges and detaches, and the uncommitted changes are still there afterwards.
  6. feature finish x where the worktree has a merge or rebase in progress — aborts before merging, with guidance; nothing is removed or detached.
  7. finish run from inside a git-flow-created worktree — records the parent branch's worktree as the destination, falling back to the main worktree.
  8. finish run from inside a hand-made worktree — nothing is recorded; the directory stays and the shell stays with it.
  9. delete x with a clean git-flow-created worktree — removes worktree and branch.
  10. delete x where the worktree was created by hand — deletes the branch and detaches the worktree.
  11. delete x --keep-worktree — deletes the branch and keeps the directory on a detached HEAD.
  12. delete x with untracked files in a git-flow-created worktree and no -W — refuses; with -W it removes.
  13. delete x run from inside its git-flow-created worktree — records the main worktree as the destination, then removes.
  14. delete x -D -W on an unmerged branch with a dirty git-flow-created worktree — force-deletes both branch and worktree.
  15. finish/delete on a branch with no worktree — behavior unchanged; the new flags are no-ops.
  16. finish/delete on a branch checked out in the main worktree — behavior unchanged; no worktree handling applies.

Out of Scope

Worktree hooks (pre-worktree-remove is added in #177) and list integration.

Technical Notes

Uses the removal, detach, provenance, and navigation operations from #172. Provenance comes only from the marker written at creation time by start (#173), checkout (#174), and worktree add (#172) — never from matching the worktree path against the template, since --worktree-path and later template changes both break that correspondence. The parent worktree is resolved from the branch's parent config, falling back to the main worktree. Dirty detection uses git status --porcelain against the worktree. The main worktree is never removed or detached. The pre-flight has to cover the --continue path too: after a conflicted merge is resolved, finish still reaches branch deletion, and it must not arrive there with an unfreeable worktree.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

specAccepted, implementation-ready specification

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions