Lesson 0003: Edge Cases & Debugging Worktrees

Part of Git Worktrees for Parallel Agentic Coding  |  ~15 minute read + troubleshooting practice

Worktrees are simple until they're not. When you have multiple agents operating in parallel, things will go wrong: a rebase in one worktree breaks another, a branch gets force-pushed, a worktree directory gets deleted by accident. This lesson gives you the diagnostic toolkit to recognize and recover from every common failure mode.

Scenario 1: Rebase in One Worktree Breaks Another

The Situation

Worktree A has feat/dark-mode checked out. You rebase feat/dark-mode onto the latest main from the main worktree. Now Worktree A's working tree is stale โ€” it still reflects the pre-rebase commits.

# In Worktree A:
git status
# "Your branch and 'origin/feat/dark-mode' have diverged..."

# The fix: reset to the new rebased state
git reset --hard feat/dark-mode
# Or, if you're not sure what happened:
git reflog                    # see what changed
git reset --hard <correct-commit>
Prevention beats recovery. Before rebasing a branch that is checked out in another worktree, either (a) remove that worktree first, or (b) communicate to whomever is working in that worktree that a rebase is coming. In an agentic coding setup, this means: if Agent A is done, remove its worktree before rebasing its branch.

Scenario 2: Branch Force-Pushed from Another Worktree

The Situation

You amend a commit and force-push feat/dark-mode from the main worktree. Worktree A still has the old version of the branch checked out. Git reports the branch has diverged.

# In Worktree A:
git fetch origin
git status
# "Your branch is behind 'origin/feat/dark-mode' by 1 commit..."

# Option 1: Accept the remote version (discard local):
git reset --hard origin/feat/dark-mode

# Option 2: Rebase local work on top of remote:
git rebase origin/feat/dark-mode

Scenario 3: Detached HEAD in a Worktree

The Situation

You created a worktree at a specific commit instead of a branch. This is useful for reviewing a PR or testing an old release, but it means you're in detached HEAD โ€” commits made here will be lost if you switch away.

# Check if you're in detached HEAD:
git worktree list
# Shows the worktree with a commit hash instead of a branch name

# To save your work, create a branch from the current position:
git switch -c my-new-branch

# Alternatively, if you meant to be on a branch:
git worktree add --detach ../path/to/worktree abc1234  # intentional
git worktree add ../path/to/worktree existing-branch   # safer: on a branch
Detached HEAD is not inherently bad. It's the right tool for reviewing a specific commit (like a PR head) without creating a branch. Just be aware that commits made in detached HEAD are only reachable via the reflog until you attach a branch to them.

Scenario 4: Orphaned Worktree Metadata (Manual rm -rf)

The Situation

You (or a script, or an agent) deleted a worktree directory with rm -rf instead of git worktree remove. The metadata in .git/worktrees/ still exists, and git worktree list shows a "prunable" entry.

# Check what's prunable:
git worktree list
# Shows something like:
# /path/to/deleted/worktree  abc1234 [feat/dark-mode] prunable

# Clean up all prunable entries:
git worktree prune

# Or be explicit about what to prune:
git worktree prune --expire 1.minute.ago  # prune entries older than 1 minute

# Verify clean state:
git worktree list

Scenario 5: "fatal: 'xyz' is already checked out"

The Situation

You try to create a worktree for a branch that's already checked out in another worktree (or in the main worktree). Git refuses.

# Find which worktree has the branch:
git worktree list | grep branch-name

# Option 1: Remove the conflicting worktree:
git worktree remove /path/to/conflicting/worktree

# Option 2: Switch the conflicting worktree to a different branch:
cd /path/to/conflicting/worktree
git switch other-branch

# Option 3 (rarely recommended): Create the new worktree
# in detached HEAD at the same commit, then switch to the branch later:
git worktree add --detach ../path/to/new/worktree $(git rev-parse branch-name)

Scenario 6: Stale Worktree After Branch Deletion

The Situation

A worktree exists for a branch that has since been deleted. The worktree is now on a dangling branch reference โ€” it still works, but git worktree list might show a detached state or an error.

# Diagnose:
git worktree list
# Worktree at /path  abc1234 (detached HEAD)
# or shows the old branch name with a warning

# Recovery depends on what you want:
# If the commits were merged โ€” just remove the worktree:
git worktree remove /path/to/worktree

# If you need to keep the work:
cd /path/to/worktree
git switch -c resurrected-branch  # re-attach to a new branch

Scenario 7: Merge Conflict Between Worktrees

The Situation

Two agents, in two worktrees, modified the same file on different branches. When you try to merge one into main, you get a conflict. The conflict exists in the worktree where you ran the merge โ€” the other worktree is unaffected.

# The merge worktree (usually main) shows the conflict:
cd ~/dev/my-project
git merge feat/dark-mode
# CONFLICT (content): Merge conflict in src/styles.css

# Resolve the conflict normally:
# Edit src/styles.css, remove conflict markers
git add src/styles.css
git commit -m "merge: resolve dark mode style conflict"

# The other worktree (feat/dark-mode) is unaware of the conflict.
# It still has the pre-merge version of the file.
# This is correct behavior โ€” each worktree is independent.
Conflicts are localized to the worktree where the merge happens. This is actually a feature โ€” Agent 2 can keep working in its worktree while you resolve the conflict from Agent 1's merge in the main worktree. The isolation works in your favor.

Debugging Toolkit: Commands That Save You

When something feels wrong, these commands will diagnose the issue 90% of the time:

Command What it tells you
git worktree list All worktrees, their branches, and whether any are prunable or detached
git worktree list --porcelain Same info in parseable format โ€” useful in scripts that check worktree health
cat .git (in the linked worktree) Confirms the pointer file is intact and pointing to the right metadata
ls .git/worktrees/ (in the main worktree) Shows all registered worktree metadata โ€” cross-reference with worktree list
git branch --list See if the branch still exists (Scenario 6)
git reflog (in the suspect worktree) Trace what happened to HEAD in that specific worktree
git status (in the suspect worktree) Check for divergence, detached HEAD, or dirty state

Preventive Hygiene

Make these habits and most edge cases never arise:

  1. Always remove with git worktree remove, never rm -rf. This single habit prevents Scenario 4.
  2. Run git worktree list before rebasing or force-pushing. If the branch is checked out elsewhere, either remove that worktree or coordinate.
  3. Prune periodically. A monthly git worktree prune in your main repos catches orphaned metadata before it accumulates.
  4. Name worktree directories clearly. When you see ~/dev/worktrees/fix-login-timeout in git worktree list, you know exactly what it is. When you see ~/dev/worktrees/temp3, you have to investigate.
  5. Clean up after each coding session. When an agent's work is merged, remove its worktree. Don't let stale worktrees accumulate.

Recap

Primary source: git-worktree โ€” BUGS section and the DETAILS section which covers the internal mechanics that explain most edge cases.

Ask questions: "What happens if I delete the .git/worktrees/ metadata directory manually?" or "Can I recover a worktree after the branch was force-pushed and I have uncommitted changes?" โ€” bring your weird scenarios to your agent-teacher.