Git Worktree Deep Dive: Parallel Branches, One Repository, Zero Headache
When people say “Git lets you have multiple branches,” they usually mean logically multiple branches inside one working directory. In real life, though, your working directory can only reflect one branch (one commit) at a time. That limitation is why developers constantly juggle git stash, temporary commits, or messy context switches.
git worktree solves this in a clean, first-class way: it lets you check out multiple branches at the same time, each in its own folder, while sharing the same underlying repository data. If you frequently multitask—hotfixes, review changes, long-running features—worktrees can make your workflow calmer and faster.
Below is an in-depth explanation of how it works, when it helps, where it bites, and how to use it effectively.
1) The mental model: Branch vs Worktree
Branch
A branch is just a name (a reference) pointing to a commit. It is not a folder. It does not “contain files” by itself. Your working directory materializes one commit at a time.
- Branch = pointer to a commit (
refs/heads/my-branch) - Working directory = the files you see on disk right now (checked out from one commit)
Worktree
A worktree is an additional working directory attached to the same repository. Each worktree can have its own branch checked out, simultaneously.
- Worktree = extra checkout folder + metadata linking it to the repo
- Multiple worktrees share the same
.gitobject database (efficient)
Key idea: With worktrees, you stop treating “one folder = one branch.” Instead you get “one repo = many folders, each on its own branch.”
2) Why Git worktree exists (the pain it removes)
Common pain without worktrees:
- You’re midway in a feature branch and suddenly need a hotfix on
main. - You either:
- stash changes (sometimes painful/unsafe if changes are half-baked),
- create a “WIP commit” you later rewrite,
- or keep switching branches and recompiling dependencies repeatedly.
With worktrees:
- Keep feature work open in one folder.
- Create a separate folder for hotfix branch.
- Switch contexts by switching folders, not branches.
This is especially powerful when your project has:
- expensive builds,
- heavy dependency installs,
- long-running test servers,
- or multiple “states” you want live at once.
3) How Git worktree actually works (under the hood, but practical)
Your main checkout has a .git directory (or a .git file pointing somewhere). With worktrees:
- There is still one “main” Git directory that stores objects, refs, etc.
- Each additional worktree gets:
- a working directory with files
- a small
.gitfile pointing to metadata stored under the main repo in something like:.git/worktrees/<name>/
Git uses that metadata to ensure safety:
- A branch is typically “locked” to a worktree while checked out there, preventing you from accidentally checking it out elsewhere and corrupting state.
4) Core commands you should know
Create a new worktree
Create a new worktree folder for an existing branch:
git worktree add ../my-hotfix hotfix/urgent-fix
../my-hotfix= path where the new working directory will be createdhotfix/urgent-fix= branch to check out there
If the branch doesn’t exist yet, create it:
git worktree add -b hotfix/urgent-fix ../my-hotfix origin/main
-bcreates the branchorigin/mainis the starting point
List worktrees
git worktree list
This shows:
- path of each worktree
- which branch/commit it is on
- and whether it’s “locked” or detached
Remove a worktree
Safest method:
git worktree remove ../my-hotfix
If the folder was deleted manually, clean up metadata:
git worktree prune
Lock / unlock (prevent pruning)
If you keep a worktree around for a long time:
git worktree lock ../my-hotfix
git worktree unlock ../my-hotfix
5) The biggest difference in day-to-day workflow
Without worktrees
- One folder
- constant branch switching
- repeated install/build cycles
- risk of stashing or half-commits
With worktrees
- One folder per context
- feature branch stays “warm”
- hotfix branch gets isolated
- you can run two dev servers at once, each from different worktrees
This is why many people say worktrees feel like “Git branches, but real.”
6) Worktrees vs cloning the repo twice
You can clone the same repo into two folders, but worktrees are better in most cases:
Why worktrees are better
- Disk efficient: objects are shared
- Faster: no second clone fetch
- Safer: branch checkout conflicts are managed
- Cleaner: one repo identity, many working directories
When separate clones are still useful
- You need different Git configs/remotes/credentials per copy
- You want totally separate
.gitmetadata (rare) - You want isolation across different Git versions/environments
7) Important gotchas (things people discover late)
1) Branches can be “in use”
If branch feature/x is checked out in a worktree, Git may prevent you from checking it out elsewhere.
This is a feature: it prevents two worktrees from writing to the same branch state.
2) Each worktree is a full working directory
Meaning:
- running
npm installin one worktree does not automatically apply to another - build artifacts are separate per folder
This is usually good (isolation), but it can surprise people who expected shared node_modules.
Tip: If you want shared dependencies, use tooling like:
- pnpm store, bun cache, cargo cache, etc.
But avoid symlinkingnode_modulesacross worktrees unless you really understand the tradeoffs.
3) Different worktrees can conflict on ports
If you run two dev servers:
- one will fail because port 3000 is taken
Use different ports per worktree (or.env.localper folder).
4) Hooks and tooling
Git hooks are usually stored in the main repo’s .git/hooks. However, your tools might reference relative paths assuming one working directory. Be mindful if scripts assume “repo root is current directory.”
8) Detached HEAD worktrees (and why you might want them)
A worktree can be created at a specific commit without attaching it to a branch (detached HEAD). Useful for:
- checking out a tagged release for a quick test
- reproducing a historical build
- bisecting without disturbing your active branches
Example:
git worktree add ../release-test v1.2.3
If v1.2.3 is a tag, you’ll likely be in detached HEAD state.
9) Practical patterns that work extremely well
Pattern A: Hotfix without interrupting feature
- Worktree 1:
feature/big-refactor - Worktree 2:
hotfix/payment-timeout
You fix, test, merge hotfix, and your feature worktree never moved.
Pattern B: Code review / PR checkout
Create a worktree just to review a PR branch:
git fetch origin pull/123/head:pr-123
git worktree add ../pr-123 pr-123
Now you can run it locally without messing your main workspace.
Pattern C: Release branch stability
Keep a long-lived worktree for release/1.8 to cherry-pick fixes while continuing normal work elsewhere.
Pattern D: Matrix testing
Have worktrees for:
mainfeature/xexperiment/y
Run tests in parallel, compare results quickly.
10) Recommendations and best practices
- Put worktrees in a predictable structure, e.g.:
~/code/myrepo/(main)~/code/myrepo-wt/hotfix-xyz/~/code/myrepo-wt/pr-123/
- Name branches/worktrees consistently:
- branch:
hotfix/xyz,feature/abc - folder:
wt-hotfix-xyz,wt-feature-abc
- branch:
- Regularly prune stale metadata:
git worktree prune
- Prefer worktrees over stash for long-lived context switching.
- Stash is fine for tiny interruptions.
- Worktrees are best for “I need to work on this for 1–3 hours.”
11) When you should NOT use worktrees
Worktrees are not always the best hammer:
- You are extremely space constrained (multiple
node_modulescan be large) - Your project setup assumes only one working directory (some older tooling)
- You rarely context-switch and stashing is enough
Even then, worktrees remain useful for:
- PR reviews
- quick hotfixes
- testing old tags
12) A simple “starter workflow” you can adopt today
- Keep your main folder on your primary branch:
cd ~/code/myrepo
git switch main
- Start a feature in a separate worktree:
git worktree add -b feature/new-dashboard ../wt-new-dashboard main
- Emergency hotfix arrives:
git worktree add -b hotfix/login-timeout ../wt-hotfix-login main
- When done:
git worktree remove ../wt-hotfix-login
This becomes addictive—in a good way.
Other considerations you might be missing
- CI parity: Having two worktrees lets you quickly reproduce “works on main, fails on branch” issues side-by-side.
- Faster debugging: You can run a debugger against one worktree while editing another.
- Safer experiments: Experimental branches stay isolated; no accidental merges or resets in your “real” workspace.
- Better mental clarity: You associate a physical folder with a task. Less “what branch am I on?” fatigue.
Comments ()