You merged a feature PR, deleted the branch, and now the linked worktree at ../project-feature is broken. git worktree list shows it as [detached HEAD] or annotated prunable, and cd ../project-feature && git status prints fatal: not a git repository. Or the reverse: you can’t recreate it because Git reports fatal: 'feature/login' is already checked out at '../project-feature'. The cause is the same in every case — a worktree keeps its own metadata in .git/worktrees/<name>/, and Git never cleans that up automatically when a branch is deleted or a directory is removed by hand.
Fastest fix: if the directory is gone but the registration lingers, run git worktree prune from the main repo and you’re done. If the directory still exists but the worktree won’t open (you moved it, or moved the main repo), run git worktree repair instead — that re-links it without deleting anything. The rest of this page is for the cases where you have uncommitted work to rescue first, or a lock to clear.
Which bucket are you in?
Run this from the main repo and match the output to the right fix:
git worktree list --porcelain
| What you see | Cause | Jump to |
|---|---|---|
A worktree line followed by prunable gitdir file points to non-existent location | Directory was deleted manually (cause 1) | git worktree prune — Step 2 |
Line shows detached and the old branch is gone | Branch deleted while checked out (cause 2/3) | rescue + re-branch — Step 5 |
cd into the worktree gives fatal: not a git repository but files are present | .git link file broken, or main repo moved (cause 4) | git worktree repair — Step 4 |
locked annotation | Worktree was locked deliberately or sits on an unmounted device | unlock — Step 3b |
Directory is empty / only has .git | Disk filled mid-add (cause 5) | prune + re-add — Step 2, then 6 |
prunable is the exact word Git uses for “this worktree’s directory is missing, so I’m willing to delete its registration.” That is the most common bucket after a branch cleanup.
Common causes
Ordered by hit rate, highest first.
1. Worktree directory was deleted without git worktree remove
Someone ran rm -rf ../project-feature, or a disk-cleanup script removed it. The .git/worktrees/project-feature/ metadata still lives in the main repo, so Git keeps reporting a worktree that no longer has a working tree.
How to spot it: git worktree list --porcelain prints prunable gitdir file points to non-existent location under that entry, and ls -la ../project-feature returns “No such file or directory.”
2. Branch was deleted while the worktree was checked out
git branch -d feature/login (or git fetch --prune removed a deleted remote branch’s tracking ref). The worktree is still on disk, but the branch it pointed at is gone, so HEAD detaches.
How to spot it: inside the worktree, git status shows HEAD detached at abc1234. From the main repo, git worktree list shows [detached HEAD] for that path.
Note: Git actively protects you here. If you try git branch -d feature/login while it is still checked out in a worktree, Git refuses with error: Cannot delete branch 'feature/login' checked out at '<path>'. The detached case happens when the branch was deleted from a different clone, or the remote branch was pruned.
3. Worktree was created on a remote-tracking branch
git worktree add ../project-feature origin/feature/login creates a detached-HEAD worktree from the start. When origin/feature/login is deleted upstream, git fetch --prune removes it locally, and the worktree is now stranded at a SHA with no branch.
How to spot it: git -C ../project-feature branch -vv shows the upstream as [gone], or cat .git/worktrees/<name>/HEAD contains a raw SHA rather than ref: refs/heads/....
4. The worktree’s .git link file is broken or the main repo moved
Each linked worktree has a .git file (not a directory) holding one line: gitdir: /path/to/main/.git/worktrees/<name>. If you moved the worktree by hand, moved or renamed the main repo, or that file got overwritten, the worktree can no longer find its parent — and the parent can’t find it.
How to spot it: cat ../project-feature/.git shows a gitdir: path that no longer exists, or cd ../project-feature && git status prints fatal: not a git repository even though your source files are right there. This is the one case you fix with git worktree repair, not prune — see Step 4.
5. Disk filled during git worktree add
add got far enough to write metadata in .git/worktrees/ but the checkout never finished because the disk filled. You’re left with an empty directory and a half-registered worktree.
How to spot it: ls -A ../project-feature/ shows nothing or only .git, and df -h . shows the volume was near full.
Shortest path to fix
Step 1: Inventory the worktrees
git worktree list --porcelain
The porcelain form prints the prunable annotation and the exact gitdir reason for each broken entry. Anything marked prunable is safe to remove; anything you reach with repair should be kept.
Step 2: Prune registrations whose directory is gone
git worktree prune --dry-run --verbose # preview: "Removing worktrees/project-feature: gitdir file points to non-existing location ..."
git worktree prune --verbose # actually remove them
Plain git worktree prune removes every stale entry immediately, regardless of age. (The 3-month grace period you may have read about only applies when git gc runs prune via gc.worktreePruneExpire, default 3.months.ago — it is not applied to a manual prune.) After this, git worktree list should no longer show the missing path.
Step 3: Remove or unlock a worktree that won’t go quietly
# Directory still exists but you want it gone (refuses if there are uncommitted changes):
git worktree remove ../project-feature
# Override an "is dirty, use --force to delete it" refusal (discards uncommitted changes):
git worktree remove --force ../project-feature
Step 3b — locked worktrees. If list shows locked or remove reports the worktree is locked, clear the lock first. A single --force does not override a lock; you need two, or an explicit unlock:
git worktree unlock ../project-feature
git worktree remove ../project-feature
# or, in one shot — the SECOND --force is what overrides the lock:
git worktree remove --force --force ../project-feature
Step 4: Repair a worktree that moved or lost its link (don’t prune this one)
If the files are still there but Git can’t open the worktree — you moved the directory, moved the main repo, or the .git link file got clobbered — git worktree repair rewrites the metadata to point at the real locations. Available since Git 2.36 (April 2022).
# Run from inside the worktree that was moved:
cd ../moved-feature
git worktree repair
# Or fix one or more linked worktrees by path, from the main repo:
git worktree repair ../moved-feature ../another-worktree
repair is non-destructive: it never deletes your checkout, it only relinks gitdir pointers in both directions. Reach for this instead of prune whenever the working files still exist.
Step 5: Re-attach a detached worktree after its branch was deleted
When the worktree is fine but its branch vanished (causes 2 and 3), give the current commit a home before you lose the SHA:
cd ../project-feature
git switch -c feature/login-revived # new branch at the current commit
# or attach to an existing branch instead:
git switch main
Back in the main repo, confirm it’s no longer detached:
git worktree list # the path should now show a branch name, not [detached HEAD]
Step 6: Re-add cleanly on a fresh path
# After prune/remove cleared the stale registration:
git worktree add ../project-feature feature/login-v2
If add fails with fatal: '../project-feature' is not an empty directory, the old directory is still there — move any real files out, delete it, then re-add.
How to confirm it’s fixed
git worktree list --porcelain
You’re done when every entry has an existing path, no line says prunable, and the worktree you care about shows a branch (branch refs/heads/...) rather than bare detached. As a final sanity check, cd into the worktree and run git status — it should report a clean tree on a named branch, not fatal: not a git repository.
Prevention
- Remove worktrees with
git worktree remove <path>before you delete the directory or the branch. The correct cleanup order after a merge is:git worktree remove, thengit branch -d, thengit push origin --delete. - Never
rm -rfa worktree directory. If you already did,git worktree pruneis the cleanup. - Don’t create worktrees directly on a remote-tracking branch (cause 3). Make a local branch first:
git switch -c feature/login origin/feature/login, thengit worktree add. - Set
git config worktree.guessRemote truesogit worktree addauto-creates a local tracking branch when a matching remote exists, avoiding stranded detached HEADs. - If you move a repo or a worktree, use
git worktree move(or rungit worktree repairafterward) rather than dragging directories in a file manager. - Keep worktrees discoverable: park them in one place (for example
~/worktrees/<repo>/<branch>) and name the directory after the branch. - Audit periodically:
git worktree listat the start of each sprint, plus a scheduled or post-mergegit worktree prune.
FAQ
Q: What’s the difference between git worktree prune and git worktree remove?
A: prune is a bulk cleanup of registrations only — it deletes metadata for worktrees whose directories no longer exist, and never touches files on disk. remove is targeted: it deletes one worktree’s working directory and its metadata, and refuses if there are uncommitted changes unless you pass --force.
Q: When do I use repair instead of prune?
A: Use repair when the working files still exist but Git can’t open the worktree — you moved the directory, moved the main repo, or the .git link file broke. Use prune only when the directory is genuinely gone. Pruning a worktree whose files you still need would orphan it.
Q: The branch was deleted but the worktree has uncommitted changes. Can I save them?
A: Yes. Don’t prune or force-remove yet. From the worktree, run git -C ../project-feature stash (the stash lands in the main repo’s stash list, recoverable with git stash apply), or git -C ../project-feature switch -c rescue/from-worktree to pin the commit and changes to a new branch. Then clean up.
Q: git worktree add says fatal: 'feature/login' is already checked out at '<path>'. Why?
A: Git enforces one checkout per branch across all worktrees to prevent divergent working trees. Either cd to the existing worktree and use it, or — if that worktree is stale — git worktree remove --force <path> (or git worktree prune if its directory is gone), then add again.
Q: How many worktrees can I have? A: There’s no hard limit. Each worktree carries its own index, HEAD, and full checkout, so it costs roughly the same disk as your working tree. Since a given branch can only be checked out once, the practical ceiling is your branch count; 3-5 active worktrees is comfortable for most repos.