The scenario every developer knows: you're deep in a feature, 15 files modified, half-working tests, and the production alert hits. You need to fix a bug on main, now.
The standard advice: git stash. Switch branches. Fix the bug. Come back. Unstash. Pray nothing conflicts.
There's a better way, and it's been in Git since 2015.
Meet git worktree
A Git worktree lets you check out multiple branches simultaneously, each in its own directory, sharing the same underlying .git repository. No stashing, no context switching, no rebuilding node_modules.
# You're in ~/work/app on feature/profile, deep in dirty changes
$ pwd
/Users/you/work/app
$ git status
On branch feature/profile
Changes not staged for commit:
modified: src/profile.js
modified: src/avatar.js
(10 more files...)
# Production alert — open a worktree for the hotfix
$ git worktree add ../app-hotfix -b hotfix/payment-500 main
Preparing worktree (new branch 'hotfix/payment-500')
HEAD is now at a3f1d22 feat(profile): add avatar
# Switch terminal to the new directory
$ cd ../app-hotfix
$ git status
On branch hotfix/payment-500
nothing to commit, working tree clean
That's it. You now have two directories:
-
app/— your feature work, untouched, 15 dirty files exactly where you left them -
app-hotfix/— a clean checkout ofmainin its own folder
Fix the bug in app-hotfix/, commit, push, open the PR. When the hotfix merges, remove the worktree:
$ git worktree remove ../app-hotfix
The branch lives on (on the remote). The extra directory is gone.
Why this beats stash
Stash works for small, short interruptions. But it has real problems:
Stash assumes you can only run one environment at a time. With a worktree, you have two node_modules/, two running npm run dev processes, two build caches. No conflict, no rebuild.
Stash is fragile. git stash pop with a conflict can leave your working tree in a mess. A worktree is just a checkout — nothing special can go wrong.
Stash is invisible. Three days later, did you git stash pop? Did you have two stashes? Which one was which? Worktrees are directories — you can see them, ls them, run them side by side.
The other big use case: reviewing PRs
If you review a lot of PRs, you know the pain: to test someone else's branch locally you have to stash your work, check out their branch, run it, switch back, re-stash, re-rebuild.
With worktrees:
$ git worktree add ../app-review origin/coworker-branch
$ cd ../app-review
$ npm install && npm run dev
# Poke around, test, review, come back to your own work untouched
Useful commands
# List all active worktrees
$ git worktree list
/Users/you/work/app a3f1d22 [feature/profile]
/Users/you/work/app-hotfix 7e4b9c1 [hotfix/payment-500]
# Add a worktree tracking an existing branch
$ git worktree add ../app-qa qa-branch
# Remove a worktree (the branch stays)
$ git worktree remove ../app-qa
# If you deleted the directory manually, clean up the reference
$ git worktree prune
When NOT to use worktree
Stash is still the right tool when:
- The interruption takes 5 minutes and you don't need to run anything
- You're on a disk-constrained machine (each worktree is a full checkout)
- Your build system assumes a single working directory (some old monorepo tooling has trouble)
The one gotcha
You can't have the same branch checked out in two worktrees at once. If you try, Git refuses. This is a feature, not a bug — it prevents you from committing to the same branch from two places and creating a mess. If you need the same branch twice (to compare states, for example), check out a detached HEAD in the second worktree instead:
$ git worktree add --detach ../app-compare main
Make it a habit
I have three muscle memories now:
- 5-minute interruption, nothing to run → stash
- Longer interruption, different branch, needs full env → worktree
- Reviewing a PR locally → always worktree
After a year of doing this, I almost never stash anymore. And I never panic when production pages me while I'm mid-feature.
This post is adapted from Git in Depth: From Solo Developer to Engineering Teams, a 658-page book covering Git the way it's actually used in real engineering teams — from day-to-day commands to CI/CD, branching strategies, methodology alignment, and Git at organizational scale.

Top comments (2)
I enjoyed reading this. Nice work.
Thank you!!! :-)