Claude Code Worktrees: Run Parallel Sessions Without Collisions
Two Claude Code sessions in the same checkout edit the same files, and sooner or later one overwrites the other's work or runs the tests in the middle of the other's change. A git worktree fixes that: a separate working directory with its own files and branch that shares the repository's history and remote with your main checkout. Claude Code builds this in: claude --worktree <name> creates a worktree and starts the session inside it.
This guide follows Anthropic's worktrees documentation. It covers starting sessions in worktrees, setting up each one (including copying .env with .worktreeinclude), what happens on exit, resuming, how Claude Code enforces isolation and where that stops, worktrees for subagents, choosing the base branch, manual git worktree use, and the errors you may hit. It replaces two older posts on this site that covered the same topic.
For the desktop app's worktree option, see Claude Code Desktop App. For sparse worktrees in a monorepo, see Claude Code in Monorepos.
Start sessions in worktrees
Pass --worktree (or -w) with a name:
1# terminal 12claude --worktree feature-auth3 4# terminal 25claude --worktree fix-loginEach command creates .claude/worktrees/<name>/ at the repository root, on a new branch named worktree-<name>, and starts Claude there. Omit the name and Claude generates one, such as bright-running-fox. Passing a name whose directory already exists reopens that worktree instead of creating a new one.
You can also ask Claude mid-session to "work in a worktree", and it creates one with the EnterWorktree tool. Entering a path outside .claude/worktrees/ always asks for your approval first, because it moves the session's working directory, write access, and project configuration there.
Two setup steps matter. Add .claude/worktrees/ to .gitignore so worktree contents never show as untracked files in the main checkout. And remember that interactive --worktree runs need workspace trust: run plain claude once in a new directory to accept the trust dialog, or --worktree exits with an error. claude -p --worktree skips the trust check.
Quick reference
claude --worktree "#1234"(quoted, so the shell does not treat#as a comment) fetches pull request or merge request 1234 fromoriginand creates.claude/worktrees/pr-1234.- Worktrees require git. For SVN, Perforce, or Mercurial,
WorktreeCreateandWorktreeRemovehooks replace the git logic. - Worktrees isolate file edits only. Subagents split work inside one session; cross-session messaging lets worktree sessions share findings.
Remember this
One claude -w <name> per task gives each session its own directory and branch; ignore .claude/worktrees/ in git.
Set up each worktree: dependencies and .worktreeinclude
A worktree is a fresh checkout of tracked files. It has no node_modules, no virtual environment, no build output, and none of your gitignored local files. Ask Claude to install dependencies first, or run your setup command in the worktree.
For gitignored files you need everywhere, such as .env, add a .worktreeinclude file at the project root. It uses .gitignore syntax, and only files that match a pattern and are gitignored are copied into each new worktree, so tracked files are never duplicated:
1.env2.env.local3config/secrets.jsonIt applies to every worktree Claude Code creates with git: --worktree sessions, subagent worktrees, and desktop-app parallel sessions. With a WorktreeCreate hook, it is not processed; copy the files in your hook script.
Two practical consequences of separate checkouts: each worktree needs its own dependency install (time and disk), and if two worktrees start dev servers they need different ports. Tell Claude which port to use in each session, or configure your dev server to pick a free one.
Quick reference
- Copying
.envinto every worktree also copies its secrets. Consider aRead(./.env)deny rule if Claude should never see them. - Patterns starting with
**/reach into a wholly ignored directory only in specific cases; name the directory in the pattern, such asvendor/**/config.json, to be sure. - Plugins installed at project scope in the main checkout also load in its worktrees, so you do not reinstall them.
Remember this
Install dependencies per worktree, copy gitignored local files with .worktreeinclude, and give each dev server its own port.
Exit, clean up, and resume
When you exit an interactive worktree session, Claude checks the worktree for work removal would delete: changed or untracked files, uncommitted work in submodules, and new commits.
- Clean: for an unnamed session, Claude removes the worktree and its branch automatically. A named session asks first, so you can keep it.
- Has work: Claude asks whether to keep or remove it. Keeping preserves the directory and branch, and Claude prints the
claude --worktree <name> --resumecommand to return. Removing deletes the directory, the branch, and everything in them. - Cannot verify: Claude asks rather than deleting anything, and names what it could not check.
Non-interactive claude -p runs have no exit prompt, so their worktrees are never cleaned up automatically. Remove them with git worktree remove, after git worktree unlock if git says the worktree is locked.
Resuming a session that ended inside a worktree returns it to that worktree, for interactive resumes, --continue and --resume with -p, and the Agent SDK. If the worktree was deleted, the session resumes in your launch directory and tells you. Resume from the main checkout when in doubt; some worktrees are only re-entered from there.
Quick reference
- Merging is still your job. Push the worktree branch, open a pull request, and review it like any other.
git worktree listshows every worktree;git worktree remove ../path --forceremoves one with uncommitted changes.- Reusing a name reopens the old worktree, and with the default base it resets to the default branch only if it is clean and unchanged or its PR was merged.
Remember this
Interactive exits clean up or ask; -p runs leave worktrees behind for git worktree remove.
What isolation Claude Code enforces, and where it stops
While a session is isolated in a worktree, Claude Code applies four checks, including to every subagent the session spawns:
1. File edits: Edit, Write, and NotebookEdit calls that target the main checkout are blocked.
2. Command working directory: a Bash, PowerShell, or Monitor command whose working directory resolves to the main checkout, or cannot be verified to stay out of it, is blocked.
3. Git redirects: commands that point git at the main checkout through git -C, --git-dir, GIT_DIR or GIT_WORK_TREE, or a cd first, are blocked.
4. Command shape: commands whose git usage cannot be verified from the text, such as computed command names or unparseable syntax, are blocked, and Claude is told how to rewrite them. This check cannot be turned off.
The limit is stated plainly in the docs: these checks read paths, directories, and command text, and none tracks which files a shell command writes. A cp into the main checkout or a shell redirect such as echo x > ../main/file is not refused by them; it falls under your normal permission rules and sandbox settings.
Hooks also need care. ${CLAUDE_PROJECT_DIR} stays pointed at the project root where the session started, while the cwd field in the hook's JSON input follows Claude into the worktree. A hook that should act on the files Claude is editing must read cwd.
Quick reference
- Worktrees share the repository's
.gitdirectory, sogit commitfrom a worktree works even with the sandbox on. - "Yes, and don't ask again" approvals in a worktree are saved to the main checkout's
.claude/settings.local.jsonand apply to every worktree. - Claude Code refuses to create a worktree when
.claude,.claude/worktrees, or the worktree directory is a symlink.
Remember this
Edits, command directories, and git redirects into the main checkout are blocked; arbitrary shell writes are not, so keep permission rules and the sandbox on.
Worktrees for subagents
Subagents can each run in their own worktree so parallel edits inside one session do not collide. Ask Claude to "use worktrees for your agents", or make it permanent for a custom subagent with isolation: worktree in its frontmatter:
1---2name: refactorer3description: Applies mechanical refactors across many files4isolation: worktree5---6 7Apply the requested refactor across every affected file, then run the tests8and report the results.Each subagent gets a temporary worktree. Claude Code removes it automatically when the subagent finishes without changes; one with changes stays until a periodic sweep can remove it without losing work, based on your cleanupPeriodDays setting. While an agent runs, Claude Code holds a git worktree lock on its worktree so cleanup cannot remove it mid-task.
A subagent in its own worktree takes its instruction files from your main conversation. When the worktree is in the default location, it does not load the worktree branch's own CLAUDE.md or .claude/rules/, even if they differ.
Quick reference
- The sweep never removes worktrees you created yourself with
git worktree add, or ones that still hold uncommitted work or unpushed commits. /batch <instruction>splits a large change across subagents, each in its own worktree.- Subagent worktrees branch from the same base as
--worktree; setworktree.baseRefto"head"if they need your in-progress work.
Remember this
isolation: worktree gives each subagent its own checkout; changed worktrees survive until you merge or the sweep can safely remove them.
Choose the base branch, or manage worktrees yourself
By default, new worktrees branch from the repository's default branch on the remote (worktree.baseRef: "fresh"), so each starts clean and matching origin. If the repository has not been fetched in 24 hours, Claude Code fetches the default branch first (capped at five seconds) and falls back to the cached ref. To branch from your current local HEAD instead, including unpushed commits, set:
1{2 "worktree": {3 "baseRef": "head"4 }5}baseRef cannot name a branch. To start from a specific existing branch, or to put the worktree outside the repository, use git directly:
1git worktree add ../project-feature-a -b feature-a # new branch2git worktree add ../project-bugfix fix-issue-456 # existing branch3cd ../project-feature-a && claude4git worktree list5git worktree remove ../project-feature-aWorktrees you create this way get the same sharing (plugins, approvals, untracked skills read-through), but Claude Code's automatic cleanup never removes them.
Quick reference
- In a large monorepo,
worktree.sparsePathschecks out only the listed directories in each Claude-created worktree; see the monorepo guide. - If you set up Git LFS with
git lfs install --local, Claude-created worktrees contain LFS pointer files; rungit lfs pullinside the worktree. - A
WorktreeCreatehook can also place worktrees outside.claude/worktrees/entirely.
Remember this
Fresh base by default; baseRef: head for in-progress work; plain git worktree add for a specific branch or location.
Errors you may hit
Most worktree problems are about git identity. Claude Code checks that a worktree really is a separate checkout before using it, because a directory whose git metadata points back into the main checkout would let an ordinary git reset --hard destroy work there. When it refuses, it leaves the directory in place, since it may hold work, and the end of the message names the recovery.
When something looks wrong, run git worktree list from the main checkout first. It shows each worktree's path, branch, and lock state, which explains most surprises.
| Message or symptom | Cause | Fix |
|---|---|---|
| --worktree exits asking for trust | No workspace trust in this directory | Run plain claude once and accept the trust dialog |
| Worktree creation fails on a symlinked path | .claude or the worktree path is a symlink | Remove the symlink and retry |
| LFS files are pointers in the worktree | LFS filter set with --local in .git/config | Run git lfs pull in the worktree |
| Refusing to use <path> as an isolation worktree | Its git metadata resolves into the main checkout | Follow the message: launch from the main checkout or recreate |
| Session resumes outside its worktree | Worktree deleted or could not be verified | Read the message; resume from the main checkout |
| git worktree remove refuses: locked | Lock left from a -p run or running agent | git worktree unlock, then remove |
Quick reference
- Never delete a refused directory before reading why it was refused; some messages point at the main checkout's metadata, not the worktree's.
- Claude Code skips the repository's own filter drivers when creating worktrees, because a filter driver is a shell command anything could have written.
- Worktrees at network paths are never resumed into; recreate them on a local path.
Remember this
Start with git worktree list; refusals protect the main checkout, and the message's ending tells you the fix.
Hands-on: two parallel sessions and a subagent
Use a repository with a test command.
1. Add .claude/worktrees/ to .gitignore and create .worktreeinclude containing .env.
2. In two terminals, run claude -w add-validation and claude -w update-docs, and give each a small task.
3. In each, run git status and git branch --show-current. Confirm separate files and branches.
4. In the first session, ask Claude to run echo test > ../../../scratch.txt (a new file in the main checkout) and see whether it is blocked or falls to a permission prompt.
5. Create .claude/agents/refactorer.md with isolation: worktree and ask Claude to use it for a rename across three files.
6. Exit both sessions; keep one worktree and remove the other. Run git worktree list.
Pass criterion: the sessions never saw each other's changes, the subagent worked in its own worktree, and git worktree list shows exactly the worktrees you chose to keep.
Quick reference
- Step 4 shows the boundary in practice: shell writes are governed by permissions and the sandbox, not by the worktree checks.
- If
.envdid not appear in a new worktree, check that it is gitignored;.worktreeincludecopies only ignored files. - Remove the kept worktree with
git worktree removewhen you have merged its branch.
Remember this
Prove separation, the shell-write boundary, and cleanup once before relying on parallel sessions.
Key takeaway
Git worktrees are how Claude Code runs several sessions on one repository without collisions: claude --worktree <name> creates .claude/worktrees/<name> on its own branch, .worktreeinclude copies gitignored local files, and interactive exits either clean up or ask before deleting work. Subagents can get their own worktrees with isolation: worktree, and worktree.baseRef chooses between a fresh default-branch base and your current HEAD.
Inside a worktree, Claude Code blocks edits, command directories, and git redirects that target the main checkout, but not every shell write, so permission rules and the sandbox still matter. And each worktree is a full checkout: install dependencies and use separate ports. For the permission rules involved, see Claude Code Permissions; for running sessions in the background, see Agent View.
Practice (30 min): complete the six steps above, then decide which of your tasks are independent enough to run in parallel worktrees.
References
- Claude Code docs: Run parallel sessions with worktrees — checked Oct 17, 2026
- Git documentation: git-worktree — checked Oct 17, 2026
- Claude Code docs: Subagents — checked Oct 17, 2026
Shoaib Hossain
Lead Author & Systems ArchitectSoftware engineer and distributed systems architect specializing in backend scalability, cloud-native infrastructure, databases, and AI engineering workflows. Author and maintainer of Core Concept Learning.
Related Articles
Explore this topic