Git Worktrees: Work on Multiple Branches Simultaneously Without Stashing or Cloning
Git worktrees let you work on multiple branches at once without stashing or cloning.
20+ years shipping production infrastructure and CI/CD at scale. Everything here is grounded in real deployments.
- ✓Basic Git commands (branch, checkout, commit, push)
- ✓Understanding of Git branches and remotes
- ✓Comfortable with command line
Use git worktree add to create a new working directory for a branch. Work in it like a separate clone, but commits are shared. Remove with git worktree remove . Never delete worktree directories manually.
Imagine you have a single house (the repository) with multiple rooms (branches). Normally you can only be in one room at a time. Worktrees are like adding separate doors to each room so you can walk into any room directly without leaving the house. Each room has its own furniture (files), but the foundation (Git objects) is shared.
You're mid-sprint, three features in progress, and a production bug hits. You need to hotfix main, but you've got uncommitted changes in your feature branch. The classic move: stash, checkout main, fix, commit, checkout back, pop stash. That's friction. And friction in a fire costs time. Git worktrees eliminate that friction entirely. They let you check out multiple branches simultaneously into separate directories, each with its own working state, all sharing the same repository. No stashing, no cloning, no context switches. After this article, you'll be able to set up worktrees for parallel feature development, hotfixes, and code reviews without ever touching git stash again.
Why You Need Worktrees: The Stash Tax
Every time you stash, you pay a mental tax: 'What was I doing? Will I remember to pop? Did I stash everything?' In a hotfix scenario, that tax compounds with adrenaline. Worktrees remove the tax entirely. You keep your feature branch's working state intact in one directory, and you work on the hotfix in another. No stashing, no commit-amending, no 'oh crap I forgot to stash that one file'. The problem worktrees solve is simple: Git's single-working-tree model forces serial context switching. Worktrees give you parallel contexts. They're not new — they've been stable since Git 2.5 (2015). But most devs still don't use them because the workflow isn't obvious. Let's fix that.
git worktree add -b <new-branch> <path> <start-point> to create a new branch and worktree in one command. Saves a step.Production Pattern: Parallel Feature Branches
In a microservices monorepo, you often need to work on two features that touch different services. With worktrees, you can have both checked out in separate directories, each with its own IDE window. No more switching branches and rebuilding the entire project. The pattern: create a worktree per branch, work independently, push from each. The key insight: worktrees share the object store, so you don't duplicate the .git directory. That means git fetch in one worktree updates refs for all. But beware: if you fetch a new branch, you need to create a worktree for it explicitly — it won't appear automatically.
rm -rf, Git still thinks it exists. You'll get errors like fatal: 'path' is not a valid path when running git worktree list. Fix: run git worktree prune to clean up stale worktree references.Hotfix Workflow: No Stash, No Panic
Production is down. You're on a feature branch with uncommitted changes. The old way: git stash, git checkout main, fix, commit, git checkout feature, git stash pop. If stash pop conflicts, you're in merge-hell while the site burns. With worktrees: git worktree add ../hotfix main, fix in ../hotfix, commit, push, deploy. Then git worktree remove ../hotfix. Your feature branch is untouched. No stash, no conflict. This is the single most valuable use case for worktrees. I've seen teams cut deployment time from 5 minutes to 30 seconds on hotfixes using this pattern.
Code Review Without Context Switch
You're deep in a feature, and a colleague asks for a code review. The old way: git stash, checkout their branch, look at code, checkout back, pop stash. Or use the GitHub UI. But sometimes you need to run the code locally. Worktrees let you check out their branch in a separate directory, run it, review, and delete — all without touching your current work. The pattern: git worktree add ../review <pr-branch>. Review in ../review. Then git worktree remove ../review. Your feature branch is undisturbed.
git worktree add --detach ../review FETCH_HEAD to check out a detached HEAD at the PR's latest commit without creating a local branch. Saves cleanup.Worktrees in CI: Parallel Testing Without Cloning
In CI, you often need to test multiple branches or commits in parallel. Cloning the repo N times is slow and wastes disk. Worktrees let you check out multiple branches from a single clone into separate directories, each with its own working tree. This is especially useful for monorepos where you want to run tests for each changed service in parallel. The trick: clone once, then create worktrees for each branch you need to test. Each worktree can be used by a separate CI job. Just be careful with concurrent writes to the shared object store — Git's object store is append-only, so it's safe, but avoid concurrent git gc.
git gc in one worktree while another worktree is actively writing can cause corruption. Git 2.6+ has guards, but avoid concurrent GC. In CI, run GC only after all worktrees are removed.When Worktrees Break: The Gotchas
Worktrees aren't magic. They have sharp edges. First: you cannot have the same branch checked out in two worktrees. Git will refuse: fatal: 'branch' is already checked out at 'path'. If you need to work on the same branch from two places, you're better off with a clone. Second: worktrees create refs under refs/worktrees/. If you manually delete a worktree directory, those refs linger and can cause confusion. Always use git worktree remove. Third: some Git GUI tools don't understand worktrees. They'll show the main repo's state, not the worktree's. If you rely on a GUI, test first. Fourth: worktrees are local. They don't push or fetch automatically. You must push from each worktree individually. Fifth: moving or renaming a worktree directory breaks the association. Don't do it.
fatal: 'refs/heads/branch' is already checked out at 'path', you tried to check out a branch that's already in a worktree. Use git worktree list to find where, then either work there or remove that worktree first.Worktrees vs. Clones: When to Use Which
Worktrees share the object store; clones don't. That means worktrees are lighter (no duplicate objects) but also more coupled. Use worktrees when: you need to work on multiple branches of the same repo, you want to avoid stash overhead, or you're in a monorepo with many services. Use clones when: you need to work on the same branch simultaneously (e.g., pair programming), you want complete isolation (different remotes, different configs), or you're on a filesystem that doesn't support hard links (worktrees use symlinks internally). Also, clones are easier to reason about for junior devs — worktrees have a learning curve. My rule: if you're the only one working on the branches, use worktrees. If multiple people need the same branch, clone.
git clone --reference <path-to-existing-clone> <url> to create a clone that shares objects via alternates. This gives you isolation with less disk usage, but it's more fragile than worktrees.The Deleted Worktree That Lost Unpushed Commits
rm -rf ../feature-x then git worktree prune. Later, commits from that worktree were gone.refs/worktrees/<name>/HEAD). If the worktree branch had unpushed commits and no other ref pointed to them, git worktree prune cleaned up the ref, making commits unreachable and eventually garbage-collected.git worktree remove <path> (safe, moves branch ref) or ensure branch has a remote tracking branch before manual deletion. Recover lost commits via git reflog on the main repo if not GC'd.- Never delete a worktree directory with
rm -rf. - Always use
git worktree removeto safely detach the branch.
fatal: 'refs/heads/branch' is already checked out at 'path' when trying to checkout a branchgit worktree list to see where the branch is checked out. 2. Either work in that worktree, or remove it with git worktree remove <path>. 3. If the worktree directory no longer exists, run git worktree prune to clean up stale references.git worktree list shows broken pathgit worktree prune to remove stale worktree entries. 2. If you need to recover commits from that worktree, check git reflog in the main repo. 3. If commits are unreachable, use git fsck --lost-found to find dangling objects.git worktree add fails with 'fatal: could not create worktree dir' due to permissionsgit worktree listgit worktree remove <path>| File | Command / Code | Purpose |
|---|---|---|
| worktree-basics.sh | mkdir demo && cd demo | Why You Need Worktrees |
| parallel-features.sh | cd ~/monorepo | Production Pattern |
| hotfix-workflow.sh | cd ~/project | Hotfix Workflow |
| code-review.sh | cd ~/project | Code Review Without Context Switch |
| ci-worktrees.sh | cd $REPO_DIR | Worktrees in CI |
| gotchas.sh | cd ~/project | When Worktrees Break |
| comparison.sh | cd ~/repo | Worktrees vs. Clones |
Key takeaways
git worktree remove to delete worktreesrm -rf. Manual deletion can lose commits.Interview Questions on This Topic
How does Git prevent the same branch from being checked out in two worktrees? What's the internal mechanism?
refs/worktrees/<id>/HEAD that records which branch is checked out. When you try to checkout a branch, Git checks all worktree HEAD refs for a match. If found, it rejects the operation. This prevents conflicting index and working tree states.Frequently Asked Questions
20+ years shipping production infrastructure and CI/CD at scale. Everything here is grounded in real deployments.
That's Git. Mark it forged?
3 min read · try the examples if you haven't