Git Worktrees
Work on multiple branches simultaneously — no more stashing or context switching
simultaneously
operations
across worktrees
since 2.5
Introduction: The Problem Git Worktrees Solve
Every developer has faced this scenario: you're deep in the middle of implementing a feature on feature/auth-refactor, and suddenly you get a message — "critical bug in production, fix needed ASAP!" You have two options:
- Stash your changes, switch branches, fix the bug, commit, push, then switch back and pop the stash — hoping nothing conflicts
- Clone the entire repository again into a second folder and work in parallel
Both options are tedious. Git Worktrees provide an elegant built-in solution: they allow you to check out multiple branches simultaneously in separate directories, all sharing the same .git repository and history.
🗂️ How Worktrees Work
src/
package.json
Branch: main
src/ (hotfix versions)
Branch: hotfix/critical-fix
src/ (feature versions)
Branch: feature/new-ui
All worktrees share one .git directory. Commits, branches, and history are always in sync.
Basic Commands
Git worktrees are managed with git worktree commands. Here are the essentials:
# Add a new worktree for an existing branch
git worktree add ../my-repo-hotfix hotfix/critical-bug
# Add a worktree AND create a new branch at the same time
git worktree add -b feature/new-payment ../my-repo-payment main
# Add a worktree in detached HEAD state (specific commit)
git worktree add ../my-repo-review abc1234
# List all worktrees
git worktree list
# Output example:
/home/alex/my-repo abc1234 [main]
/home/alex/my-repo-hotfix def5678 [hotfix/critical-bug]
/home/alex/my-repo-payment ghi9012 [feature/new-payment]
# Remove a worktree (safe — checks for uncommitted changes)
git worktree remove ../my-repo-hotfix
# Force remove even with uncommitted changes
git worktree remove --force ../my-repo-hotfix
# Prune stale worktree references (after manual deletion)
git worktree prune
# Move a worktree to a different path
git worktree move ../my-repo-hotfix ../archives/hotfix-jan2026
Real-World Example: Hotfix While Keeping Feature Work
# === Scenario: You're working on feature/auth-refactor ===
cd ~/my-repo # your main worktree
git branch # shows: * feature/auth-refactor
# ... lots of uncommitted work in progress ...
# 🚨 CRITICAL BUG ALERT! Do NOT stash. Just add a worktree:
git worktree add -b hotfix/login-null-check ~/my-repo-hotfix main
# Open a new terminal and work on the hotfix
cd ~/my-repo-hotfix
# Fix the bug
vim src/auth/login.ts
git add .
git commit -m "fix: handle null user on login redirect"
git push origin hotfix/login-null-check
# Create PR and merge to main (via GitHub/GitLab/etc)
# Then merge to main locally:
git checkout main # ← you'd do this in a 3rd worktree or here
git merge hotfix/login-null-check
git push origin main
# Clean up
git worktree remove ~/my-repo-hotfix
git branch -d hotfix/login-null-check
# Back to your feature work — nothing was interrupted!
cd ~/my-repo
# All your uncommitted changes are still here, untouched ✅
Advanced Usage: CI/CD, Code Reviews & Parallel Testing
# ─── Pattern 1: Code Review Without Switching ───────────────
# Review a PR without disturbing your current work
git worktree add /tmp/review-pr-243 origin/feature/payment-v2
cd /tmp/review-pr-243
# Run the app, check behavior, leave comments
cd ~/my-repo
git worktree remove /tmp/review-pr-243
# ─── Pattern 2: Parallel Test Runs ──────────────────────────
# Run tests on main while developing on feature branch
git worktree add /tmp/test-main main
cd /tmp/test-main && npm test & # runs in background
cd ~/my-repo && npm test & # runs in parallel
# ─── Pattern 3: Release Branch Management ───────────────────
git worktree add ~/releases/v2.1 release/2.1
git worktree add ~/releases/v2.0 release/2.0
# Apply security patches to both simultaneously
patch_file="fix-cve-2026-001.patch"
cd ~/releases/v2.1 && git apply "../$patch_file" && git commit -am "security: apply CVE-2026-001"
cd ~/releases/v2.0 && git apply "../$patch_file" && git commit -am "security: apply CVE-2026-001"
# ─── Pattern 4: Ephemeral Worktrees for CI ──────────────────
# In a CI script — build without changing the checked-out branch
git worktree add /tmp/ci-build "$CI_COMMIT_SHA"
cd /tmp/ci-build
npm ci && npm run build && npm test
git worktree remove /tmp/ci-build
⚠️ Important Rules & Constraints
The same branch cannot be checked out in two worktrees simultaneously. Git enforces this to prevent conflicting HEAD pointers. You'll get: fatal: 'feature/x' is already checked out
All worktrees share a single .git object database. Git operations like fetch, log, and blame work identically in any worktree — they all see the same refs.
Most modern IDEs (VS Code, JetBrains) support worktrees. Each worktree directory is a separate "project" in your IDE. VS Code's Remote - Containers also works with worktrees.
Worktrees don't duplicate the .git objects directory. Only the working files are duplicated. A worktree of a 500MB repo uses ~100-200MB extra (just working files), not 500MB.
Worktrees vs Alternatives
⚖️ Comparison: Worktrees vs Other Approaches
| Approach | Context Switch | Disk Usage | Parallel Work | Best For |
|---|---|---|---|---|
| git worktree | ✅ None | ✅ Minimal | ✅ True parallel | Most use cases |
| git stash | ⚠️ Full switch | ✅ None | ❌ Sequential only | Quick, temporary |
| Second clone | ✅ None | ❌ Full duplication | ✅ True parallel | Isolated experiments |
| WIP commit + switch | ⚠️ Full switch | ✅ None | ❌ Sequential only | When stash isn't clean |
Scripting Worktrees for Productivity
# Add to your ~/.bashrc or ~/.zshrc
# Create a worktree for a PR review
gwt-review() {
local branch="$1"
local dir="/tmp/review-$(basename $branch)"
git fetch origin "$branch"
git worktree add "$dir" "origin/$branch"
echo "Reviewing at: $dir"
cd "$dir"
}
# Create a worktree based on current repo name
gwt-add() {
local branch="$1"
local repo_name=$(basename "$(git rev-parse --show-toplevel)")
local short_branch=$(echo "$branch" | sed 's/[/:]/-/g')
local dir="../$(repo_name)-$short_branch"
git worktree add -b "$branch" "$dir" main
echo "Worktree at: $dir"
cd "$dir"
}
# List worktrees in a nice table
gwt-list() {
git worktree list --porcelain | awk '
/^worktree/ { path=substr($0,10) }
/^branch/ { branch=substr($0,8) }
/^HEAD/ { head=substr($0,6,7) }
/^$/ { printf "%-50s %-30s %s
", path, branch, head; path=branch=head="" }
'
}
# Clean up all /tmp/review-* worktrees
gwt-clean-reviews() {
git worktree list --porcelain | grep -A1 '^worktree /tmp/review-' | grep '^worktree' | awk '{print $2}' | xargs -I{} git worktree remove "{}"
}
Worktrees with Monorepos and Node.js/npm
# Each worktree has its own node_modules — this is usually fine
# But to avoid reinstalling, you can use npm ci with caching:
git worktree add ../my-repo-feature feature/new-ui
cd ../my-repo-feature
npm ci # Install dependencies for this branch
# With pnpm — it uses a shared store, so adding a worktree is fast!
git worktree add ../my-repo-feature feature/new-ui
cd ../my-repo-feature
pnpm install # Links from global pnpm store — very fast
# With yarn workspaces / pnpm workspaces in a monorepo:
# Worktrees work great — each worktree gets its own node_modules
# but shares the package cache
# .gitignore each worktree's external node_modules if needed:
# Add to .gitignore:
../*-worktree/
../*-hotfix/
../*-feature/
💡 Best Practices & Pro Tips
../repo-hotfix, ../repo-review-123, ../repo-release-2.1. Makes gwt-list output readable.git worktree prune regularly (or as a git hook) to clean stale references. Also add temporary worktree paths to your global ~/.gitignore.code /path/to/worktree) or use JetBrains' "Open Directory" for parallel IDEs on the same codebase.~/projects/my-repo → ~/projects/my-repo-hotfix. Avoids deep nesting and keeps related work grouped.Summary
Git Worktrees are a powerful but underutilized feature available in every modern Git installation. They eliminate the friction of context-switching between branches by allowing multiple checkouts of the same repository to coexist simultaneously. Whether you're handling emergency hotfixes, reviewing pull requests, running parallel tests, or managing multiple release branches, worktrees provide a clean and efficient solution.
Start small: next time you need to context-switch, try git worktree add instead of stashing. Once you build the habit, you'll find yourself using worktrees as a core part of your daily Git workflow.