Git worktrees for parallel branch work
How and when to use git worktree to keep multiple branches checked out at once, sharing one object store, without the disk cost or coordination headaches of multiple clones.
On this page
A clone gets expensive once you need three branches open at the same time. git worktree is the underused alternative: one repository, many working directories, one object store. Reach for it the moment you find yourself either stashing work to switch branches or running git clone against the same remote a second time.
Git worktree
A linked working directory attached to an existing repository — shares objects and most refs, owns its own HEAD and index.
The repository created by git clone or git init is the main worktree. Every additional directory created by git worktree add is a linked worktree. Linked worktrees share the object database and refs/* with the main, but each has its own HEAD, index, and pseudorefs. The headline rule that falls out of that design: one branch cannot be checked out in two worktrees at the same time — Git refuses by default.
What is shared, what is per-worktree
The shared object store is why a worktree is cheap. Disk usage is roughly “the checked-out files plus a tiny .git gitfile that points back to the main.” A second git clone would re-download every object the main already has.
When a worktree pays for itself
-
Interrupt-driven hotfix without stashing
A teammate pages you with a P1 while you have a half-finished refactor staged.
git worktree add -b hotfix-123 ../hotfix-123 origin/maingives you a clean branch offmainin a sibling directory. Your refactor stays exactly as you left it. -
Parallel feature branches
Three branches you actually need to switch between today (auth, billing, perf profiling) become three worktrees side by side. No stash juggling, no “did I commit before checking out?” anxiety.
-
Long-running build or test in isolation
git worktree add --detach ../test-run HEADgives you a throwaway checkout to run a 20-minute integration suite while you keep coding in the main worktree. -
Reproducing a bug on a clean checkout
Spinning up a worktree at a tag (
git worktree add ../repro v1.4.2) is faster thangit stash,git checkout, then untangling everything later.
The commands you actually use
# New branch off current HEAD, in a sibling directory
git worktree add ../feature-x
# Existing branch
git worktree add ../release release
# New branch from an explicit start point
git worktree add -b hotfix-login ../hotfix origin/main
# Detached HEAD, for throwaway builds/tests
git worktree add --detach ../test-run HEADgit worktree list -v # what exists, where, and on what HEAD
git worktree remove ../feature-x # safe: refuses if dirty
git worktree prune -v # drop stale admin records after manual deletes
git worktree repair # fix links after manual moves/copiesIf <commit-ish> is omitted, Git names the branch after basename(<path>). The shorthand - resolves to @{-1} (the previously checked-out ref) — handy when scripting.
Worktree vs second clone
| Axis | Worktree | Second clone |
|---|---|---|
| Disk | Shares object store; only the checked-out files cost space. | Full duplicate — every object, every ref, every pack. |
| Creation time | Near-instant; no network fetch. | Full clone — re-downloads everything from the remote. |
| Branch safety | Built-in: refuses duplicate checkout by default. | No coordination — easy to make divergent commits on the same branch in two places. |
| Fetch propagation | Fetch once; every worktree sees the new refs. | Each clone fetches independently. |
| Mental cost | Requires knowing what's shared vs per-worktree. | Familiar — it's just another repo. |
Sharp edges
Conventions worth adopting
- Pick a naming scheme and stick to it:
../wt-<branch>keeps siblings sortable and obvious in shell completion. - Treat
git worktree list -vas the source of truth — never poke at.git/worktrees/files directly. - Lock worktrees on removable drives with a reason:
git worktree lock --reason "external disk" ../portable. Otherwise Git’s auto-prune will quietly drop the admin record after the configured expiry. - For scripting, prefer the porcelain output:
git worktree list --porcelain -z.
Recovery playbook
| Symptom | Action |
|---|---|
worktree list shows a prunable entry | git worktree prune -v |
| Linked worktree was moved or copied manually | git worktree repair from the main worktree |
| “branch already checked out elsewhere” | git worktree list to find the holder; remove or switch |
| Config differs by worktree unexpectedly | Inspect via git rev-parse --git-path config.worktree |
When in doubt, git rev-parse --git-path <name> is the safe way to resolve any path Git uses — it picks the per-worktree or shared file as appropriate without you having to know which.
The official git-worktree(1) man page is the authoritative reference and worth reading in full once you start relying on this command.
Related
- Git· mutualIgnoring files beyond .gitignoreLocal-only ignores, untracking already-tracked files, hiding local edits to tracked files, and a global ignore for OS junk — the four problems .gitignore alone doesn't solve.
- Git· mutualStacked diffs: commits as review unitsTreat each commit (or tiny branch) as the unit of review, not a large feature branch. Smaller reviews, less waiting, better commit hygiene — and a non-trivial rebase tax to pay.
- Git· mutualGit submodules without surprise detached HEADsSubmodules embed one repo inside another by pinning a commit, not a branch. Knowing that single fact prevents most of the pain — detached HEADs, missed pushes, and silent divergence after a pull.
- Git· relatedGit rebase without losing workWhat rebase actually does to your commits, how to drive the interactive form, and the recovery moves that keep a bad rebase from becoming a lost-work incident.