The first time you run two coding agents on the same repository, you learn the lesson fast. Agent A is halfway through a refactor when agent B runs the test suite, sees broken imports, and "fixes" them. Or both edit the same lock file. Or one of them switches branches and the other keeps writing into a checkout that no longer matches its plan.
Agents are now good enough that a single developer can usefully run three or four of them at the same time: one on a bug, one on a feature, one writing tests, one exploring a spike. The bottleneck is no longer the model. It is the working directory. A normal Git checkout has exactly one branch, one index and one set of files on disk, and every process that touches it shares all three.
Git has had the answer since version 2.5 (2015): worktrees. One repository, many checked-out directories, each on its own branch. Agent tools have caught up. Claude Code added a --worktree flag in February 2026, and OpenAI's Codex app, launched the same month, runs agent threads in worktrees by default.
This post is the cheatsheet I wish I had before I started: the mental model, the commands, the setup traps, and a workflow that keeps parallel work mergeable.
1. The mental model
A Git repository has two parts: the object database and refs (commits, branches, tags, all inside .git) and a working tree (the files you edit, plus HEAD and the index that say what is checked out and staged).
A worktree is an extra working tree attached to the same repository.
| Thing | Shared across worktrees? | Consequence |
|---|---|---|
| Commits, objects | Yes | A commit made in one worktree is immediately visible from all others. No push or fetch needed. |
Branches and tags (refs/heads, refs/tags) |
Yes | Create a branch in one, see it everywhere. |
| Remotes and most config | Yes | git fetch in any worktree updates the remote-tracking refs for all. |
HEAD |
No, per worktree | Each worktree has its own current branch. |
| Index (staging area) | No, per worktree | git add in one never stages files in another. |
| Files on disk | No, per worktree | The whole point: edits are isolated. |
refs/bisect, refs/worktree, refs/rewritten |
No, per worktree | You can bisect in one worktree while working in another. |
Untracked and ignored files (.env, node_modules, .venv) |
No, and not copied | Each new worktree starts without them. See section 4. |
Two rules matter in practice:
- One branch, one worktree. By default
git worktree addrefuses to check out a branch that is already checked out somewhere else. That is a feature: it stops two agents from writing to the same branch. - Worktrees are cheap. They share the object database, so a new worktree costs only the disk space of the checked-out files, not a second clone.
Worktree vs. clone vs. branch switching
| Approach | Isolation | Cost | Sharing commits | Good for |
|---|---|---|---|---|
git switch in one checkout |
None: one task at a time | Free | Trivial | A single person, serial work |
git stash + switch |
None, plus the risk of losing a stash | Free | Trivial | Quick interruptions |
Second git clone |
Full | Disk and network for a full clone | Push and fetch between clones | Different remotes or very different setups |
git worktree add |
Files, index, HEAD |
Checked-out files only | Instant, same repo | Parallel agents and parallel humans |
| Container or VM per agent | Files, processes, network | Highest | Via push or mounted volume | Untrusted code, conflicting services |
Worktrees isolate files. They do not isolate processes, ports, databases or credentials. If two agents both start a dev server on port 8000 or migrate the same local Postgres, worktrees will not save you. Keep that limit in mind for section 4.
2. The commands you need
# Create a worktree on a NEW branch, based on main
git worktree add -b feat/invoice-export ../myrepo-invoice-export main
# Create a worktree for an EXISTING branch
git worktree add ../myrepo-hotfix hotfix/login-timeout
# Detached HEAD: throwaway experiments, no branch created
git worktree add --detach ../myrepo-spike HEAD
# See all worktrees (path, commit, branch)
git worktree list
git worktree list --porcelain # stable, script-friendly output
# Remove a worktree when done (refuses if there are uncommitted changes)
git worktree remove ../myrepo-invoice-export
git worktree remove --force ../myrepo-spike # discard changes
# Clean up metadata for worktree directories deleted by hand
git worktree prune --dry-run --verbose
git worktree prune
# Protect a worktree on a removable disk or network share from pruning
git worktree lock --reason "on external SSD" ../myrepo-data
git worktree unlock ../myrepo-data
# Move a worktree, or repair links after moving the main repo
git worktree move ../myrepo-spike ../spikes/myrepo-spike
git worktree repair
Useful details:
-b <branch>creates the branch;-Bresets it if it already exists. Use-Bcarefully: it can throw away commits on that branch.git worktree add <path>with no branch creates a new branch named after the last path component. Explicit-bis clearer in scripts.- Inside a linked worktree,
.gitis a small file, not a directory. It points back to.git/worktrees/<name>in the main repository. Tools that assume.gitis a directory can break; most modern tools handle it. git rev-parse --show-toplevelgives the root of the current worktree.git rev-parse --git-common-dirgives the shared.git. Scripts should use these instead of guessing paths.- Recent Git (2.48 and later) can link worktrees with relative paths (
--relative-paths, orworktree.useRelativePaths). This helps when the repository lives in a container volume or gets moved, at the cost of compatibility with older Git versions.
3. Directory layout and naming
Pick one layout and stick to it. Agents and scripts work better with predictable paths.
| Layout | Example | Pros | Cons |
|---|---|---|---|
| Siblings of the main checkout | ~/code/myrepo, ~/code/myrepo-feat-x |
Simple, visible, editors open them as separate projects | Clutters the parent directory |
| Dedicated folder next to the repo | ~/code/myrepo.worktrees/feat-x |
Tidy, easy to clean up in bulk | One more path convention to remember |
| Inside the repo, ignored | ~/code/myrepo/.worktrees/feat-x or a tool folder such as .claude/worktrees/ |
Self-contained, what some agent tools default to | Must be in .gitignore, and some file watchers and test runners will crawl it |
Naming conventions that pay off:
- Branch name = task, worktree folder = branch slug.
feat/invoice-exportlives ininvoice-export. When you have six terminals open, the folder name is your only clue. - Prefix agent branches, for example
agent/or the agent name. It makes them easy to list (git branch --list 'agent/*') and easy to delete in bulk. - One task per worktree. If an agent wants to "also fix" something unrelated, that is a new worktree and a new branch, not scope creep in the current one.
If you put worktrees inside the repository, add the folder to .gitignore and to the exclude lists of your test runner, linter and formatter. Otherwise pytest in the main checkout will happily collect tests from every worktree.
4. Per-worktree setup: the part that actually breaks
A fresh worktree contains exactly the tracked files of its branch. Everything else your project needs to run is missing.
| Missing piece | Symptom | Fix |
|---|---|---|
.env, local secrets |
App fails on startup, or the agent "fixes" config by hard-coding values | Copy or symlink from the main checkout in a setup script. Never commit them to make the problem go away. |
Virtual env / node_modules |
Import errors, agent runs pip install globally |
Create per worktree. With uv, uv sync is fast enough that this is a non-issue. For Node, pnpm shares a global store, so installs are cheap. |
| Build caches | First build is slow | Accept it, or point caches to a shared location if the tool supports it safely |
| Dev server ports | "Address already in use", or worse, agent B tests against agent A's server | Assign a port per worktree (section 7 derives one from the name) |
| Local database | Migrations from two branches fight over one schema | One database (or schema) per worktree, named after the branch; or use SQLite or containers per worktree |
| Docker Compose project name | Two worktrees share containers and volumes because the folder names collide or match | Set COMPOSE_PROJECT_NAME per worktree |
| Git hooks | Hooks live in the shared .git/hooks, so they run in every worktree |
Usually what you want. If hooks call tools with hard-coded paths, fix the paths. |
| Per-worktree Git config | You want a different identity or setting in one worktree | git config extensions.worktreeConfig true, then git config --worktree key value |
Write the setup down once, as a script in the repository (for example scripts/worktree-setup.sh), and make it idempotent. Then tell your agents about it in the project instructions file (CLAUDE.md, AGENTS.md or similar): "After creating a worktree, run scripts/worktree-setup.sh before anything else." Agents follow written setup steps far more reliably than they guess them.
Some agent tools also have hooks for this. Claude Code, for example, documents WorktreeCreate and WorktreeRemove hook events that run your own setup and teardown when it creates or removes a worktree.
5. How agent tools use worktrees (mid-2026)
The pattern has converged across tools: each agent session gets its own worktree and branch; you review the diff; you merge or discard.
| Tool | What it does with worktrees |
|---|---|
| Plain Git + any terminal agent | You run git worktree add, cd into it, start the agent. Works with every tool, no magic. |
| Claude Code CLI | Since v2.1.49 (February 19, 2026): claude --worktree <name> (or -w) starts a session in an isolated worktree, created under .claude/worktrees/ if you do not name a path. Subagents can declare isolation: worktree to work in a temporary worktree. Later releases added hooks, cleanup of stale agent worktrees, and a worktree.sparsePaths setting for large monorepos. |
| OpenAI Codex app | Launched February 2, 2026 for macOS. Agent threads run in Git worktrees so several can work on one repository without touching your local checkout. |
| Editors with background agents | Most of them now offer a "run in a worktree" option. Check where they create it and whether your setup script runs. |
Whatever the tool, check three things before you trust it with parallel work:
- Where does it create worktrees, and are they ignored by your test runner and file watchers?
- Does your setup run (env files, dependencies, ports)? If not, the agent will improvise.
- What happens on exit or crash? Are worktrees kept, cleaned up, or left behind with uncommitted work?
6. A workflow that stays mergeable
Parallelism moves the bottleneck from writing code to integrating it. Plan for that.
Before starting
- Split work into tasks that touch different files or modules. Two agents editing the same 200-line file in parallel will produce a conflict that costs more than the time you saved.
- Base every worktree on a fresh
main(git fetchfirst, thengit worktree add -b ... origin/main). - Give each agent a written task with acceptance criteria and the command that proves it is done ("
uv run pytest tests/billingpasses").
While running
- Keep each agent on its own branch. If two tasks turn out to need the same change, stop one and land the shared change first.
- Ask agents to commit early and often in their worktree. Small commits make review, cherry-picking and rollback easy.
- Check in regularly. A quick
git -C ../myrepo-feat-x log --oneline main..shows what an agent has committed without leaving your terminal.
Integrating
- Review each branch's diff on its own:
git diff main...feat/invoice-export(three dots: changes since the branches diverged). - Merge or rebase one at a time, rerunning the tests after each. The second branch to land is the one that finds the conflicts.
- Rebase waiting branches onto the new
mainbefore you review them:git -C ../myrepo-feat-y rebase main. Because worktrees share refs, the newmainis already there. - Throw away freely. A worktree that went in the wrong direction costs one
git worktree remove --forceand onegit branch -D. That is cheaper than rescuing it.
How many agents at once?
There is no magic number, but the limit is usually your review capacity, not the machine. Each parallel branch is a diff you must read, understand and own. If you cannot review it carefully, you are not working in parallel, you are just building up review work. Start with two or three, measure how long review and integration take, and scale from there.
7. A small Python helper
A minimal script to create a worktree with a predictable layout, a per-worktree port, and a copied .env. Standard library only.
#!/usr/bin/env python3
"""Create a git worktree for a task: new branch, setup files, a stable port."""
import hashlib
import shutil
import subprocess
import sys
from pathlib import Path
def git(*args: str, cwd: Path | None = None) -> str:
result = subprocess.run(
["git", *args], cwd=cwd, check=True, capture_output=True, text=True
)
return result.stdout.strip()
def port_for(name: str, base: int = 8100, span: int = 800) -> int:
"""Deterministic port per worktree name, so restarts reuse the same port."""
digest = hashlib.sha256(name.encode()).hexdigest()
return base + int(digest, 16) % span
def main(task: str, base_ref: str = "origin/main") -> None:
root = Path(git("rev-parse", "--show-toplevel"))
slug = task.lower().replace(" ", "-")
branch = f"agent/{slug}"
path = root.parent / f"{root.name}.worktrees" / slug
git("fetch", "--quiet", "origin", cwd=root)
git("worktree", "add", "-b", branch, str(path), base_ref, cwd=root)
env_src = root / ".env"
if env_src.exists():
shutil.copy2(env_src, path / ".env")
port = port_for(slug)
with open(path / ".env", "a", encoding="utf-8") as f:
f.write(f"\nPORT={port}\nCOMPOSE_PROJECT_NAME={root.name}-{slug}\n")
print(f"worktree: {path}\nbranch: {branch}\nport: {port}")
if __name__ == "__main__":
main(sys.argv[1])
Usage: python new_worktree.py "invoice export", then cd into the printed path, run your setup (uv sync, migrations), and start the agent there. Hash-based ports can collide; for a handful of worktrees the chance is small, and the server will fail loudly if it happens.
Cleanup is the mirror image:
git worktree remove ../myrepo.worktrees/invoice-export
git branch -d agent/invoice-export # -d refuses if not merged; -D forces
git worktree prune
8. Common mistakes
| Mistake | What happens | Better |
|---|---|---|
Deleting a worktree folder with rm -rf |
Git keeps stale metadata; the branch stays "checked out" and cannot be used elsewhere | git worktree remove, or git worktree prune after the fact |
| Running the test suite from the main checkout with worktrees inside it | Tests from every worktree get collected | Keep worktrees outside the repo or exclude the folder |
| Two worktrees, one database | Migrations and fixtures clash; flaky, confusing failures | One database or schema per worktree |
| Forgetting that commits are shared | Someone runs git branch -D or rebases a branch another worktree depends on |
Agree that each worktree "owns" its branch; never rewrite another worktree's branch |
| Long-lived agent worktrees | Branch drifts far from main, painful merge |
Short tasks, frequent rebase, merge or delete within a day or two |
| Treating worktrees as a security boundary | An agent can still read your home directory, use your credentials and reach the network | Worktrees isolate files, not permissions. Use sandboxing or containers for untrusted work. |
git worktree add -B on an existing branch |
Resets the branch and silently drops its commits | Use -b for new branches; check git worktree list first |
Why this matters
- Parallel agents need parallel checkouts. Without isolation, agents corrupt each other's state in ways that look like model mistakes.
- Worktrees are the cheapest isolation Git offers. No extra clone, no push and pull between copies, instant sharing of commits.
- The hard part is everything that is not tracked: env files, dependencies, ports and databases. Script it once and tell your agents.
- Integration is the new bottleneck. Small, independent tasks and one-at-a-time merging keep parallel work from turning into conflict resolution.
- Review capacity sets the limit. Every branch an agent produces is still code you are responsible for.
Final Thoughts
Worktrees are an old, unglamorous Git feature that suddenly matters, because the way many of us write code changed. When the unit of work becomes "start an agent on a task, review the result", a single checkout becomes a queue, and queues are slow.
The commands take ten minutes to learn. The discipline takes longer: small tasks, a setup script, one branch per worktree, careful review, and deleting what did not work without regret. Get those right and running three agents at once feels less like chaos and more like having a small team that never touches each other's files.
Sources
- Git documentation, git-worktree: subcommands and options, shared vs. per-worktree refs,
extensions.worktreeConfig, refusal to check out a branch that is already checked out,prune,lockandrepair, relative-path linking. - GitHub Blog, Release highlights from Git 2.5 (July 2015): introduction of
git worktree. - Anthropic, Claude Code changelog: v2.1.49 adds the
--worktree(-w) flag and subagentisolation: "worktree"; v2.1.50 addsWorktreeCreateandWorktreeRemovehooks; v2.1.76 addsworktree.sparsePaths. Release dates from the npm registry (v2.1.49 published February 19, 2026). - Anthropic, Claude Code common workflows: run parallel sessions with Git worktrees: worktree workflow for parallel Claude Code sessions.
- Techzine, OpenAI launches macOS app for agentic software development (February 2026): Codex app launch and its use of Git worktrees for parallel agents.
- Docker documentation, Specify a project name:
COMPOSE_PROJECT_NAMEand how Compose derives project names from the directory.