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 add refuses 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; -B resets it if it already exists. Use -B carefully: 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 -b is clearer in scripts.
  • Inside a linked worktree, .git is a small file, not a directory. It points back to .git/worktrees/<name> in the main repository. Tools that assume .git is a directory can break; most modern tools handle it.
  • git rev-parse --show-toplevel gives the root of the current worktree. git rev-parse --git-common-dir gives 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, or worktree.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-export lives in invoice-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:

  1. Where does it create worktrees, and are they ignored by your test runner and file watchers?
  2. Does your setup run (env files, dependencies, ports)? If not, the agent will improvise.
  3. 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 fetch first, then git 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/billing passes").

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 main before you review them: git -C ../myrepo-feat-y rebase main. Because worktrees share refs, the new main is already there.
  • Throw away freely. A worktree that went in the wrong direction costs one git worktree remove --force and one git 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