Guide

Claude Code worktrees: cleanup, location, branches and base ref

Claude Code cleans up most of its worktrees itself: when you exit a claude --worktree session it deletes a clean, unnamed worktree and its branch, and asks you about anything holding work. The leftovers come from runs with -p, from worktrees you chose to keep, and from subagent and background worktrees that still hold changes. Find them with git worktree list, delete each with git worktree remove <path> (after git worktree unlock if it is locked), then delete its branch with git branch -d.

Where Claude Code puts worktrees

claude --worktree feature-auth creates the checkout at .claude/worktrees/feature-auth/ under your repository root, on a new branch called worktree-feature-auth. Without a name, Claude generates one. Background sessions and subagents that Claude isolates use the same directory, and a pull request worktree started with claude --worktree "#1234" lands at .claude/worktrees/pr-1234. Add the directory to .gitignore so its contents do not show up as untracked files in your main checkout:

.claude/worktrees/

There are three ways to put worktrees somewhere else:

  • Create them with git. git worktree add ../shop-feature-a -b feature-a puts a worktree beside the repository on a new branch; cd into it and run claude.
  • The desktop app setting. In the Claude desktop app, Settings → Claude Code → Worktree location changes the directory, and a branch prefix setting adds a prefix to every worktree branch name.
  • A WorktreeCreate hook. The hook replaces Claude Code's git logic entirely and returns the directory it created, so it can place worktrees anywhere. Claude Code then skips .worktreeinclude, so the hook has to copy files such as .env itself, and a matching WorktreeRemove hook handles cleanup.

What Claude Code removes on its own

Each way of creating a worktree has its own cleanup rule. The worktrees documentation and the agent view documentation give these:

How the worktree was madeWhat happens to it
Interactive --worktree, unnamed, clean on exitRemoved with its branch, no prompt
Interactive --worktree, named, clean on exitYou are asked first, so you can keep it
Interactive --worktree with changes, untracked files or new commitsYou choose keep or remove; removing deletes the directory and branch with everything in them
claude -p --worktreeNever cleaned up; its lock stays until a later session's stale-lock sweep releases it
Subagent with isolation: worktreeRemoved when the subagent finishes without changes; otherwise left for the sweep
Background session (--bg or agent view)Left for the sweep, or removed when you delete the session
Created by you with git worktree addNever removed by Claude Code

The sweep runs periodically and removes subagent and background-session worktrees once they are older than the cleanupPeriodDays setting, 30 days by default, the same setting that controls how long transcripts are kept. It skips a worktree that still has changed or untracked files or unpushed commits, one with uncommitted work in a submodule, and one belonging to a --worktree session you have not sent to the background. To keep these worktrees longer, raise the number in settings.json:

{
  "cleanupPeriodDays": 90
}

Deleting a background session can delete its worktree

In agent view, pressing Ctrl+X twice on a session removes the worktree Claude created for it, uncommitted changes included. claude rm <id> from the shell is more careful: it keeps the worktree, and the session, when there are uncommitted changes. Both refuse when the worktree has commits Claude Code cannot confirm are saved elsewhere, and name the branch and the number of unpushed commits. Push or merge them and delete again. To throw them away, press Ctrl+X twice again in agent view, or run the exact claude rm command with --discard-unpushed that the refusal prints.

Commit or push anything you want from a background session before you delete it in agent view. The worktree's uncommitted changes go with it.

The desktop app archives instead

In the desktop app, hover over a session in the sidebar and click the archive icon to remove its worktree. Auto-archive after PR merge or close in Settings → Claude Code does this for you once a session's pull request is merged or closed, for local sessions that have finished running.

Clean up leftover worktrees by hand

Run these from the main checkout. They work on any worktree, whether Claude Code or you created it.

  1. List what exists. Worktrees that are locked or whose directory is gone are flagged locked or prunable, and --verbose adds the reason:
    git worktree list --verbose
  2. Remove a finished worktree. Git removes only clean worktrees; add --force to discard uncommitted changes and untracked files:
    git worktree remove .claude/worktrees/feature-auth
  3. If git refuses because the worktree is locked, make sure no session is still using it, then unlock it and remove it:
    git worktree unlock .claude/worktrees/feature-auth
    git worktree remove .claude/worktrees/feature-auth
  4. If you deleted a worktree directory with rm -rf or Finder, git still has a record of it and lists it as prunable. Preview, then clear those records:
    git worktree prune -n -v
    git worktree prune
  5. Delete the branch. git worktree remove leaves it in the repository. git branch marks branches still checked out in another worktree with +, so remove the worktree first:
    git branch -d worktree-feature-auth
    -d deletes only a branch that has been merged; -D deletes it anyway; commits that were only on that branch are then reachable only through the reflog until git garbage-collects them.

