Parallel Sessions & Worktrees
|
This content was generated with the assistance of AI and should be verified against the official documentation of each tool and framework before being relied on in production. This section’s bibliography lists the reference material consulted while preparing these pages. |
This page targets the Claude Code CLI’s --worktree flag and VS Code’s Agents window, both checked against
Claude Code — Run parallel sessions with worktrees and
VS Code — The Agents window as of 2026-09-28; the
GitHub Copilot CLI’s cloud sandbox is checked against
GitHub Copilot — About cloud and local sandboxes,
where it is an experimental feature as of that date. The running example is the same DocsAssistant API Spring Boot + Python
sample used throughout this sub-section, with its Java sources under
src/main/java/com/example/docsassistant/, its tests under src/test/java/com/example/docsassistant/, and a
Python ingestion script under ingest/.
A git worktree is a second working directory checked out from the same
repository, on its own branch, sharing the repository’s history and remote with the main checkout. Running each
agent session in its own worktree means one session editing DocsController.java never touches files a second
session is editing under ingest/, even though both sessions share the same .git directory underneath.
Running several agents with git worktrees
Claude Code: --worktree
Passing --worktree (or -w) a name creates an isolated worktree and starts Claude Code in it. By default the
worktree is created under .claude/worktrees/<name>/ at the repository root, on a new branch named
worktree-<name>:
$ claude --worktree docs-endpoint
Running the same command again with a different name, in another terminal, starts a second isolated session; a
name left out is generated automatically (for example bright-running-fox). A worktree is a fresh checkout, so
project setup (installing dependencies, copying a local .env) has to be repeated inside it once — or copied in
automatically for every future worktree by listing the files in a .worktreeinclude file at the repository root,
in .gitignore syntax. Claude Code also enforces isolation on its own: while a session is running inside a
worktree, it blocks file edits and git commands that target the main checkout, so a stray "also fix this in the
other module" instruction cannot cross worktrees by accident. See
Claude Code — Run parallel sessions with worktrees.
Inside a running session, asking Claude to "work in a worktree" creates one on demand with the EnterWorktree
tool, and it can switch to another existing worktree the same way; entering a path outside
.claude/worktrees/ asks for approval first, because the move takes the session’s working directory and
project configuration with it. New worktrees branch from the repository’s default branch unless
worktree.baseRef is set to "head" in settings.json, which branches from the current local HEAD instead — useful when a worktree needs to continue in-progress, unpushed work rather than starting clean:
.claude/settings.json{
"worktree": {
"baseRef": "head"
}
}
The worktree keys are listed in
Claude Code — Settings reference.
Claude Code can also create a worktree straight from a pull request, fetching its head commit from origin:
$ claude --worktree "#42"
For a branch that already exists, or a worktree placed outside the repository, git worktree add directly is
the documented alternative to --worktree:
$ git worktree add ../docs-fix-456 fix-issue-456
$ cd ../docs-fix-456
$ claude
VS Code and the Copilot CLI
VS Code’s Agents window (opened with the Chat: Open Agents window command, or code --agents from a
terminal) manages several concurrent agent sessions across workspaces from one place; as of the date above, VS
Code’s documentation marks it as currently in preview. Starting a session there in a local git repository offers
a choice between letting the agent edit files directly in the folder or running it in an isolated git worktree,
optionally after checking out an existing local branch; that worktree isolation requires a local git repository
with at least one commit. Several sessions can stay open at once to compare results, though only one is active
for workspace actions at a time. See
VS Code — The Agents window.
The GitHub Copilot CLI documents a separate mechanism for running tasks in parallel: copilot --cloud starts an
interactive session in a GitHub-hosted cloud sandbox instead of the local machine, and its own docs describe this
as useful for running multiple tasks in parallel without consuming local resources. As of the date above cloud
sandboxing is an experimental feature, so experimental features must be enabled (for example
copilot --cloud --experimental), and it is available only for interactive sessions — --cloud cannot be
combined with the -p or -i options. See
GitHub Copilot — About cloud and local sandboxes
and GitHub Copilot — Cloud and local sandboxes.
Copilot’s own background cloud agent, covered on
Cloud & Background Agents, is a third,
unattended way to run a task off the local machine; it is not a worktree and does not run locally at all.
Splitting work by module
DocsAssistant API has a natural split for parallel work: the Java backend under
src/main/java/com/example/docsassistant/ (and its tests) is largely independent of the Python ingestion script
under ingest/. Two worktrees, one per module, let two sessions work at the same time without either one seeing
the other’s in-progress edits:
$ claude --worktree docs-endpoint # backend: add GET /api/pages/{id}
$ claude --worktree ingest-retry # ingest/: add retry logic to the ingestion script
Splitting by module works best when the modules' files genuinely do not overlap — two build files, two test suites, two sets of source files. A change that must touch both modules together (for example, an API contract both the Java controller and the Python script serialize against) is a poor fit for two independent worktrees, because neither session sees the other’s assumptions about the shared contract until they merge; that kind of change is better done in one session, or with the two sessions passing findings to each other rather than working in isolation (Claude Code’s cross-session messaging lets the sessions in separate worktrees do exactly that).
Fan-out / fan-in
Fan-out is starting several sessions on independent pieces of a larger task at the same time; fan-in is bringing their results back together once each piece is done. Two worktrees on two modules, as above, is the simplest fan-out: one prompt per session, each scoped to its own worktree and its own piece of DocsAssistant API.
docs-endpoint)$ claude --worktree docs-endpoint "add a GET /api/pages/{id} endpoint to
@src/main/java/com/example/docsassistant/DocsController.java that returns the page as a PageDto
using PageRepository.findById, or a 404 with a JSON error body when the id doesn't exist"
ingest-retry)$ claude --worktree ingest-retry "add exponential-backoff retry to the HTTP calls in
@ingest/build_index.py, up to 3 attempts, and log each retry"
Fan-in happens at the git level, not inside either session: once both sessions finish and commit, the two branches merge back into the integration branch one at a time, the same way any two feature branches would (see Branches). A third pattern — asking one Claude Code session to spawn several subagents for research run in parallel, each in its own context window investigating one module and returning a summary to the parent session — fans in automatically because the parent collects those summaries; by default it does not isolate file edits the way separate worktrees do, so it fits read-only investigation (for example, "look at the backend and the ingestion script in parallel and summarize how they’d need to change") better than two sessions that will both edit files. See Claude Code — Subagents for the difference in depth.
Merge-conflict strategy
Two worktrees on genuinely separate files, as in the DocsAssistant API split above, merge without conflicts most
of the time: git only needs to combine non-overlapping changes into one history. Conflicts still turn up when
both sessions touched a shared file — a shared pom.xml, a shared configuration file, or a README both agents
updated — and the strategy for handling them is the same one that applies to any two branches, agent-authored or
not:
-
Merge (or rebase) one branch before starting the next session’s merge, rather than merging both at once, so any conflict is between one worktree’s branch and the integration branch, never between two worktrees directly.
-
Keep each worktree’s changes reviewable on their own — a focused diff per module, as shown above — so a conflict, when it happens, is easy to read: it is one small change against another, not two large ones.
-
Resolve the conflict with the same tools used for any merge conflict — an editor’s three-way merge view, or
git statusplus manual edits — and, if useful, ask the agent in one of the worktrees to look at the conflict markers and propose a resolution once both sides are visible in its own worktree, rather than asking an agent that only saw one side to guess at the other.
See Merging, Rebasing and Conflicts for the full mechanics of resolving a conflict.
Worked example: two worktrees, then merge
Following the module split above end to end, from creating the two worktrees to a clean merge back into
main:
$ git checkout main
$ git pull
$ claude --worktree docs-endpoint "add a GET /api/pages/{id} endpoint to
@src/main/java/com/example/docsassistant/DocsController.java ..."
# ... session runs, commits its change on branch worktree-docs-endpoint ...
$ claude --worktree ingest-retry "add exponential-backoff retry to
@ingest/build_index.py ..."
# ... session runs, commits its change on branch worktree-ingest-retry ...
$ git checkout main
$ git merge worktree-docs-endpoint
$ git merge worktree-ingest-retry
Because DocsController.java and build_index.py are disjoint files, both merges are fast-forward or clean
three-way merges with nothing to resolve. If a later session on a third worktree had also touched
DocsController.java, that third merge could conflict with the first, and the strategy above — merge one
worktree’s branch at a time, resolve with the usual conflict tools — applies exactly as it would for any two
ordinary feature branches:
Once both worktrees' branches are merged and their work is confirmed on main, any worktree still on disk can be
removed with git worktree remove. Claude Code handles most of this itself when an interactive worktree session
exits: a clean worktree from an unnamed session is removed automatically along with its branch, a named session
prompts first so the worktree can be kept for later, and a worktree that still holds changes, untracked files or
new commits always prompts to keep or remove it. Non-interactive -p runs get no exit prompt and are not cleaned
up. Claude Code’s periodic sweep covers only worktrees it created for subagents and backgrounded sessions, once
they are older than the cleanupPeriodDays setting, and it keeps any worktree that still holds work as well as
the worktree of a --worktree session that was never backgrounded. See
Claude Code — Clean up worktrees.