Git Worktrees For Managing Multiple Feature Branches Simultaneously
Git Worktrees: Manage Multiple Feature Branches Without the Switching Nightmare
Stop stashing. Stop context-switching. Git worktrees let you check out multiple branches simultaneously in separate directories — each with its own working tree, no conflicts.
The Core Concept
One repository, multiple working directories. Each worktree shares the same .git folder but has its own branch and working state.
# Your main repo lives here
~/projects/my-app/ # main branch
# Worktrees live alongside it
~/projects/my-app-feature-auth/ # feature/auth branch
~/projects/my-app-hotfix-prod/ # hotfix/prod-crash branch
Essential Commands
# Create a new worktree (branch must not exist yet)
git worktree add ../my-app-feature-auth -b feature/auth
# Create a worktree from an existing branch
git worktree add ../my-app-hotfix hotfix/prod-crash
# Create a worktree in detached HEAD state
git worktree add --detach ../my-app-review abc1234
# List all worktrees
git worktree list
# Remove a worktree (after you're done)
git worktree remove ../my-app-feature-auth
# Force remove if worktree has uncommitted changes
git worktree remove --force ../my-app-feature-auth
# Prune stale worktree references
git worktree prune
My Preferred Directory Layout
Keep worktrees organized by putting them in a sibling directory pattern:
~/projects/
├── my-app/ # main / primary worktree
├── my-app--auth/ # feature/auth
├── my-app--payments/ # feature/payments
└── my-app--hotfix/ # hotfix/critical-bug
The double-dash naming convention makes it obvious these are worktrees of the same repo at a glance.
Real Workflow Example
# You're deep in feature work on main worktree
# Prod alert fires — need a hotfix NOW
# Step 1: Spin up a hotfix worktree (don't touch your current work)
git worktree add ../my-app--hotfix -b hotfix/null-pointer-exception
# Step 2: Jump over, fix it, ship it
cd ../my-app--hotfix
# ... make your fix ...
git commit -am "fix: null pointer in payment processor"
git push origin hotfix/null-pointer-exception
# Step 3: Back to your feature — zero disruption
cd ../my-app
# Your changes are exactly where you left them
Worktree List Output
$ git worktree list
/home/user/projects/my-app abc1234 [main]
/home/user/projects/my-app--auth def5678 [feature/auth]
/home/user/projects/my-app--hotfix ghi9012 [hotfix/null-pointer-exception]
Quick Reference Card
| Task | Command |
|---|---|
| New worktree + new branch | git worktree add ../path -b branch-name |
| New worktree + existing branch | git worktree add ../path branch-name |
| List all worktrees | git worktree list |
| Remove worktree | git worktree remove ../path |
| Force remove | git worktree remove --force ../path |
| Clean stale refs | git worktree prune |
| Move a worktree | git worktree move ../old ../new |
| Lock a worktree | git worktree lock ../path |
Gotchas to Know Before You Start
You can't check out the same branch in two worktrees. Git will refuse. One branch = one worktree at a time.
# This will FAIL if feature/auth is already checked out
git worktree add ../another-auth feature/auth
# fatal: 'feature/auth' is already checked out at '...'
.git is a file, not a directory, in linked worktrees.
$ cat ~/projects/my-app--auth/.git
gitdir: /home/user/projects/my-app/.git/worktrees/my-app--auth
Don't be surprised — this is normal and expected.
Node modules, build artifacts, and .env files don't transfer. Each worktree is a fresh working directory. You'll need to run npm install (or equivalent) in each new worktree.
# Quick setup script after creating a worktree
git worktree add ../my-app--feature-x -b feature/x && \
cd ../my-app--feature-x && \
cp ../my-app/.env . && \
npm install
Bash/Zsh Aliases Worth Adding
# ~/.bashrc or ~/.zshrc
# Create worktree with automatic setup
gwt() {
local branch=$1
local path="../$(basename $(git rev-parse --show-toplevel))--${branch//\//-}"
git worktree add "$path" -b "$branch"
cd "$path"
}
# List worktrees (short)
alias gwtl='git worktree list'
# Remove current worktree (from inside it)
gwtrm() {
local current=$(pwd)
cd ..
git worktree remove "$current"
}
When to Use Worktrees vs. Stash vs. Branches
| Situation | Use |
|---|---|
| Quick context switch, same day | git stash |
| Parallel long-running features | Worktrees |
| Code review while mid-feature | Worktrees |
| Hotfix while feature is in progress | Worktrees |
| Running two versions simultaneously | Worktrees |
The Bottom Line
If you're still stashing work every time a Slack message says "can you review this PR real quick?" — you're leaving productivity on the table. Worktrees are underused and genuinely change how you work across multiple features.
Set one up in the next five minutes. You won't go back.
Was this article helpful?
Senior Kubernetes Architect
10+ years orchestrating containers in production. Battle-tested opinions on everything from pod scheduling to service mesh. I've seen clusters burn and helped rebuild them better.
Related Articles
Git Push Rejected: How To Fix "Updates Were Rejected Because The Remote Contains Work You Do Not Have"
You've seen this error. Everyone has. You try to push your changes and Git stops you cold: Here's your fast-track reference to diagnose and fix it. --- The...
Fix Git 'fatal: refusing to merge unrelated histories'
Resolve the Git error 'refusing to merge unrelated histories' when pulling or merging branches that share no common ancestor.
Git Bisect: Find the Exact Commit That Broke Production
Use git bisect to binary-search through commit history and pinpoint the exact change that introduced a bug — manually or fully automated.
Git Commands: Cheat Sheet
Git commands cheat sheet for DevOps engineers — branching, rebasing, stashing, bisecting, cherry-picking, and recovery workflows with examples.
Istio AuthorizationPolicy For Namespace-Level RBAC In Multi-Tenant Kubernetes Clusters
Multi-tenancy in Kubernetes is one of those topics that sounds straightforward until you're three months into a production incident because Team A's micros...
Pre-Commit Hooks Framework for Automated Code Quality
Set up the pre-commit hooks framework to automatically enforce linting, formatting, and security checks before every Git commit.