Clean Up Stale AI Agent Git Worktrees Safely
Prepared and checked using AI. Sources are linked in the article.
To clean up stale AI agent Git worktrees without losing work, identify each worktree and its branch, inspect both uncommitted files and commits, then remove only the worktree you have finished reviewing. Delete its branch as a separate decision. Git’s worktree commands distinguish a linked worktree from the main worktree; git worktree remove removes the linked worktree, while git worktree prune cleans up records for paths that are already missing.
Inventory the worktrees first
Run these commands from the main worktree:
git worktree list --verbose
git worktree list --porcelain
git branch -vv
The first command gives you a readable list of paths, checked-out branches, and annotations such as locked or prunable. The porcelain form separates each worktree’s path, HEAD commit, branch or detached state, and annotations into labeled fields. Git’s branch listing shows the upstream branch and linked worktree path with -vv. Record the path, branch, and commit for each candidate before removing anything.
For the examples below, suppose the main worktree is on main, an agent used ../agent-api, and its branch is agent/api. Replace those names with the values from your inventory. A worktree is a cleanup candidate because its task is finished or abandoned, not merely because its directory name looks old. If an agent or editor may still be working there, settle that first.
If you are new to the relationship between a branch and a linked directory, the worktree overview provides the setup behind this cleanup procedure.
Check three places where work can survive
Start with the candidate’s working files. Git’s -C option runs a command as though it started in the named directory, so you can inspect the agent worktree without switching directories:
git -C ../agent-api status --short --untracked-files=all
git -C ../agent-api diff
git -C ../agent-api diff --cached
Status with --untracked-files=all lists individual untracked files as well as tracked changes. The two diff forms cover unstaged changes and changes staged for the next commit, respectively. Read the diffs; a clean-looking branch comparison cannot tell you whether an interrupted agent left an untracked source file in its directory.
Next, inspect commits on the agent branch that are not reachable from your integration branch:
git log --oneline main..agent/api
git diff --stat main...agent/api
The main..agent/api log range selects commits reachable from agent/api but not main. The three-dot diff summarizes changes from the branches’ common ancestor to the agent branch. Use the log to spot commits that still need a decision, and open the full diff when the summary is insufficient. A committed change remains on its branch after worktree removal, provided you keep that branch.
Finally, inspect files that Git ignores. They do not appear in ordinary status output, yet an agent may have placed useful local notes, generated data, or other files there. This dry run previews untracked and ignored paths without deleting them:
git -C ../agent-api clean -ndx
The -n dry run and -x option explain why this is an inspection command: -x includes ignored files in the preview, while -n makes no removal. Treat the listed paths as a review queue. Do not turn this into a deletion command merely to make worktree removal succeed.
Preserve work from an interrupted agent
If the worktree has edits worth keeping, leave it in place while you review them or save them before removal. A stash created with -u records tracked modifications and untracked files, then clears those changes from the worktree:
git -C ../agent-api stash push -u -m "agent/api before cleanup"
git stash list
The message makes the saved state easier to identify later. Check that the stash appears in the list before proceeding, and inspect any ignored paths separately: -u includes untracked files, whereas --all also includes ignored files. Avoid using --all casually if ignored directories contain large or sensitive local data. A stash is useful for temporary preservation; keep a clearly named branch for commits that may need review or merging.
If the worktree has a detached HEAD, its commits have no branch name in the worktree listing. Before removal, copy its HEAD commit ID from git worktree list --porcelain and give that commit a branch name if you may need it:
git branch rescue/agent-api <commit-id>
Use the actual commit ID in place of <commit-id>. This creates a named reference to that commit; it does not save uncommitted files. Save those separately first. For a branch that already exists, keeping the branch is enough to retain its committed history while you decide what to do with it.
When the branch contains work you want in main, review and integrate it before branch deletion.
Remove a reviewed worktree
Once the path contains nothing you still need locally, remove that specific linked worktree from the main worktree:
git worktree remove ../agent-api
git worktree list
By default, git worktree remove accepts only clean linked worktrees: it refuses tracked modifications and untracked files. It also refuses to remove the main worktree. If the command stops, return to the status, diff, and ignored-file checks; the refusal is information worth investigating. git worktree remove --force can remove an unclean worktree, so reserve it for a path whose contents you have deliberately decided to discard. The worktree command also requires force for a worktree containing submodules.
Removing the directory and removing the branch solve different problems. Keep the branch if its commits are still under review, are needed for a pull request, or have not been integrated. A missing worktree directory does not mean its branch is unwanted.
Delete branches only after checking their commits
After worktree removal, check which branch tips are reachable from main:
git branch --merged main
git log --oneline main..agent/api
git branch --merged main lists branches whose tip commits are reachable from main. If agent/api appears there and the branch is no longer needed, delete it:
git branch -d agent/api
-d requires the branch to be fully merged into its configured upstream, or into the current HEAD when it has no upstream. That is why the explicit comparison with main matters: an upstream can be different from the integration branch you care about. Deleting a branch also deletes its branch reflog. Do not use git branch -D as a shortcut through an unexplained -d refusal; -D permits deletion regardless of merged status.
A squash merge or cherry-pick can leave an agent branch’s commits absent from main even if you have incorporated their changes. In that situation, reachability alone cannot settle the decision. Compare the changes that landed with the agent’s branch, then either retain the branch or consciously delete it after confirming that its work is accounted for.
Handle missing, moved, and locked paths separately
If git worktree list marks a path prunable, first establish whether the directory was intentionally deleted or moved. A dry run shows which missing-worktree records pruning would remove:
git worktree prune --dry-run
If the path really is gone and you no longer need its worktree record, run git worktree prune. Pruning removes administrative information for missing worktrees; it does not inspect a surviving directory for uncommitted work, and it is not branch cleanup.
If someone moved the directory, use git worktree repair <new-path> to reconnect it before treating the old location as stale. If the worktree is on an intermittently mounted drive, a locked annotation may be intentional: locking prevents pruning and removal while that drive is absent. Investigate the lock reason with git worktree list --verbose; unlock only after you know the path should be removable.
For repeated cleanup, use the same order each time: inventory paths and branches, inspect local files and ignored paths, review branch-only commits, preserve anything uncertain, remove the linked worktree, and then decide whether to delete the branch. This order makes each irreversible choice depend on a specific piece of reviewed work.
Where Parallel Code fits
Parallel Code is our free, open-source desktop app for macOS and Linux. It runs several AI coding agents in parallel, each in its own git worktree, and provides a diff-first review surface. That makes it relevant when reviewing agent changes before deciding which worktrees and branches to keep.
Frequently asked questions
Does git worktree remove delete the agent’s branch?
No. Remove the linked worktree first, then decide whether its branch should remain. Use git branch -d <branch> only after checking that the branch’s commits are accounted for.
Is a clean git status enough to remove a worktree?
It checks tracked changes and untracked files, but ordinary status output does not show ignored files. Preview ignored paths with git clean -ndx, and inspect branch-only commits as well: those commits are outside the working-file status report.
What if the agent worktree directory is already gone?
Use git worktree prune --dry-run to inspect the record Git would discard. If the directory was moved, repair the link instead; if it was intentionally deleted, prune the stale record and review the branch separately.
Should I use --force when removal fails?
Only after identifying the contents you intend to discard. A refusal may point to tracked edits, untracked files, a lock, or submodules, and force can bypass safeguards that would otherwise stop removal.