Choosing remove at Claude Code's exit prompt deletes the worktree's branch too. Agent view does not always delete it, and git worktree remove never does, so check git branch for leftover worktree-* branches after a cleanup.

A worktree is a directory, a branch is a pointer

A branch is a named line of commits. A worktree is a working directory with one branch (or a detached commit) checked out in it. A repository normally has one working directory, so moving between branches means switching the files under you. Linked worktrees let a repository have several, each with a different branch checked out at the same time, while sharing one history, one set of branches and one remote.

That is why parallel agents need worktrees and not just branches. Two agents in one directory on different branches would still be editing the same files on disk, and each git checkout one ran would change the files under the other. With a worktree each, every agent has its own files and its own branch, and its commits land in the shared repository where you can diff and merge them.

One rule follows from this: git will not check out a branch that another worktree already has checked out unless you force it. Every agent needs its own branch, and git worktree add fails if you name the branch your main checkout is on. claude --worktree avoids this by creating a new branch for each worktree.

What new worktrees branch from

By default a new Claude Code worktree branches from the repository's default branch on the remote, usually origin/main, so it starts clean and does not contain your unpushed commits. To keep that ref current, Claude Code fetches the default branch when the repository has not been fetched in the last 24 hours, giving up after five seconds and using the cached ref if the fetch fails. With no remote, or no origin/HEAD it can find, it falls back to your local HEAD.

When agents need to build on work you have not pushed, set worktree.baseRef to "head":

{
  "worktree": {
    "baseRef": "head"
  }
}

New worktrees, subagent worktrees included, then branch from your current local HEAD; inside a worktree, that means the worktree's own HEAD, not the main checkout's. The setting accepts only "fresh" (the default) and "head", not a branch name. To start from a particular branch, create the worktree with git and run claude in it:

git worktree add ../shop-bugfix fix-issue-456
cd ../shop-bugfix && claude

To start from a pull request, pass its number or URL: claude --worktree "#1234" fetches the pull request's head commit from origin. The quotes stop your shell treating # as a comment.

Reusing a name follows the base setting too. claude --worktree feature-auth on a name that already exists opens that worktree. With the "fresh" base, a worktree that is clean, still on the branch Claude Code created for it, and either has no commits of its own or had its pull request merged and remote branch deleted, is reset to the default branch; anything else reopens where it left off.

For running several of these sessions side by side, see how to run multiple Claude Code agents at once; Codex has its own worktree handling, covered in running multiple Codex CLI agents.

Worktrees in Armadai

Armadai is a native macOS app that puts each project folder in its own workspace on one infinite canvas, with Claude Code and Codex running in it. Its task hand-off uses worktrees too: you choose Run with Claude or Run with Codex on a task, and Armadai gives that run its own Git worktree and tracks it through to review, where the work comes back as a draft pull request for you to approve or send back. The Codex Agent tile can also fork a conversation into a new worktree to try another approach.

Armadai runs the Claude Code and Codex you already have, under your own accounts, so the cleanup rules above still apply to worktrees that Claude Code itself creates inside a session. It is a paid app with no free plan, at $20 a month or $120 a year after a 7-day free trial that requires a payment method.

Questions

Does git worktree remove delete the branch too?

No. git worktree remove deletes the directory and git's record of it, and the branch stays in the repository. Delete it afterwards with git branch -d, or git branch -D if it holds commits that were never merged. Claude Code's own exit prompt is different: when you choose to remove there, it deletes the worktree and its branch.

Why is my Claude Code worktree locked?

Claude Code holds a git worktree lock on a worktree while an agent or a backgrounded session is using it, and runs with -p keep the lock they took until a later session's stale-lock sweep releases it. If the session is finished, run git worktree unlock on the path, then git worktree remove. git worktree list --verbose shows the lock reason.

Can I make Claude Code keep subagent and background worktrees longer?

Yes. The periodic sweep removes those worktrees once they are older than the cleanupPeriodDays setting, which defaults to 30 and also controls how long transcripts are kept. Raise it in settings.json, for example to 90. Worktrees that still hold changes, untracked files or unpushed commits are kept regardless of age.

Can I open an existing Claude Code worktree again by name?

Yes. Passing --worktree a name whose directory already exists opens that worktree instead of creating a new one. With the default fresh base, a worktree that is clean, still on its own branch, and either has no commits of its own or had its pull request merged and remote branch deleted, is reset to the default branch; otherwise it reopens at its old tip.

