Last Tuesday I was deep in a refactor — 40 files touched, tests half-green — when Slack lit up: “Production’s returning 500s, can you look at main?” My old workflow: git stash, switch branches, forget what I stashed, lose 20 minutes reconstructing state. My current workflow: git worktree add ../hotfix main, fix the bug in a separate directory, push, delete the worktree, and I never left my refactor. Total context-switch cost: zero.
Git worktrees have been around since Git 2.5 (July 2015), but I’ve met maybe three developers who actually use them. Everyone else is still juggling git stash or cloning the repo twice. That’s a shame, because worktrees solve a real, daily problem — and they’re already on your machine.
What Git Worktrees Actually Are
A worktree is a linked checkout of your repository at a different branch or commit, in a separate directory, sharing the same .git data. One repo, multiple working directories, each on its own branch. No duplicate clones, no extra disk space for the object database.
# You're on feature/auth-refactor in ~/code/myapp
git worktree add ../myapp-hotfix main
# Now ~/code/myapp-hotfix has a full checkout of main
# Both share the same .git/objects — no duplicate data
The key constraint: each worktree must be on a different branch. Git won’t let two worktrees check out the same branch simultaneously (that would be a recipe for corruption). This is actually a feature — it forces clean separation.
Three Workflows Where Worktrees Save Real Time
1. Code Reviews Without Context Switching
I review 3-5 PRs a day. Before worktrees, reviewing meant either reading diffs in the GitHub UI (fine for small changes, terrible for architectural PRs) or stashing my work to check out the PR branch locally.
Now I keep a persistent review worktree:
# One-time setup
git worktree add ../review main
# When a PR comes in
cd ../review
git fetch origin
git checkout origin/feature/new-payment-flow
# Run tests, inspect code, check behavior
npm test
npm run dev # boot the app on a different port
# Done reviewing? Back to my branch
cd ../myapp
# My work is exactly where I left it
The time savings are measurable. I tracked it for two weeks: stash-and-switch averaged 4 minutes per review (stash, checkout, install deps, run, switch back, pop stash). Worktrees averaged 40 seconds. With 4 reviews a day, that’s ~13 minutes saved daily. Not life-changing alone, but it compounds — and the cognitive cost of interrupted focus is way higher than the clock time.
2. Hotfixes While Mid-Feature
This is the classic case. You’re mid-feature, things are broken in your working tree (intentionally — you’re refactoring), and production needs a patch. With worktrees:
git worktree add ../hotfix main
cd ../hotfix
# fix the bug
git commit -am "fix: null check on user.profile (#1234)"
git push origin main
cd ../myapp
git worktree remove ../hotfix
No stash. No “was I on the right commit?” No dependency reinstall because your lockfile changed between branches. Clean in, clean out.
3. Running Two Versions Side-by-Side
I needed to compare API response times between our v2 and v3 endpoints during a migration. With worktrees, I had both versions running simultaneously on different ports:
git worktree add ../api-v2 release/v2
cd ../api-v2 && PORT=3001 npm start &
cd ../myapp && PORT=3002 npm start &
# Now hit both with curl or your HTTP client
curl -w "%{time_total}\n" http://localhost:3001/api/users
curl -w "%{time_total}\n" http://localhost:3002/api/users
Try doing that with stash. You can’t.
The Commands You Actually Need
The full git worktree subcommand has plenty of options, but in practice I use four:
# Create a worktree for an existing branch
git worktree add ../path branch-name
# Create a worktree with a new branch (like checkout -b)
git worktree add -b new-branch ../path starting-point
# List all worktrees
git worktree list
# Remove a worktree (cleans up the directory and git references)
git worktree remove ../path
That’s it. Four commands cover 95% of usage. There’s also git worktree prune for cleaning up stale references if you manually delete a worktree directory instead of using remove, but you shouldn’t need it often.
Gotchas I Hit (So You Don’t Have To)
Node modules and build artifacts. Each worktree is a separate directory, so you need a separate node_modules in each. For a big project, that first npm install in a new worktree takes time. I mitigate this by keeping one long-lived review worktree rather than creating/destroying them constantly.
IDE confusion. VS Code handles worktrees well — just open the worktree directory as a separate window. JetBrains IDEs can get confused if you open the same project root with different worktrees. The fix: open the specific worktree directory, not the parent.
Submodules. If your repo uses submodules, you need to run git submodule update --init in each new worktree. Worktrees don’t automatically initialize submodules. Annoying, but a one-liner fix.
Branch locking. Remember: one branch per worktree. If you try to check out a branch that’s already active in another worktree, Git blocks you with:
fatal: 'main' is already checked out at '/home/user/code/myapp-hotfix'
This is intentional and correct. If you need to work on the same branch from two directories, you have a workflow problem, not a Git problem.
My Worktree Setup
I keep my projects structured like this:
~/code/
├── myapp/ # main development (feature branches)
├── myapp-review/ # persistent review worktree (long-lived)
└── myapp-hotfix/ # created on-demand, deleted after use
I added a shell alias to speed up the common case:
# ~/.zshrc or ~/.bashrc
hotfix() {
local branch="${1:-main}"
local dir="../$(basename $(pwd))-hotfix"
git worktree add "$dir" "$branch" && cd "$dir"
}
# Usage: just type 'hotfix' or 'hotfix release/v3'
And a cleanup alias:
worktree-clean() {
git worktree list --porcelain | grep "^worktree" | awk '{print $2}' | while read wt; do
if [ "$wt" != "$(git rev-parse --show-toplevel)" ]; then
echo "Remove $wt? (y/n)"
read answer
[ "$answer" = "y" ] && git worktree remove "$wt"
fi
done
}
When Worktrees Aren’t the Answer
I’m not going to pretend worktrees solve everything. They don’t make sense when:
- You’re working solo on a single branch. No context switching means no need for worktrees.
- Your project has a 10-minute build step. Each worktree needs its own build, so the overhead might not be worth it for infrequent switches.
- You need the same branch in two places. Worktrees explicitly prevent this. Clone the repo instead.
For everything else — code reviews, hotfixes, comparing versions, running multiple branches in parallel — worktrees are the right tool. I’ve been using them daily for about a year now, and git stash usage in my shell history dropped from ~15 times/week to maybe once.
Level Up Your Git Setup
If you’re spending real time on Git workflows, it’s worth investing in a proper reference. Pro Git by Scott Chacon covers worktrees alongside the internals that make them possible — understanding Git’s object model makes everything click. (Full disclosure: affiliate link.)
For the terminal setup that makes all this fast, a solid mechanical keyboard actually matters when you’re typing Git commands dozens of times a day. I’ve been using a Keychron Q1 — the tactile feedback on those Brown switches makes a difference over an 8-hour session. (Affiliate link.)
And if you want more developer workflow content, I write about tools and techniques regularly here on orthogonal.info. Check out my regex tester build or the EXIF parser deep dive for more hands-on dev tool content.
Join Alpha Signal on Telegram for free market intelligence and developer insights.
📧 Get weekly insights on security, trading, and tech. No spam, unsubscribe anytime.

Leave a Reply