4 min read
Claude Code in a git worktree: what it starts without, what conflicts after
We ran claude --worktree and merged three agents' branches back. The worktree skips unpushed commits and .env, and 2 of 3 merges conflicted on a shared list.
You want two Claude Code sessions working at once without one overwriting the other's files. The usual answer is one flag:
claude --worktree feature-authA git worktree is a second working directory attached to the same repository.
It has its own files and its own branch. It shares the history, the remotes and
.git with your main checkout. Two sessions in two worktrees cannot edit each
other's files. They can still collide later, when their branches come back to
main.
We measured both ends: what a worktree that Claude Code creates holds when the
session starts, and what happens when three worktree branches are merged back.
The run used git 2.39.5 and Claude Code 2.1.286, in throwaway repositories.
Claude Code ran with an empty config and printed /context, which makes no
model call. The merge part is plain git. We ran it twice and got the same
output. The script is in this site's repository.
What the new worktree has, and what it does not
Each test repository had one pushed commit, one commit not yet pushed, an
uncommitted line in CLAUDE.md, an untracked notes.txt, and a gitignored
.env and node_modules/. Then claude --worktree one:
| In the main checkout | Default | With .worktreeinclude | With baseRef: "head" |
|---|---|---|---|
| The commit you have not pushed | absent | absent | present |
.env (gitignored) | absent | present | absent |
node_modules/ (gitignored) | absent | absent | absent |
notes.txt (untracked) | absent | absent | absent |
Your uncommitted line in CLAUDE.md | absent | absent | absent |
By default the worktree starts at the last commit you pushed, not at the one
you are looking at. Claude Code branches from the default branch on the
remote. Work committed and not pushed is not there. In a repository with no
remote it falls back to your latest local commit. Setting worktree.baseRef to
"head" makes it start from your local HEAD.
The session reads the worktree's own CLAUDE.md. /context listed that file
and not the one in the main checkout. A rule you added to CLAUDE.md and did
not commit is not in force in the worktree.
.worktreeinclude copies what you list, if the file is gitignored. It does not
install anything: node_modules/ was absent in every case. A worktree needs
its own install.
Two smaller things:
- A
claude -p --worktreerun leaves its worktree behind, locked. The docs say so.git worktree removerefuses it withexit 128until you rungit worktree unlock - A branch can be checked out in one worktree only. Git refuses a second
worktree on
worktree-one, and refuses to delete that branch while the worktree exists
What conflicts when three worktrees come back
Three worktrees cut from one commit, one per agent. Each agent edits its own source file, so the code never overlaps. Each one also records that its task is done. The branches are merged into main one after another. When a merge conflicts, it is resolved the way a careful person would, and the next merge goes ahead.
| Where the agent writes "done" | Merges that conflicted |
|---|---|
| A shared checklist, tasks on adjacent lines | 2 of 3 |
| The same checklist, one unchanged line between tasks | 0 of 3 |
| A shared log, each agent appends a line | 2 of 3 |
| Each task's own file, status edited in place | 0 of 3 |
| A new file per change, nothing edited | 0 of 3 |
The source files never conflicted. Every conflict was in the file that records status. The first merge never conflicts, because main has not moved yet. From the second merge on, git sees two edits that touch: on neighbouring lines, or both at the end of the same file. Git will not guess the order, so it stops.
The checklist result is narrower than it looks. With a single unchanged line
between tasks, such as an owner: line, all three merges went through. What
causes the conflict is two edits next to each other, not the shared file
itself. A tidy checklist with one task per line puts every edit next to
another one.
Moving status into one file per task removed every conflict here. That is enough for this pattern, where each agent owns its own task. It stops being enough when two agents touch the same task on two branches. Where a task tracker keeps its status measures that case.
A checklist before you start parallel sessions
- Push first, or set
worktree.baseRefto"head". Otherwise the agent starts from code you have already changed - Commit
CLAUDE.mdchanges before you open the worktree. The session reads the worktree's copy - List
.envand other local config in.worktreeinclude, and run the install in each worktree - Do not let agents write status on neighbouring lines of one file. Use a file per task, or one line of space between entries
- After a
-prun, unlock and remove the worktree yourself
What this does not cover
- One machine: macOS, git
2.39.5, Claude Code2.1.286. Worktree behaviour in Claude Code has changed between versions, and its docs note several of those changes - No model ran. Part A reads the worktree Claude Code creates and the context it loads. Part B stands in for agents with scripted edits, so it shows git's rules and not how often real agents trigger them
- Interactive exits, which ask before removing a worktree, were not tested.
Neither were subagents with
isolation: worktreeor the desktop app's parallel sessions - Three agents and one-line edits. More agents add more neighbours
The script and both runs are in this site's repository under
docs/search-log/bench/. kadence records every change as a new file,
the last row of the second table, so parallel worktrees have nothing to
conflict over. Why task files conflict
measures how often status files conflict in real repositories.
Where the numbers come from
- Bench run 2026-10-12 with git 2.39.5 (Apple Git-154) and Claude Code 2.1.286, run twice with identical output apart from paths, pids and hashes. Script and full output in this site's repository: docs/search-log/bench/2026-10-12-claude-code-worktrees.sh and .txt
- Bench, part A: `claude -p --worktree one "/context"`, run with an empty CLAUDE_CONFIG_DIR and no MCP servers, in throwaway repositories holding one pushed commit, one unpushed commit, an uncommitted edit to CLAUDE.md, an untracked notes.txt and a gitignored .env and node_modules/
- Bench case A1, defaults: the worktree is at .claude/worktrees/one on branch worktree-one, at the pushed commit; the unpushed commit, .env, node_modules/dep.json and notes.txt are absent; its CLAUDE.md has 2 lines against 3 in the main checkout; /context lists the worktree's CLAUDE.md as the project memory file; the worktree is left locked
- Bench case A2: with `.env` in .worktreeinclude, .env is present in the worktree and node_modules/dep.json, notes.txt and the unpushed commit are still absent
- Bench case A3: with worktree.baseRef set to head, the worktree is at the unpushed commit; .env is absent
- Bench case A4: in a repository with no remote, the worktree is at the latest local commit
- Bench case A5: `git worktree remove` on the worktree a -p run created exits 128 with 'cannot remove a locked working tree'; after `git worktree unlock` it exits 0
- Bench case A6: `git worktree add` of branch worktree-one while it is checked out in the first worktree exits 128 with 'is already checked out at'; `git branch -D worktree-one` exits 1 with 'Cannot delete branch'
- Bench, part B: three worktrees from one commit, each agent edits its own source file and records its task as done; branches merged into main in the order 1, 2, 3; a conflict is resolved by taking main's side and replaying that agent's edit, then the next merge runs
- Bench case B1, a checklist with tasks on adjacent lines: merge 1 fast-forwards, merges 2 and 3 exit 1 with CONFLICT (content) in TASKS.md
- Bench case B2, the same checklist with one unchanged line between tasks: all 3 merges exit 0
- Bench case B3, each agent appends a line to one shared LOG.md: merges 2 and 3 exit 1 with CONFLICT (content) in LOG.md
- Bench cases B4 and B5, status in each task's own file, or a new file per change: all 3 merges exit 0 in both
- Claude Code docs, 'Run parallel sessions with worktrees', code.claude.com/docs/en/worktrees, fetched 2026-10-12: worktrees are created under .claude/worktrees/<name>/ on a branch named worktree-<name>; baseRef 'fresh' (default) branches 'from the repository's default branch on the remote'; .worktreeinclude copies files that 'match a pattern and are also gitignored'; '-p' runs have no exit prompt, so 'Claude doesn't clean up their worktrees'
- Google Trends, read 2026-10-12, worldwide, past 12 months: `claude code git worktree` is the second-largest related query for `git worktree`, and rising (docs/search-demand-trends-2026-10-12.md)