Sources

Details about other products come from their own pages, checked on the dates shown. If something has changed, tell us at support@armadai.sh and we will correct it.

  • claude --worktree (or -w) with a name creates a worktree under .claude/worktrees/<name>/ at the repository root on a new branch named worktree-<name>; without a name Claude generates one. Adding .claude/worktrees/ to .gitignore is recommended. code.claude.com, checked October 5, 2026.
  • On exiting an interactive worktree session, Claude removes a clean worktree and its branch automatically for an unnamed session, prompts first for a named session, prompts to keep or remove a worktree with changed or untracked files, submodule changes or new commits, and prompts when it cannot verify the state. Removing deletes the directory and its branch. Keeping prints a claude --worktree <name> --resume command. code.claude.com, checked October 5, 2026.
  • Runs with -p have no exit prompt, so their worktrees are not cleaned up and the lock taken at creation stays until a later session's stale-lock sweep releases it; remove them with git worktree remove, running git worktree unlock first if git refuses because the worktree is locked. code.claude.com, checked October 5, 2026.
  • A subagent's worktree is removed automatically when the subagent finishes without changes. A periodic sweep removes worktrees Claude created for subagents and background sessions once they are older than cleanupPeriodDays, but keeps any that hold changed or untracked files or unpushed commits, belong to a --worktree session that has not been backgrounded, or were created with git worktree add. code.claude.com, checked October 5, 2026.
  • Claude Code holds a git worktree lock on a worktree while an agent or backgrounded session runs, and the sweep releases locks left by exited sessions but never a lock you set yourself. To clean up a worktree the sweep keeps, run git worktree remove, adding --force for uncommitted changes or untracked files. code.claude.com, checked October 5, 2026.
  • cleanupPeriodDays sets how many days Claude Code keeps transcripts and other application data; it is a whole number, minimum 1, default 30. code.claude.com, checked October 5, 2026.
  • Deleting a session in agent view (Ctrl+X twice) removes the worktree Claude created for it including uncommitted changes; claude rm keeps it when it has uncommitted changes; a worktree with commits Claude Code cannot confirm are saved elsewhere is kept until you push them or delete again, and the claude rm command with --discard-unpushed that the refusal prints discards them. code.claude.com, checked October 5, 2026.
  • In the desktop app, worktrees are stored in <project-root>/.claude/worktrees/ by default; Settings → Claude Code has a Worktree location option and a branch prefix, the archive icon on a session removes its worktree, and Auto-archive after PR merge or close archives finished local sessions. code.claude.com, checked October 5, 2026.
  • A WorktreeCreate hook replaces the default git worktree logic, including placing worktrees somewhere other than .claude/worktrees/; .worktreeinclude is not processed when a hook creates the worktree. A WorktreeRemove hook handles cleanup. code.claude.com, checked October 5, 2026.
  • worktree.baseRef accepts "fresh" (default, branch from the remote default branch) or "head" (branch from the current local HEAD, which inside a worktree is that worktree's HEAD), and cannot be set to a branch name. Subagent worktrees use the same base. code.claude.com, checked October 5, 2026.
  • For a fresh base, Claude Code fetches the default branch when the repository has not been fetched in 24 hours, capped at five seconds, uses the cached ref if that fails, and falls back to the local HEAD if there is no remote or origin/HEAD cannot be found. code.claude.com, checked October 5, 2026.
  • claude --worktree "#1234" or a GitHub pull request or GitLab merge request URL fetches that change's head from origin and creates the worktree at .claude/worktrees/pr-<number>. code.claude.com, checked October 5, 2026.
  • Passing --worktree an existing name reopens that worktree; with a fresh base it resets to the default branch when it is clean, still on its branch, and has no commits of its own or its pull request was merged and its remote branch deleted. code.claude.com, checked October 5, 2026.
  • git worktree add ../project-bugfix fix-issue-456 creates a worktree from an existing branch, and git worktree add ../project-feature-a -b feature-a creates one on a new branch. code.claude.com, checked October 5, 2026.
  • A repository can have several working trees, letting you check out more than one branch at a time. git worktree remove removes only clean worktrees unless --force is given, and a locked one needs --force twice; git worktree prune (with -n for a dry run) removes records of worktrees whose directories are missing; git worktree list --verbose shows lock reasons and prunable entries; add refuses a branch already checked out in another worktree unless forced. git-scm.com, checked October 5, 2026.
  • git branch -d deletes a branch that is fully merged and -D forces deletion; git branch marks branches checked out in linked worktrees with a plus sign. git-scm.com, checked October 5, 2026.