Course · Lesson 13 of 30
Git Worktrees
Pro · 6 min read
git worktree lets one repository check out multiple branches into
multiple directories simultaneously — same history, same object store,
separate working files. It predates AI tooling by a decade and has
quietly become the load-bearing isolation primitive of agentic coding:
one agent, one worktree is the rule that lets several agents work
one codebase without corrupting each other, and every parallel pattern
in this course (lessons 19, 22, 29, 30) stands on it. This lesson: the
mechanics in two minutes, why agents specifically need this, and the
five sharp edges — each of which costs an afternoon the first time and
a sentence to prevent.
The mechanics
# new directory with that branch checked out
git worktree add ../myapp-auth feature/auth
# create branch and worktree together
git worktree add ../myapp-fix -b fix/timeout
git worktree list # what exists where
git worktree remove ../myapp-fix # after merge
git worktree prune # clean stale records
Each directory gets its own working files, its own index, its own
HEAD. Commits made anywhere land in the shared repository, visible
to all. A branch can only be checked out in one worktree at a time
(git enforces this), and the object store is shared — so worktrees are
cheap (no re-clone, no duplicate history) and coherent (no divergent
repos to reconcile). That's the whole feature. The judgement is in
knowing what it protects you from.
Why agents specifically need this
Run two agents in one directory and they share mutable state you
can't see them sharing: the working tree, the index, build caches,
scratch files, node_modules. The failure isn't a crash — it's
silent interleaving, and it's worth spelling out the actual
scenarios because they're what you'll be debugging otherwise:
- Agent A stages files for a focused commit; agent B runs
git commit -aand sweeps A's half-done work into B's commit, under B's message. Both report success. - Agent A runs the test suite; it fails bafflingly, because B is mid-edit in a shared module. A "fixes" the phantom failure, introducing a real bug.
- Both write
tmp/results.json. Last writer wins. Nothing reports the loss. A's conclusions are now computed from B's data — every number plausible, every number wrong.
Everything exits zero. The output is wrong in ways you discover much later, detached from the cause — the worst failure shape there is. Give each agent its own worktree and the shared mutable surface shrinks to the one thing git coordinates well: the commit graph. Conflicts still exist — two agents editing the same function on different branches collide at merge — but that's the visible, tooled, recoverable kind. Worktrees convert invisible corruption into ordinary merge conflicts, which is a magnificent trade.
Beyond safety, the workflow wins that make this daily-driver rather than emergency equipment:
- Parallel lanes for one human. An agent grinding a refactor in one worktree while you (or a second agent) hotfix in another — no stash shuffle, no "wait until it's done."
- Cheap review. An agent finishes a branch; you add it as a worktree beside main and diff, run, and compare side by side without disturbing the agent's directory.
- Disposability. A worktree per experiment means a failed
experiment is
git worktree remove— no archaeology into what it touched.
The five sharp edges
1. Paths are per-worktree, and agents resolve them wrong. A script, hook, or agent that computes "the repo root" by walking up from its own location can end up operating on a sibling worktree. The insidious part: containment logic tested in a single directory passes — "resolve from my location" and "resolve from the invocation" are identical when there's one directory — and silently fails exactly when parallelism arrives. Resolve paths from the invocation's working directory, and test any path-validation logic with two worktrees, never one. (Lesson 15's containment hooks inherit this rule directly.)
2. Uncommitted work is invisible across lanes. Agent A cannot see agent B's edits until B commits. For independent tasks, that's the point; for coupled tasks, it means integration surprises arrive at merge. Slice work so lanes are independent (lesson 11's batch-by-coupling rule), and merge frequently — long-lived parallel lanes are conflict factories, agentic or not.
3. The environment isn't isolated. Worktrees isolate files. They share your env vars, running services, databases, and ports. Two agents starting the dev server both want :3000; two test suites hitting one Postgres still race each other. Per-lane env files, per-lane ports, separate schemas or containers when it gets serious — the isolation you need is the isolation your stack needs, and worktrees only supply the filesystem layer.
4. Dependencies are per-directory. Each worktree needs its own
node_modules / venv / build cache. That's disk and setup time —
script it into lane creation (git worktree add ... && cd ... && npm ci), because an agent that finds dependencies missing will "fix" the
problem in creative ways you didn't want.
5. Cleanup is manual. Merged branches leave worktrees behind. A
dozen forgotten worktrees is a dozen stale copies of your code for
future greps (yours or an agent's) to find and be confused by.
git worktree list monthly; remove the corpses; prune the
records. Better: make lane cleanup part of your merge ritual or your
orchestrator's epilogue (lesson 22).
The mental model to keep
Git's history was designed for massive concurrency; git's working directory was designed for exactly one actor. Worktrees scale the actors by multiplying the directories, at the cost of a little disk and discipline — the cheapest concurrency correctness you will ever buy. When lesson 19 catalogs parallel hazards and lesson 22 builds orchestrated fleets, "each worker in its own worktree" is the sentence doing the heaviest lifting; learn the five edges here, at one lane, before the fleet makes each of them N times more expensive to discover.
A personal teaching project, in development. The registry it builds is a teaching artifact and is not an assurance opinion about any issuer. Not affiliated with or endorsed by any employer, or by any vendor whose tools it describes. Where a unit depends on a specific flag or path, it names the version it was verified against. All units.