Git worktrees for parallel coding agents: what they isolate and what they share
7m read time verified against Claude Code 2.1.220

Git worktrees for parallel coding agents: what they isolate and what they share

Git worktrees give parallel coding agents their own files and nothing else. What --worktree isolates in Claude Code, what stays shared across the one .git, and the isolation choices the flag does not make for you.

Open three terminals, run claude --worktree in each, and ten seconds later you have three agents working on three features in three directories. Nothing overlaps. Nothing collides.

That is the pitch, and the file-level half of it is true.

The rest of the machine is shared, and that is the half with teeth.

What a git worktree actually isolates

A git worktree is a second working directory with its own checked-out files, its own index and its own branch, pointing at the same repository. One clone, several trees. That is the whole idea.

Claude Code has first-class support for them. Pass --worktree (or -w) with a name and you get a directory at .claude/worktrees/<name>/ on a new branch called worktree-<name>:

bash
claude --worktree feature-auth

Leave the name off and it invents one, something like bright-running-fox. Add --tmux and the session lands in its own tmux window. Hand it a pull request instead of a name and it fetches pull/<number>/head for you:

bash
claude --worktree "#1234"

Quote it, or your shell treats everything after the # as a comment.

Subagents get the same treatment. Add isolation: worktree to a custom subagent's frontmatter and every run happens in a throwaway checkout:

markdown
---
name: refactorer
description: Applies mechanical refactors across many files
isolation: worktree
---

While that agent runs, Claude Code calls git worktree lock on its directory so the periodic cleanup sweep cannot pull the floor out from under it.

Put .claude/worktrees/ in your .gitignore before you start, or your main checkout fills up with untracked files belonging to other agents.

The base branch is not where you are standing

Here is the first thing that catches people out. New worktrees do not branch from your current HEAD. They branch from your repository's default branch on the remote.

That is the worktree.baseRef setting, and it defaults to "fresh". So you are four commits deep on a feature branch, you spin up a worktree to have an agent fix something adjacent, and the agent quietly starts from origin/main. Everything you have not pushed is absent.

For a genuinely independent task that is the right default. For the common case, where the parallel work builds on what you are already doing, say so:

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

Inside a worktree, "head" resolves to that worktree's HEAD rather than the main checkout's.

A fresh checkout is not a working environment

A worktree checks out tracked files. Only tracked files.

So your .env is not there. Your .env.local is not there. Your node_modules is not there.

The env half has a first-party fix: a .worktreeinclude file in the project root, gitignore syntax. Anything matching a pattern that is also gitignored gets copied into every worktree Claude creates.

text
.env
.env.local
config/secrets.json

Dependencies are your problem. Every worktree needs its own install before an agent can build or test anything, and people have watched auto-created worktrees eat ten gigabytes in an afternoon.

On npm that is the price of admission. pnpm's content-addressable store symlinks packages from one place on disk, so the second install costs almost nothing. This is the rare situation where the package manager argument stops being religious and starts being arithmetic.

There is a second lever if the repository is big: worktree.sparsePaths checks out only the directories you name, and symlinkDirectories points each worktree's node_modules back at the main copy. Both live in the monorepo setup.

Ports and databases were never isolated

Worktrees give each agent its own files. Everything those files talk to is still shared.

Two agents running npm run dev will fight over port 3000. They also share your local Postgres, your Docker daemon, your Redis, your build caches and every artefact directory outside the repository. Agent A runs a migration, agent B's tests start failing, and neither has any way to work out why. Since 2.1.224 they can at least warn each other when something like that lands, which turns a silent failure into a sentence.

Nothing in the worktree machinery helps here, because git has no opinion about your dev server. Assign a port per worktree in that worktree's .env.local, give each one its own database name, or accept that one agent at a time gets to run the stack.

Real runtime isolation needs containers. Worktrees are the git layer. A container is the process layer. They compose, and neither one stands in for the other.

The one .git they all write to

Every worktree shares the repository's .git directory. That sharing is the design, and it is what makes worktrees cheap enough to create per task.

It also makes refs global.

  • Stashes are shared. The stash list lives in .git. An agent that stashes in one worktree has put that stash in every session's list, where it can be popped in the wrong tree.
  • Branches are shared. Delete a branch in one worktree and it is gone everywhere. You cannot check the same branch out twice, which is the one collision git actually catches for you.
  • Force operations are shared. A reset --hard or a rebase on a branch another worktree is standing on does exactly as much damage as it would without worktrees.

