Git Worktrees
What Are They?
A git worktree is a checked-out copy of a branch that lives in a separate directory on your filesystem, but shares the same underlying git repository (.git database) as your main clone.
Normally, a single git clone has one working directory — the files you see and edit. A worktree lets you have multiple working directories at once, each on a different branch, all tied to the same repository. You don’t clone the repo a second time; you project a second (or third, or fourth) working directory from the one clone.
~/.git/ ← shared: all objects, refs, config
~/projects/myapp/ ← main worktree (branch: main)
~/projects/myapp-feature/ ← linked worktree (branch: feature/auth)
~/projects/myapp-hotfix/ ← linked worktree (branch: hotfix/crash)
All three directories above read and write to the same .git object store. Commits made in any worktree are immediately visible to all others.
Core Commands
Add a worktree
# Check out an existing branch into a new directory
git worktree add ../myapp-feature feature/auth
# Create a new branch and check it out in one step
git worktree add -b feature/new-thing ../myapp-new-thing main
The first argument is the path for the new directory. The second is the branch name (or starting commit).
List worktrees
git worktree list
Example output:
/home/you/projects/myapp abc1234 [main]
/home/you/projects/myapp-feature def5678 [feature/auth]
Remove a worktree
# Remove the directory and deregister the worktree
git worktree remove ../myapp-feature
# Force-remove even if there are untracked or modified files
git worktree remove --force ../myapp-feature
After deleting a linked worktree directory manually (e.g. with rm -rf), git still knows about it. Clean up the stale reference with:
git worktree prune
Move a worktree
git worktree move ../myapp-feature ../myapp-auth-feature
Typical Workflows
Work on two branches simultaneously
You’re deep in a feature branch when a urgent bug report comes in. Instead of stashing your work or committing a WIP, you add a worktree:
git worktree add ../myapp-hotfix main
cd ../myapp-hotfix
# fix the bug, commit, push — then come back to your feature
Your feature working directory is untouched.
Run tests against a different branch without switching
git worktree add /tmp/myapp-test origin/release/2.0
cd /tmp/myapp-test
cargo test
You keep your editor open on main while tests run elsewhere.
Review a colleague’s PR locally
git fetch origin
git worktree add ../review-pr-123 origin/pr/123
cd ../review-pr-123
# read, run, evaluate — then remove when done
git worktree remove ../review-pr-123
How It Works Internally
When you run git worktree add, git:
- Creates a subdirectory inside
.git/worktrees/<name>/to store the worktree’s private state (itsHEAD, index, and a back-reference to the working directory path). - Writes a
.gitfile (not a directory) into the new working directory that points back to.git/worktrees/<name>/. - Checks out the requested branch into the new directory.
The object database (all commits, trees, blobs) is shared. Only the index and HEAD are per-worktree.
Limitations and When to Avoid Them
Each branch can only be checked out once
The most important constraint: a single branch cannot be checked out in two worktrees at the same time. Git enforces this to prevent the two trees from diverging their indexes silently. If you try, you’ll get an error:
fatal: 'feature/auth' is already checked out at '/home/you/projects/myapp'
Workaround: check out the second worktree at a specific commit (detached HEAD), or create a local tracking branch.
Tools that look for .git as a directory can break
Some tools assume .git is a directory, not a file. A linked worktree has a .git file instead, which confuses:
- Older git GUIs that scan for
.git/directories - Some shell prompts and plugins that detect git repos naively
- Scripts that do
test -d .git
Build systems that use the working directory path
If your build system or language tooling caches absolute paths (e.g. Cargo’s target/ directory is placed relative to the workspace root), separate worktrees work fine — each has its own target/ directory. But if a tool bakes the source path into cached artifacts, switching between worktrees may cause spurious rebuilds or cache invalidation.
Hooks run in the worktree context, not the main repo
Git hooks in .git/hooks/ apply to all worktrees. But the working directory ($GIT_WORK_TREE) will be the linked worktree path, not the main repo path. Hook scripts that assume a fixed working directory can behave unexpectedly.
Not a substitute for branches in CI
Worktrees are a local developer convenience. Don’t model CI pipelines around them — use proper branch checkouts in ephemeral CI environments instead.
Submodules require extra care
Submodules are not automatically initialized in a new worktree. You need to run git submodule update --init inside each linked worktree where you need them.
Avoid for long-lived parallel development
If you find yourself maintaining two worktrees of the same repo for weeks at a time, that’s a signal you might want two separate clones or a proper branch strategy — not worktrees. Worktrees shine for short-lived parallel work (hotfixes, reviews, quick tests), not as a permanent parallel development setup.
Quick Reference
| Task | Command |
|---|---|
| Add a worktree for an existing branch | git worktree add <path> <branch> |
| Add a worktree and create a new branch | git worktree add -b <branch> <path> <start-point> |
| List all worktrees | git worktree list |
| Remove a worktree | git worktree remove <path> |
| Clean up stale worktree records | git worktree prune |
| Move a worktree | git worktree move <old-path> <new-path> |