A Git worktree's directory was deleted with rm -rf — what stale state remains and how do you clean it up?
answer
- Half the pair survives the delete
- Look under .git/worktrees
- The branch is still considered occupied
- Error names a path that no longer exists
- prune, or remove it properly next time
basics
~20 sThe repository still holds that worktree's administrative directory under .git/worktrees, so it appears in git worktree list as prunable and still occupies its branch. Run git worktree prune to drop the bookkeeping, or remove worktrees with git worktree remove.
solid answer
~50 sDeleting the checkout only removes files; the repository's `.git/worktrees/<name>/` directory — holding that worktree's HEAD, index and reflog — survives. Practically that means `git worktree list` still lists the path (annotated as prunable), and the branch it had checked out is still considered occupied, so `git worktree add` or `git switch` for that branch fails naming a directory that no longer exists. `git worktree prune` removes bookkeeping for every worktree whose directory is gone, and `git worktree prune --dry-run` shows what it would remove first. The clean habit is `git worktree remove <path>`, which deletes the checkout and its administration together. If a worktree lives on removable media or a network share, `git worktree lock` marks it so a prune does not discard it while it is merely unmounted, and `git worktree repair` fixes the pointers after a directory or the repository itself was moved by hand.
code
console · 9 lines$ rm -rf ../review
$ git worktree list
/home/dev/project 4a1c9e2 [main]
/home/dev/review 9b2f7c1 [feature-x] prunable
$ git worktree prune --dry-run
Removing worktrees/review: gitdir file points to non-existent location
$ git worktree prunego deeper
Recall that deleting the folder is not enough: run git worktree prune to clear what Git still records, and prefer git worktree remove next time.
Explain why — the administrative directory under .git/worktrees survives, so the entry still lists as prunable and the branch stays occupied — and know that garbage collection eventually prunes it on its own.
Diagnose from the symptom: an error naming a path that no longer exists. Show the dry-run check before pruning, the lock case for removable media, and repair after a manual move, plus what state was and was not recoverable.
Own the conventions that stop this recurring: a standard location and naming scheme for worktrees, teardown through git worktree remove in scripts and tooling, and locking for any worktree on storage that can legitimately disappear.
## What a worktree consists of A linked worktree is two things: the checkout directory, whose root contains a `.git` file with a `gitdir:` line, and an administrative directory `.git/worktrees/<name>/` inside the original repository holding this checkout's `HEAD`, index, reflog and a `gitdir` file pointing back at the checkout's location. Deleting the directory with `rm -rf` destroys half of that pair. The repository has no way to notice until something asks. ## The symptoms - `git worktree list` still shows the vanished path. Modern Git annotates such entries as **prunable**, with the reason being that the recorded location no longer exists. - The branch that worktree had checked out is still treated as occupied. `git worktree add ../new that-branch` fails with `'that-branch' is already checked out at '<deleted path>'`, and `git branch -d that-branch` refuses for the same reason. The error names a directory that is not there, which is the giveaway. - Nothing is corrupted, and no objects are at risk. Commits made in that worktree are in the shared object database and remain reachable through any branch that points at them. ## The cleanup `git worktree prune` scans the administrative directories and removes the bookkeeping for any whose recorded working directory no longer exists. `--dry-run` (`-n`) lists what would go, and `--verbose` explains why each entry qualifies. Once pruned, the branch is released and everything behaves normally again. Git also prunes on its own schedule: `git gc` removes stale worktree administration older than `gc.worktreePruneExpire` (three months by default), so a forgotten one eventually disappears. `git worktree prune --expire <time>` applies a different cutoff on demand. ## The habit that avoids all of this Use `git worktree remove <path>`. It refuses if the worktree has uncommitted changes or untracked files (`--force` overrides), then deletes both the checkout and its administration in one step. Removing a worktree does not delete the branch it had checked out — that is a separate `git branch -d`. ## The recoverable-loss case The reason `rm -rf` deserves a second thought is not the bookkeeping — that is trivially pruned — but the contents. Anything committed in that worktree is safe in the shared object database and can be found by branch, tag or, if the branch is gone, through the reflog. Anything only *staged or modified* there is gone with the directory: the index lived in the worktree's administrative directory and the file contents lived in the deleted tree. Note also that the HEAD reflog is per-worktree, so the movements of the deleted worktree's HEAD are in its administrative directory — worth reading *before* you prune if you are trying to reconstruct what it was doing. ## Locking and repairing Two neighbouring commands round out the lifecycle: - **`git worktree lock <path>`**, optionally with `--reason "<text>"`, marks a worktree as not prunable. This is for checkouts on removable drives or network mounts that are legitimately absent when unmounted — without the lock, a prune while it is offline would discard its administration and orphan it. `git worktree unlock` reverses it. - **`git worktree repair`** fixes the two-way pointers when they no longer agree — for example after moving a worktree directory with `mv` instead of `git worktree move`, or after moving the main repository so every linked worktree's `.git` file points at the old location. Run it in the repository (optionally passing worktree paths) and it rewrites the pointers to match reality. And **`git worktree move <old> <new>`** is the supported way to relocate a linked worktree in the first place, updating both sides so repair is never needed. ## What good answers include A strong answer names the surviving administrative directory, the two visible symptoms (prunable listing, branch still occupied with an error naming a missing path), the fix (`prune`, with `--dry-run` first), the better habit (`remove`), and at least one of the lifecycle edge cases — `lock` for removable media, `repair` after a manual move. Mentioning that committed work is never at risk, while staged-only work in the deleted directory is, shows you understand where each piece of state lived.
- Is any committed work lost when a worktree directory is deleted?No. Commits live in the shared object database, so they are reachable from any branch or tag that points at them, and through the reflog if the branch is gone. What is lost is uncommitted work — modified files and the staged index — because those lived in the deleted directory and its administrative area.
- When would you deliberately prevent a worktree from being pruned?When it legitimately lives somewhere that is sometimes absent — a removable drive or a network mount. `git worktree lock <path> --reason "<text>"` marks it so a prune while it is unmounted does not discard its administration and orphan the checkout. `git worktree unlock` releases it when you are done.
- You moved a linked worktree with mv instead of git worktree move. What breaks and how do you fix it?The two pointers disagree: the worktree's `.git` file still names its old administrative directory, and that directory's `gitdir` file still names the old checkout path, so Git can no longer connect them. `git worktree repair` rewrites the pointers to match where things actually are. Using `git worktree move` in the first place updates both sides and avoids the problem.
- How do you check what a prune would remove before running it?`git worktree prune --dry-run` lists the entries it would drop without touching anything, and `--verbose` explains why each one qualifies. That matters when a worktree is only temporarily unreachable — an unmounted volume looks exactly like a deleted directory to the check, which is what locking is for.
saying these in an interview costs you the question
- Assumes deleting the directory fully removes the worktree
- Thinks the stale entry means the repository is corrupt
- Believes committed work in that worktree is lost
- Runs prune blindly with an unmounted removable volume attached
- Moves a worktree with mv and expects Git to follow it