Read that list back and you will notice it is the destructive half of git. Worktree isolation protects your files from a confused agent and does nothing about the commands that rewrite history. If you would not hand an agent git push --force in your main checkout, your permission rules still have to say so inside a worktree.

The isolation only runs one way

That permission point has a sharp edge worth knowing about.

Approve a Bash command with "Yes, don't ask again" inside a worktree session and the rule is written to the main checkout's .claude/settings.local.json. It applies in your main checkout, in every other worktree, and it outlives the worktree that produced it.

That is the right behaviour. Nobody wants to re-approve npm test in five throwaway directories. Be clear about the shape of it though: files flow inward and stay put, permission grants flow outward and stick.

The disposable environment writes to your durable configuration. An answer you give at two in the morning in a directory you are about to delete is a permanent one.

Cleanup needs a habit

When you exit an interactive worktree session, Claude checks for changed files, untracked files and new commits. Clean and unnamed, it removes the directory and the branch. Anything else, it asks whether to keep or remove.

Two ways that stops happening:

  • -p runs have no exit prompt, so headless sessions never clean up after themselves. Clear them with git worktree remove.
  • Subagent worktrees holding work stay on disk until a periodic sweep can remove them without losing anything, governed by your cleanupPeriodDays setting.

Run git worktree list now and then. If you script agents at all, the disk fills up long before git starts complaining.

Generation parallelises, review does not

Everything above is solvable with a morning of setup. The real ceiling sits somewhere else.

People running this seriously settle at three to five concurrent agents. The tooling copes fine at eight, and the ceiling is you. Five worktrees produce five branches that all need reading, and reading is the part that never got faster.

Teams that go higher get there by removing overlap rather than adding isolation: one file, one owner, no two running tasks touching the same code. That rules out conflicts by design instead of resolving them afterwards, and it forces the planning to happen before any agent starts, which is where it belonged anyway.

Speed got cheap and judgement didn't, and parallel agents are the purest form of that trade. You can multiply generation with a shell flag. Your capacity to understand what comes back is exactly what it was yesterday.

One task, one worktree, closed when done

That is the same rule as clearing a session on a task boundary, applied to the filesystem instead of the context window. A long session accumulates stale context. A long-lived worktree accumulates a stale environment: a branch that drifted from main last Tuesday, dependencies from two lockfiles ago, a database left mid-migration.

Isolation is a set of decisions about files, refs, ports, data and permissions, and --worktree makes exactly one of them for you.

Make the other four deliberately.

(27 of 36)
01My Claude Code setup: status line, plugins and terminal02Superpowers: teaching Claude Code to think before it types03Claude Code hooks: deterministic control over AI workflows04The CLAUDE.md file: give your AI permanent memory05Stop asking your agent nicely06What's new in Claude Code: notes from the London talk07The best number in Opus 4.8 isn't a benchmark08Stale memory is worse than no memory09The agent is just a loop10Build an MCP server, then ask whether it should exist11Skill, subagent, hook, or slash command? Pick the right one12Log in to MCP servers from your shell13How to give Claude safe access to your SQL database14The day 'default' became 'Manual'15Claude Code skills: how to write one that works16How to write a proper Claude Code subagent17Claude Code permissions: the guide I wish the docs were18Sandboxing Claude Code: put your agent in a box that holds19Prompt injection defense for developers who ship agents20Best Claude model for coding: which one for which task21Refactoring legacy code with a coding agent: start with characterization tests22MCP server authentication: OAuth, scopes and rate limits23Opus 5 is here and your effort settings just expired24AI agent incident response: what to do when your coding agent goes wrong25Claude Code /doctor: what it checks and what changed26Claude Code context management: when to /clear and when to /compact27Git worktrees for parallel coding agents: what they isolate and what they share28Claude Code plan mode: decide before the agent writes29Debugging with a coding agent: give it the search, keep the hypothesis30Claude Code checkpoints and /rewind: how to undo an agent's changes31Claude Code cross-session messaging: how to make your sessions talk to each other32Audit logging for AI agents: what Claude Code records and what deserves a human33Sharing Claude Code config across a team: what a repo can and cannot enforce34Your Claude Code session has no clock35Claude Code in a large codebase: scoping an agent to the part that matters36Recovering a Claude Code session your picker will not show you