Git Worktrees, and How Coding Agents Use Them

For most of my career a git repository was a single desk. One folder on disk, one branch checked out,
one thing in progress. When a hotfix landed on top of a half-finished feature, I'd git stash, switch
branches, fix the thing, switch back, git stash pop, and hope I remembered what state I'd left
everything in. It worked, but it always felt like I was fighting the tool to do two things at once.
Git worktrees are the feature that ends that fight, and most developers I talk to either have never
heard of them or tried them once years ago and moved on. That's a shame, because they've quietly become
one of the most important pieces of plumbing in modern development — especially now that I spend my days
running coding agents that need to work in parallel. This post is the explanation I keep giving: what a
worktree actually is, the five commands that cover real use, and why every agent harness worth its salt
is built on top of them.
One repository, many working directories
Here's the mental model. A git repository is really two things glued together: the object store (all
your commits, trees, and blobs — the entire history, living in .git) and a working directory (the
actual files you edit, which are just one commit checked out onto disk). For most of git's life those two
came as a pair: one .git, one working directory.
A worktree breaks that one-to-one assumption. It lets a single repository — a single object store and set
of branches — project itself onto several working directories at once, each sitting at a different
commit or branch. You don't clone anything. The history isn't copied. You just get another folder where a
different branch is checked out, backed by the same underlying repo.
So instead of one desk, you have several, all reading from and writing to the same filing cabinet. On
desk A you're on main. On desk B you're on feature/payments. On desk C an experiment. Switching
between them is just cd — no stashing, no branch-switching, no losing your place.
The five commands you actually need
Worktrees have a small, friendly surface. This is essentially all of it.
Create one. Point at a path and a branch:
# check out an existing branch into a new sibling directory
git worktree add ../myapp-payments feature/payments
# or create a brand-new branch at the same time
git worktree add -b hotfix/login ../myapp-hotfix main
That second form is the one I use most: "give me a fresh directory on a new branch hotfix/login,
branched from main." A few seconds later ../myapp-hotfix exists, fully checked out, ready to build.
See what you've got.
git worktree list
# /home/joche/myapp a1b2c3d [main]
# /home/joche/myapp-payments e4f5g6h [feature/payments]
# /home/joche/myapp-hotfix a1b2c3d [hotfix/login]
Tear one down when you're finished:
git worktree remove ../myapp-hotfix
Clean up stale entries — if a worktree directory got deleted by hand, git still has a bookkeeping
record of it. prune clears those out:
git worktree prune
Lock one you want git to leave alone (handy when a worktree lives on a removable or network drive):
git worktree lock ../myapp-payments
That's the whole toolkit. add, list, remove, prune, lock. Everything else is just normal git
inside each directory.
What's shared and what isn't (the part that bites people)
This is the bit worth slowing down on, because the surprises all come from here.
Shared across every worktree — they're one repository, after all:
- the commit history and all objects (a commit you make in one worktree is instantly visible to the
others — same object store), - the branches, tags, and refs,
- the stash, the config, and the hooks in
.git/hooks.
Not shared — these live in the working directory, so each worktree has its own:
- your uncommitted edits, HEAD, and index (the whole point — isolation),
- untracked and ignored files:
node_modules, build output,.env,bin/,obj/.
That last point is the one that trips everyone up. Spin up a fresh worktree for a Node or .NET project and
it does not come with node_modules or a bin/ folder — those are gitignored, so they were never part
of the repo. You have to run npm install (or dotnet restore/build) in each new worktree before it'll
run. The flip side is also true and occasionally nasty: because the same branch can't be checked out in
two worktrees at once, git will flatly refuse git worktree add if that branch is already live
somewhere. That refusal is a feature — it's what stops two desks from fighting over the same branch — but
it surprises people the first time.
One more bit of plumbing worth knowing, because it demystifies the whole thing: a linked worktree's .git
isn't a directory, it's a small text file containing a single line — gitdir: /path/to/main/.git/worktrees/<name>
— pointing back to the real repository. That's the entire trick. The working files are local; the brains
are shared.
Why coding agents live and die by this
Everything above was true and useful long before AI. But worktrees went from "neat trick" to "core
infrastructure" the moment I started running coding agents in parallel — and understanding why is
the real point of this post.
A coding agent edits files. If you want several agents working at the same time — one fixing a bug,
one writing tests, two trying competing approaches to the same feature — they cannot share a single working
directory. They'd overwrite each other's edits, trip over each other's half-finished changes, and leave you
with a directory that's some incoherent blend of three different ideas. You'd be back to git stash, except
now the stashing is happening between robots and nobody's keeping track.
Worktrees solve this exactly. Give each agent its own worktree on its own branch:
git worktree add -b agent/fix-auth ../run-fix-auth main
git worktree add -b agent/add-tests ../run-add-tests main
git worktree add -b agent/refactor-db ../run-refactor-db main
Now three agents run fully isolated, in parallel, each in its own directory on its own branch — but all
reading from the same history, so they all started from an identical, consistent main. No locks, no
collisions, no shared mutable state. When they finish, you have three branches you can diff, review, and
merge (or throw away) independently. This is the foundation of the "fan out N agents, compare the results,
keep the best one" pattern I wrote about in the chat-agent-harness
post — and it only works cleanly
because each contestant gets a real, isolated checkout.
The properties that make this so good for agents are worth naming:
- Isolation without cost. Each agent gets a genuine, separate working directory, but there's no
git clone— no re-downloading history, no duplicated.git. The object store is shared, so spinning
one up is fast and cheap on disk relative to a full clone. - Trivial, safe teardown. If an agent's attempt is garbage, you don't have to carefully unwind its
edits from a shared directory. You delete the worktree and prune the branch — the rest of your work was
never touched. That disposability is exactly what you want when an agent might go off the rails. - A clean review boundary. Each agent's entire contribution is one branch and one diff. You review it
in isolation and merge deliberately, instead of trying to untangle who-changed-what in a shared tree.
This is why it shows up as a first-class feature in agent tooling. In Claude Code, for instance, you can
launch a sub-agent with worktree isolation, and the harness spins up a temporary git worktree for it
automatically — and just as automatically removes it afterward if the agent didn't actually change
anything. You get the isolation guarantee for free, and you don't end up with a yard full of abandoned
directories. Under the hood it's exactly the commands above; the harness is just doing the bookkeeping so
the agents (and you) don't have to.
The setup I actually use
For day-to-day human work, I keep a flat convention: the main checkout at ~/code/myapp, and
task-specific worktrees as siblings — ~/code/myapp-<task>. They're easy to spot in a file browser, easy
to cd into, and git worktree list is my dashboard of what's in flight. I delete them aggressively;
a worktree should be cheap and disposable, not something you nurse for weeks.
For agent work I let the harness own the worktrees entirely. The only discipline that matters is the one
the gotchas above demand: each worktree needs its own dependency install before anything runs, and you
have to respect that a branch can only be checked out once. Get those two things right and the rest is just
git doing what it's good at — tracking history once, and lending it out to as many desks as you need.
If you've never run git worktree add, do it once on a real project this week. For solo work it'll quietly
delete a class of annoyance you'd stopped noticing. And if you're starting to orchestrate coding agents,
it's not optional — it's the substrate that makes safe parallelism possible at all.