You are three hours into a feature. Half the files are modified, the tests are red on purpose, and you have a mental map of exactly what comes next. Then someone pings you: production is broken, can you take a look.
So you do the usual dance. git stash, git checkout main, git pull, make a branch, fix the bug, push it, open the PR. Then git checkout back to your feature, git stash pop, and hope nothing conflicts. Your dev server restarted twice, your editor reloaded half its tabs, and your mental map is gone.
Git has had a better answer to this since 2015. It is called a worktree, and most developers have never used it.
What a worktree actually is
A normal clone has one working directory: one set of checked out files, one current branch. A worktree lets a single repository have several working directories at the same time, each on its own branch.
They all share the same .git object store. You are not cloning the repository again. Commits, branches, remotes, and fetched objects are shared, so a commit made in one worktree is immediately visible from the others. What each worktree has for itself is its own checked out files, its own index (staging area), and its own HEAD.
In practice that means your feature branch stays exactly as you left it, uncommitted changes and all, in one folder, while you fix production in another.
The hotfix, done with a worktree
From inside your repository, with your feature work still uncommitted:
git fetch origin
git worktree add -b fix/login-timeout ../myapp-hotfix origin/main
That creates a new directory, ../myapp-hotfix, with a fresh branch called fix/login-timeout started from the latest origin/main. Your current directory is untouched.
cd ../myapp-hotfix
# fix the bug, run the tests
git commit -am "Fix login timeout on slow sessions"
git push -u origin fix/login-timeout
Open the PR, then go back to your feature folder. Nothing was stashed, nothing restarted, your editor never noticed. When the hotfix is merged, clean up:
git worktree remove ../myapp-hotfix
The commands you will actually use
There are only a handful worth remembering:
# new worktree on a new branch, based on a start point
git worktree add -b <branch> <path> <start-point>
# new worktree on an existing branch
git worktree add <path> <branch>
# see every worktree and what it has checked out
git worktree list
# delete a worktree when you are done
git worktree remove <path>
# clean up records for worktree folders you deleted by hand
git worktree prune
git worktree list is the one to run when you lose track:
/home/amit/code/myapp a1b2c3d [feature/billing-export]
/home/amit/code/myapp-hotfix e4f5a6b [fix/login-timeout]
/home/amit/code/myapp-review 9c8d7e6 [pr/482]
Where worktrees pay off beyond hotfixes
Reviewing a pull request properly. Instead of reading a diff in the browser, check the branch out into its own worktree, run it, and click around. Your own work stays where it is. When you are done, remove the folder.
Running something slow while you keep working. Start a long test suite, a load test, or a production build in one worktree and keep coding in another. Before worktrees, that meant either waiting or risking the run picking up files you were still editing.
Comparing behavior side by side. Run the old version and the new version of a service at the same time on different ports, against the same inputs. That beats switching branches back and forth and trying to remember what the old output looked like.
Parallel AI coding sessions. If you use coding agents, giving each one its own worktree keeps them from editing the same files at the same time. Each agent gets an isolated checkout of its own branch, and you review and merge their work like any other branch.
The gotchas worth knowing up front
One branch, one worktree. Git will not let you check out the same branch in two worktrees at once, and it tells you so with an error naming the folder that already has it. This is a safety feature. Two working directories moving the same branch would trample each other. If you need a second copy, create a new branch from it.
Ignored files do not come along. A new worktree has your tracked files and nothing else. No node_modules, no .env, no local build output. Plan on running your install step in each new worktree, and copy any local config you need. With npm, pnpm, or similar, the package manager cache makes that second install much faster than the first.
Keep worktrees outside the main folder. If you create a worktree inside your repository's directory, it shows up as untracked files in your main checkout. Sibling folders like ../myapp-hotfix avoid that entirely. Some people keep a dedicated parent folder per project, with one subfolder per worktree.
Delete with git worktree remove, not rm -rf. Git keeps a small record of every worktree. If you delete the folder by hand, that record goes stale, and the branch can still look checked out. git worktree prune fixes it, but remove avoids the problem in the first place. It also refuses to delete a worktree with uncommitted changes unless you pass --force, which has saved more than one afternoon of work.
Submodules are still rough. If your repository uses submodules, worktree support works but is not as smooth as the rest of Git. Test it on your project before building a workflow around it.
Worktree or a second clone?
The obvious alternative is to clone the repository a second time. It works, but it costs more than it looks.
A second clone downloads and stores the whole history again. On a large repository that is gigabytes of disk and a slow first clone. The two copies also know nothing about each other. A branch you create in one does not exist in the other until you push it and fetch it. Every git fetch has to run twice. It is easy to end up committing to a stale copy that is days behind.
Worktrees avoid all of that because there is only one repository. Fetch once and every worktree sees the new commits. Create a branch in one and it is immediately available to check out in another. Adding a worktree takes seconds, since Git only has to write the files for that branch.
The one case for a real second clone is when you want two completely independent setups, for example different remotes or different Git config. For everyday branch juggling, a worktree is the lighter tool.
A layout that stays tidy
After a few weeks, worktrees can scatter across your disk. A simple convention keeps them under control:
~/code/myapp/ main checkout, your long running work
~/code/myapp-hotfix/ short lived, removed after merge
~/code/myapp-review/ reused for whatever PR you are reviewing
Keep one review worktree around and point it at whichever branch you are reviewing with git switch, instead of creating and deleting a folder every time. Create hotfix worktrees on demand and remove them as soon as the fix is merged. Run git worktree list once a week and remove anything you no longer need.
Takeaway
Stashing was always a workaround for having one working directory. Worktrees remove the limitation instead. Next time an urgent fix interrupts real work, run git worktree add, fix it in a separate folder, and come back to your feature exactly as you left it.
Top comments (0)