If you’ve ever found yourself stashing changes again just to switch branches, or cloning the same repository into three different directories just to keep a few branches open, you’re not alone. That’s a very common workflow—and a very inefficient one.
git worktree offers a better way.
Instead of juggling multiple clones, git worktree lets you create additional working directories (“worktrees”) that all share the same underlying .git data. Each worktree can be checked out to a different branch, with its own filesystem view of the code, but they all stay in sync with a single repository.
For operations teams, developers, and folks doing code reviews or production hotfixes, this can be a game-changer.
What Is a Git Worktree, Really?
A worktree is just another directory on disk that’s attached to an existing Git repo, with its own:
- Checked-out branch
- Working copy of the files
- Staging area (index)
Under the hood, all the Git history and objects still live in one shared .git store. That means:
- No wasted disk space from duplicated clones
- No repeated
git clone/git fetchcycles - Easy cleanup when you’re done experimenting
You can think of it as “additional checkouts of the same repo,” each in its own folder.
Basic Workflow: Your First Worktree
Let’s assume you have a repo already:
|
1 2 |
cd ~/projects/my-app |
You’re currently on main, but you want to work on a feature in parallel without constantly stashing or committing half-baked changes.
Create a new worktree
|
1 2 |
git worktree add ../my-app-feature feature/login-form |
This does two things:
- Creates a new directory
../my-app-feature - Checks out the branch
feature/login-formin that directory
If the branch doesn’t exist yet, you can create it on the fly:
|
1 2 |
git worktree add -b feature/login-form ../my-app-feature origin/main |
-b feature/login-form— creates a new branch../my-app-feature— filesystem path for the new worktreeorigin/main— starting point for the new branch
Now you have:
~/projects/my-app→ still onmain~/projects/my-app-feature→ onfeature/login-form
You can work in both directories independently, just like separate clones, but they share the same repo.
Listing and Removing Worktrees
As you add more worktrees, it’s easy to forget what’s attached where.
List all worktrees
|
1 2 |
git worktree list |
You’ll see output like:
|
1 2 3 |
/home/user/projects/my-app 123abc4 [main] /home/user/projects/my-app-feature 789def0 [feature/login-form] |
Remove a finished worktree
Once a feature is merged and you’re done with that extra checkout:
|
1 2 |
git worktree remove ../my-app-feature |
This:
- Removes the directory
- Detaches the worktree from the repo (the branch and commits remain in Git!)
If the directory isn’t empty or you’ve got uncommitted work, Git may refuse to remove it; clean up or commit first, or use --force if you really mean it:
|
1 2 |
git worktree remove --force ../my-app-feature |
Cleaning up stale worktrees
Sometimes directories get deleted manually or paths become invalid. You can prune references:
|
1 2 |
git worktree prune |
This cleans up any worktrees Git thinks are gone.
Real-World Use Cases
Let’s look at where git worktree shines in day-to-day work at a place like Reliable Penguin.
1. Reviewing Pull Requests Locally
You’re on main but want to review a PR branch in a clean environment.
|
1 2 3 4 5 6 7 |
cd ~/repos/client-site git fetch origin # Create a worktree for the PR branch git worktree add ../client-site-pr-123 pr/123-user-login cd ../client-site-pr-123 |
Now you can:
- Run tests
- Check logs
- Spin up the app or container stack
All without touching your primary working copy in ~/repos/client-site.
Once the review is done:
|
1 2 3 |
cd ~/repos/client-site git worktree remove ../client-site-pr-123 |
2. Hotfixing Production While a Big Feature Is In Progress
Classic situation:
- Your main working directory is halfway through a large refactor
- A production bug appears that needs a quick hotfix on
releaseorproductionbranch
Instead of stashing or panic-committing WIP changes:
|
1 2 3 4 5 6 7 8 9 10 11 12 |
cd ~/repos/api-service git fetch origin # New worktree on production branch git worktree add ../api-service-hotfix origin/production cd ../api-service-hotfix # Fix the bug # ... git commit -am "Fix timeout on billing webhook" git push origin HEAD:production |
After deploy and verification:
|
1 2 3 |
cd ~/repos/api-service git worktree remove ../api-service-hotfix |
Your main directory with the refactor remains untouched throughout.
3. Long-Lived Feature Branches
Some features take weeks or months. Keeping them in a dedicated worktree keeps your primary repo clean and ready for small tasks, experiments, and quick fixes.
|
1 2 3 |
cd ~/repos/ops-tools git worktree add -b feature/config-dashboard ../ops-tools-dashboard origin/main |
You can:
- Keep
../ops-tools-dashboardopen for the long-running project - Use
~/repos/ops-toolsfor small fixes, minor releases, or spike branches
Using Worktrees with Bare Repositories
If you keep a bare repo (for example in /srv/git/my-repo.git), git worktree is a very natural fit.
|
1 2 3 4 |
cd /srv/git/my-repo.git # bare repo git worktree add /srv/work/my-repo-main main git worktree add /srv/work/my-repo-staging staging |
Now you can use:
/srv/work/my-repo-mainfor development/srv/work/my-repo-stagingfor staging deployments
All tied back to the same bare repo.
This pattern works well for:
- Deployment servers
- CI/CD runners
- Shared build hosts
Things to Watch Out For
git worktree is powerful, but there are a few gotchas:
- One branch, one worktree
A branch can only be checked out in one worktree at a time. If you try to reuse it, Git will complain.- Workaround: create temporary branches (e.g.
pr/123-review) when you need a second view.
- Workaround: create temporary branches (e.g.
- Don’t manually move worktree directories
Moving the directory in the filesystem can confuse Git, because paths are tracked.- If you must move or rename, it’s safer to remove and recreate the worktree.
- Remember to prune
If you delete directories manually, run:
12git worktree prune
to clean up Git’s internal list. - Tooling awareness
Most tools work fine, but some scripts or IDE configs assume a single.gitat the repo root. With worktrees, the.gitentry in each worktree is usually a small file pointing back to the shared store. Modern tools handle this well, but legacy scripts may need an update.
Where git worktree Fits in a DevOps Workflow
For a team like Reliable Penguin, worktrees align nicely with:
- Code review: one worktree per PR when deeper investigation is needed
- Ops & SRE: hotfix worktrees mapped to production branches on bastion or maintenance hosts
- Multi-environment testing: separate worktrees for branches like
main,staging,canary - Context switching: keep “big project” branches isolated from daily quick tasks
By using git worktree instead of multiple clones, you keep:
- Disk usage under control
- Network traffic lower (fewer redundant fetches)
- Your mental model cleaner: “same repo, multiple views”
Summary
If your current Git workflow involves:
- Constant
git stash/git stash pop - Three clones of the same repo in different directories
- Awkward “WIP commit, switch branch, fix, come back, amend” dance
…it’s time to give git worktree a serious look.
With just a few commands:
|
1 2 3 4 5 |
git worktree add <path> <branch> # create git worktree list # inspect git worktree remove <path> # clean up git worktree prune # tidy references |
you can turn one repository into a flexible workspace with clean, focused directories for each piece of work.




