written by Eric J. Ma on 2026-06-15 | tags: git worktree branches workflow productivity hotfix review cloning cleanup tips
In this blog post, I share how git worktrees have become my go-to solution for juggling multiple branches without the hassle of stashing, committing unfinished work, or cloning repos. I explain what worktrees are, how they differ from clones, and why they're perfect for quick reviews, hotfixes, and parallel development. I also cover common pitfalls and cleanup tips. Curious how worktrees can simplify your workflow and keep your projects organized? Read on to find out!
You are deep in a feature branch. Files are half-edited, tests are mid-run, your terminal is a graveyard of useful state. Then a teammate pings you: "can you review this PR?" Or a bug on main needs fixing right now.
Your options feel lousy. You can stash your work and pray you remember the path back. You can commit a half-finished change just to park it. Or you can clone the repo into a second folder and juggle two copies of the history.
There is a fourth option, and it is the one I now reach for every time: git worktree.
Let's strip away the internals for a second. What is a git worktree? A git worktree shows up as a new folder on disk that contains a full copy of your repo's files, checked out on whatever branch you ask for, placed anywhere you want on your computer.
That is the essential experience of git worktrees. You run one command, you cd into a new directory, and you have a clean working tree ready to go. When you are done, you remove it, and the folder disappears.
Here is the basic loop:
# create a new folder ../hotfix with the repo checked out on a new branch "hotfix" git worktree add ../hotfix # go work there cd ../hotfix # ...edit, commit, push... # when you are done, clean it up cd - git worktree remove ../hotfix
git worktree remove deletes the folder and deregisters it from git. That is cleanup. If you ever do it by hand (rm -rf ../hotfix), git leaves a stale registration behind, and git worktree prune sweeps that up.
You can have several worktrees at once. git worktree list shows you every one:
git worktree list
Each entry is a folder on disk, a branch, and a commit. Treat them like separate workspaces that happen to share one brain.
That's a great question! If I just need a second copy of the repo, why run git clone into another folder?
You can, and people do. I have one colleague at work who has the software developer's equivalent of Untitled12.ipynb for multiple repos. But a clone and a worktree are doing fundamentally different things under the hood, and the difference shows up the moment you start working.
A clone is a second, independent repository. git clone copies the entire .git database, history and all, into a brand new repository. The two clones know about each other only as remotes. To share work between them you fetch and push, the same as you would with a colleague's machine. Branches you create in one clone are invisible to the other until you sync them.
A worktree is a second door into the same repository. It adds a working directory, but the history, the commits, the branches, and the tags all live in one shared .git. Make a commit in any worktree and it is instantly visible in all the others, because they are reading from the same underlying git database. There is nothing to sync.
Here is how that plays out side by side:
git clone into a new folder |
git worktree add |
|
|---|---|---|
| Storage | Copies the full .git history again |
Adds only the working files; shares the .git database |
| Branches | Each clone keeps its own copy; must fetch/push to sync | All branches shared instantly across worktrees |
| New branches | Invisible elsewhere until pushed | Visible everywhere immediately |
| Same branch twice | Allowed (independent checkouts) | Blocked; a branch lives in one worktree at a time |
| Network | Needed to sync between copies | Never needed (storage is shared locally) |
That last row is the one I feel most. With clones, every "let me grab that branch" is a fetch. With worktrees, the branch is already there because it was never anywhere else.
Git enforces a single constraint, and it is worth knowing up front: a branch can be checked out in only one worktree at a time.
If you are on feature-x in your main folder, git will refuse to also check out feature-x in a worktree. That refusal protects you from two working directories racing on the same branch's index. If you need a second working tree for similar work, make a new branch for it:
git worktree add -b feature-x-take2 ../take2
This is the tradeoff worktrees make. Clones give you total independence at the cost of duplication and syncing. Worktrees give you zero duplication and zero syncing at the cost of that one-branch-one-worktree rule. This is basically perfect for the "park my work and go look at something else" use case.
Yes, and that is the essence of how git worktrees work.
A normal repository has a .git directory that holds everything: the object database (every commit, tree, and blob), the refs (branches and tags), the configuration, the logs. One repository, one .git.
A linked worktree has a .git file instead of a .git directory. That file is one line long:
gitdir: /Users/you/myproject/.git/worktrees/hotfix
That path points back into the main repository's .git directory, into a small admin folder that holds only the per-worktree state: the worktree's own HEAD, its own index, a few logs. The heavy lifting, the object database and the refs, is shared from the main repo.
You can see it for yourself:
cat ../hotfix/.git # gitdir: /Users/you/myproject/.git/worktrees/hotfix ls /Users/you/myproject/.git/worktrees/ # hotfix
That is the linkage. Every worktree points into the same .git directory, which is why a commit made in one shows up immediately in the rest. They are separate folders on disk with separate working files, but they read and write to one shared repository. One brain, many desks.
A few patterns where worktrees have earned their keep for me. Each one is a plain-English ask you can hand to a coding agent:
main. I git worktree add a throwaway folder, do the review or the fix, push, and remove it. My feature branch never moves. The ask: "Help me review <PR URL> in a new worktree."main, so I can reproduce a bug against both without juggling stashes. The ask: "Check out the v1.2 release tag in a worktree so I can compare it against main."The shared storage means I can have five of these open and still pay only for the working files, five times over, instead of five copies of the entire history.
git worktree remove <path> is the polite way out. It deletes the folder and tells git to forget about it. If the worktree has uncommitted changes, git will refuse unless you pass --force, which is a nice safety net.
If you ever delete a worktree folder by hand, the registration lingers until you run git worktree prune. I treat prune as the "tidy up" command and run it now and then after a week of creating and discarding worktrees.
The next time you are tempted to stash or clone just to look at another branch, try this instead:
git worktree add ../scratchpad cd ../scratchpad
Or alternatively, ask an agent to work in a worktree for you:
"Set up a worktree on a new branch and make the changes there."
Work there. Commit there. When you are done, come back and git worktree remove ../scratchpad. Your main folder stays exactly as you left it, the throwaway folder is gone, and you never duplicated a single commit to get there.
One brain, many desks. That is all a worktree is!
@article{
ericmjl-2026-git-worktrees-for-beginners,
author = {Eric J. Ma},
title = {Git worktrees for beginners},
year = {2026},
month = {06},
day = {15},
howpublished = {\url{https://ericmjl.github.io}},
journal = {Eric J. Ma's Blog},
url = {https://ericmjl.github.io/blog/2026/6/15/git-worktrees-for-beginners},
}
I send out a newsletter with tips and tools for data scientists. Come check it out at Substack.
If you would like to sponsor the coffee that goes into making my posts, please consider GitHub Sponsors!