Every developer knows the pain: you’re deep in a feature branch, someone asks you to review a PR, and now you’re stashing changes, switching branches, rebuilding dependencies, and losing your mental context. Git worktrees solve this elegantly.

The Problem with Branch Switching

Traditional git workflow assumes one working directory:

1
2
3
4
5
6
7
8
# You're working on feature-x
git stash
git checkout main
git pull
git checkout pr-branch
npm install  # dependencies changed
npm run build  # wait for it...
# review, then reverse the whole process

Every switch costs time and mental energy. Your editor loses state. Your dev server restarts. Your flow is gone.

Worktrees: Multiple Checkouts, One Repo

Git worktrees let you check out multiple branches simultaneously in separate directories, all sharing the same .git database:

1
2
3
4
5
6
# Create a worktree for the PR review
git worktree add ../project-pr-review pr-branch

# Now you have:
# ~/project/           <- your feature-x work (untouched)
# ~/project-pr-review/ <- pr-branch checkout

Your original working directory stays exactly as you left it. No stashing, no rebuilding, no lost context.

Practical Patterns

Pattern 1: Permanent Main Branch Worktree

Keep main always ready for quick checks:

1
2
3
4
5
6
# One-time setup
git worktree add ../project-main main

# Structure:
# ~/code/project/      <- day-to-day development
# ~/code/project-main/ <- always on main, always clean

Now cd ../project-main && git pull gives you instant access to production code without touching your work.

Pattern 2: Ephemeral Review Trees

Create worktrees on-demand for PR reviews:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# Quick review workflow
review-pr() {
  local branch=$1
  local dir="../review-${branch//\//-}"
  git fetch origin "$branch"
  git worktree add "$dir" "origin/$branch"
  cd "$dir"
  echo "Review in: $dir"
  echo "When done: git worktree remove $dir"
}

# Usage
review-pr feature/new-auth

Pattern 3: Hotfix Isolation

Production is on fire. You need to patch without contaminating your feature work:

1
2
3
4
git worktree add ../hotfix-$(date +%Y%m%d) main
cd ../hotfix-$(date +%Y%m%d)
git checkout -b hotfix/critical-fix
# fix, test, push — your feature branch remains pristine

Managing Worktrees

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# List all worktrees
git worktree list
# /home/dev/project        abc1234 [feature-x]
# /home/dev/project-main   def5678 [main]
# /home/dev/project-review ghi9012 [pr-branch]

# Remove when done
git worktree remove ../project-review

# Prune stale worktrees (if directory was deleted manually)
git worktree prune

IDE Integration

Most modern IDEs handle worktrees gracefully:

VS Code: Open the worktree directory as a separate window. Each window maintains its own state, extensions work normally, and you can have both open side-by-side.

1
2
# Open worktree in new VS Code window
code ../project-main

JetBrains IDEs: File → Open and select the worktree directory. The IDE recognizes it as part of the same git repository.

The Dependency Problem

Worktrees share git data but not node_modules, venv, or build artifacts. This is actually a feature — different branches might need different dependencies.

For Node.js projects:

1
2
3
4
5
6
7
8
# Option 1: Install per-worktree
cd ../project-review && npm install

# Option 2: Use pnpm with shared store (faster)
cd ../project-review && pnpm install

# Option 3: Symlink if dependencies match
ln -s ../project/node_modules node_modules  # risky but fast

For Python:

1
2
3
4
5
# Each worktree gets its own venv
cd ../project-review
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

Caveats

Don’t checkout the same branch twice. Git prevents this because two worktrees modifying the same branch would create conflicts:

1
2
git worktree add ../test main
# error: 'main' is already checked out at '/home/dev/project-main'

Worktrees aren’t clones. They share refs, so a git fetch in one worktree updates all of them. This is usually what you want.

Clean up after yourself. Orphaned worktrees don’t hurt anything but clutter your disk:

1
2
3
# Add to your shell profile
alias gwl='git worktree list'
alias gwp='git worktree prune'

When Worktrees Shine

  • Code review without losing your place
  • Comparing implementations across branches side-by-side
  • Running tests on main while developing on feature
  • Hotfixes with zero risk to in-progress work
  • Long-running tasks (builds, test suites) that shouldn’t block you

When to Just Switch Branches

Worktrees have overhead. If you’re making a quick, clean switch and coming right back, traditional checkout is fine:

1
2
3
4
5
6
# This is fine
git stash
git checkout main
git pull
git checkout -
git stash pop

Use worktrees when the context switch is expensive or when you need both states accessible simultaneously.


Git worktrees have been around since Git 2.5 (2015) but remain underused. Once you internalize the pattern, the “stash-switch-rebuild-switch-pop” dance feels prehistoric. Your branches can coexist, and so can your mental contexts.