Master Git Worktrees: Seamlessly Manage Multiple Branches Without Cloning
This guide explains why traditional stash or multiple‑repo cloning fall short, introduces Git's worktree feature, and walks through adding, listing, removing, and pruning worktrees so developers can handle hotfixes and features in parallel without disrupting their main workflow.
Background
As programmers we often have to switch between feature development and urgent hotfixes, and the usual solutions are either committing unfinished work or using
git stash | git stash pop. The stash approach has limitations in several scenarios.
Scenarios We Face
Running long tests on the main branch; switching to a hotfix or feature interrupts testing.
Large projects make frequent index switching costly.
Older releases have different settings, causing IDE re‑structure overhead.
Branch switching requires resetting environment variables (dev/qa/prod).
Need to switch to a colleague’s code to reproduce bugs.
Why Not Clone Multiple Repos?
State synchronization between repos is difficult; cherry‑picking across repos is cumbersome.
Each repo repeats the full
.githistory, consuming large disk space.
Managing many repositories for a single project is error‑prone.
git‑worktree
Git has supported worktrees since 2015, but many developers are unaware of it. It allows a single repository to have multiple working directories that can be on different branches without interfering with each other.
Maintain one repo while working on several branches simultaneously, without interference.
Common commands (most frequently used):
<code>git worktree add [-f] [--detach] [--checkout] [--lock] [-b <new-branch>] <path> [<commit-ish>]
git worktree list [--porcelain]
git worktree remove [-f] <worktree>
git worktree prune [-n] [-v] [--expire <expire>]
</code>Two Git Knowledge Points You Might Miss
When you run
git initor
git clone, the repository initially has only one worktree, called the
main worktree.
In a working directory Git either has a
.gitdirectory or a
.gitfile that points to the actual
.gitfolder.
git worktree add
Assume the project root is
amend-crash-demo:
<code>.
└── amend-crash-demo
1 directory
</code>Run the following commands:
<code>cd amend-crash-demo
git worktree add ../feature/feature2
</code>Output:
<code>➜ amend-crash-demo git:(main) git worktree add ../feature/feature2
Preparing worktree (new branch 'feature2')
HEAD is now at 82b8711 add main file
</code>Directory structure becomes:
<code>.
├── amend-crash-demo
└── feature
└── feature2
3 directories
</code>The command creates a new branch
feature2at the current HEAD and places its working tree at the specified path.
Inside the new worktree there is a
.gitfile that points back to the main repository:
<code>gitdir: /Users/rgyb/Documents/projects/amend-crash-demo/.git/worktrees/feature2
</code>Now you can work on
feature2(add/commit/pull/push) without affecting the main worktree.
If your branch naming convention includes a slash (e.g.,
feature/JIRAID-Title), the slash would be interpreted as a directory separator. Use the
-boption to create the branch while keeping the desired name:
<code>git worktree add -b "hotfix/JIRA234-fix-naming" ../hotfix/JIRA234-fix-naming
</code>Resulting directory layout:
<code>.
├── amend-crash-demo
├── feature
│ └── feature2
└── hotfix
└── hotfix
└── JIRA234-fix-naming
6 directories
</code>After adding the
-bflag, the structure is tidy:
<code>.
├── amend-crash-demo
├── feature
│ └── feature2
└── hotfix
├── JIRA234-fix-naming
└── hotfix
└── JIRA234-fix-naming
7 directories
</code>git worktree list
From any worktree you can list all existing worktrees:
<code>git worktree list
</code>Example output shows the main worktree and the additional ones:
<code>/Users/rgyb/Documents/projects/amend-crash-demo 82b8711 [main]
/Users/rgyb/Documents/projects/chore/chore 8782898 (detached HEAD)
/Users/rgyb/Documents/projects/feature/feature2 82b8711 [feature2]
/Users/rgyb/Documents/projects/hotfix/hotfix/JIRA234-fix-naming 82b8711 [JIRA234-fix-naming]
/Users/rgyb/Documents/projects/hotfix/JIRA234-fix-naming 82b8711 [hotfix/JIRA234-fix-naming]
</code>git worktree remove
Remove a worktree by name:
<code>git worktree remove hotfix/hotfix/JIRA234-fix-naming
</code>If the worktree has uncommitted changes, force removal with
-f:
<code>git worktree remove -f hotfix/JIRA234-fix-naming
</code>git worktree prune
Use
git worktree pruneas a cleanup fallback to delete stale administrative files left after worktree removal.
Summary
The complete workflow consists of four commands:
<code>git worktree add
git worktree list
git worktree remove
git worktree prune
</code>Using a single repository with multiple worktrees avoids the drawbacks of cloning many repos and keeps the workflow smooth.
My practice: I keep all feature worktrees under a feature directory and all hotfix worktrees under a hotfix directory to maintain a tidy disk layout.
Soul Questions
Can the main worktree be deleted? Why?
Do you understand how the
.git/worktreesdirectory changes when repeatedly creating and deleting worktrees?
macrozheng
Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.