Skip to main content

Git Worktrees: Multiple Branches, Zero Context Switching

Development
6 min read

You're knee-deep in a feature branch when urgent production fire hits. Instead of stashing, switching, and losing your mental context, what if you could just... open another folder and work on the hotfix immediately? Git worktrees make this possible, and once you experience the workflow, you'll wonder how you ever lived without them.

What Are Git Worktrees?

Git worktrees let you check out multiple branches of the same repository into separate directories simultaneously. Think of it as having multiple working copies of your repo, each locked to a different branch, all sharing the same .git folder and commit history.

Here's the mental shift: instead of switching branches in one directory, you switch directories for different branches.

The difference is dramatic: traditional workflow forces sequential context switching, while worktrees enable parallel development.

Why Worktrees Change Everything

No More Stash Juggling

You know the drill: you're in flow state, deep in complex changes, when urgent work appears. With traditional git, you stash (hoping you don't forget what you were doing), switch branches, work, switch back, unstash, and spend 10 minutes remembering where you left off.

Worktrees eliminate this entirely. Your feature work stays exactly as you left it, in its own directory.

IDE State Preservation

Your IDE doesn't lose track of open files, breakpoints, or terminal sessions when you switch between worktree directories. Each branch maintains its own IDE workspace state.

Parallel Development

Need to compare implementations across branches? Open both directories in separate IDE windows. Want to copy a function from one branch to another? Simple file copy. Testing how your feature branch handles different scenarios? Keep multiple environments running simultaneously.

Setting Up Your First Worktree

Let's walk through the practical setup. I'll use a typical web app scenario where you maintain main, develop features, and handle production hotfixes.

Initial Repository Setup

Start with your existing repository:

cd ~/projects/myapp
git status # confirm you're in the main branch and clean

Creating Worktrees

Here's the playbook I'd run for a typical multi-branch workflow:

# Create a worktree for your main branch (if not already there)
git worktree add ../myapp-main main

# Create worktree for a new feature branch
git worktree add ../myapp-auth -b feature-auth

# Create worktree for hotfix work
git worktree add ../myapp-hotfix -b hotfix-critical-bug

# Create worktree for an existing remote branch
git worktree add ../myapp-staging origin/staging

Your directory structure now looks like:

~/projects/
├── myapp/ # original clone
├── myapp-main/ # main branch worktree
├── myapp-auth/ # feature-auth branch worktree
├── myapp-hotfix/ # hotfix-critical-bug branch worktree
└── myapp-staging/ # staging branch worktree

Worktree Management Commands

# List all worktrees
git worktree list

# Remove a worktree (deletes the directory)
git worktree remove ../myapp-hotfix

# Remove worktree reference (if you manually deleted the directory)
git worktree prune

# Move a worktree to different location
git worktree move ../myapp-auth ../features/myapp-auth

Real-World Scenarios

Scenario 1: The Production Emergency

You're implementing OAuth integration when a critical security vulnerability needs immediate patching.

Your OAuth work remains untouched, IDE state preserved, no mental context lost.

Scenario 2: Testing Across Environments

You need to verify your feature works with the current production state:

# Keep feature development going in myapp-auth
# Test integration in production-like environment
cd ../myapp-main
git pull origin main # Get latest production state
npm start # Run production version

# In another terminal
cd ../myapp-auth
npm run dev # Run feature version

# Compare behaviors, check for conflicts, verify compatibility

Scenario 3: Code Review Workflow

Someone requests changes on your PR while you're already working on the next feature:

# Current work in myapp-next-feature
# PR feedback for feature-auth branch
cd ../myapp-auth
# Address review comments
git add .
git commit -m "refactor: address PR feedback"
git push

# Immediately back to new feature work
cd ../myapp-next-feature

Advanced Worktree Strategies

The Branch-Per-Directory Pattern

Organize worktrees by purpose rather than branch name:

~/projects/myapp/
├── current/ # Your main development branch
├── production/ # Production/main branch
├── staging/ # Staging branch
├── feature/ # Current feature work
├── hotfix/ # Emergency fixes
└── experiment/ # Experimental branches

Shared Configuration

Worktrees share the same .git directory, which means:

This is powerful for consistency but requires awareness for hooks and config that affect working directory state.

Common Gotchas and Solutions

Issue: Accidentally Committing to Wrong Branch

Problem: You forgot which worktree you're in and accidentally committed to the wrong branch.

Solution: Make your current branch and worktree obvious in your terminal or editor:

  • Customize your shell prompt to display the current branch (most modern shells and plugins support this).
  • Use directory naming conventions that include the branch or purpose.
  • Many IDEs and editors (like VS Code, JetBrains, etc.) show the current branch in the status bar—keep an eye on it before committing.
  • Consider using tools like git status or git branch --show-current to double-check your context before making changes.
  • For extra safety, set up pre-commit hooks that warn you if you're about to commit to a protected or unexpected branch.

Issue: Worktree Directory Confusion

Problem: Too many similar directory names cause confusion.

Solution: Use descriptive names and consistent patterns:

# Instead of
myapp-feature-auth
myapp-feature-billing
myapp-hotfix-security

# Use
myapp-auth-feature
myapp-billing-feature
myapp-security-hotfix

Issue: Large Repository Performance

Problem: Multiple worktrees of large repositories consume disk space.

Solution: Use sparse-checkout for focused worktrees:

git worktree add ../myapp-frontend -b frontend-only
cd ../myapp-frontend
git sparse-checkout init --cone
git sparse-checkout set frontend/ shared/

Workflow Optimization Tips

1. IDE Project Templates

Create VS Code workspace files for common worktree combinations:

// myapp-dev.code-workspace
{
"folders": [
{ "path": "./myapp-main" },
{ "path": "./myapp-feature" },
{ "path": "./myapp-staging" }
],
"settings": {
"git.defaultCloneDirectory": "./worktrees"
}
}

2. Automated Worktree Setup

Script common worktree patterns:

# setup-feature-work.ps1
param([string]$FeatureName)

git worktree add "../myapp-$FeatureName" -b "feature-$FeatureName"
code "../myapp-$FeatureName"
Set-Location "../myapp-$FeatureName"

3. Cleanup Automation

# clean-merged-worktrees.ps1
git worktree list --porcelain |
Select-String "branch refs/heads/" |
ForEach-Object {
$branch = ($_ -split "/")[-1]
if (git branch --merged main | Select-String $branch) {
Write-Host "Removing merged worktree: $branch"
git worktree remove "../myapp-$branch" --force
}
}

When NOT to Use Worktrees

Worktrees aren't always the answer:

  • Simple, linear workflows: If you rarely work on multiple branches simultaneously
  • Disk space constraints: Each worktree requires full working directory space
  • Team unfamiliarity: If your team isn't comfortable with the concept
  • Complex build systems: Some build tools don't handle multiple working directories well

The Bottom Line

Git worktrees transform your development workflow from sequential branch switching to parallel branch development. You maintain mental context, preserve IDE state, and eliminate the friction of constant stashing and switching.

Here's the playbook I'd run for getting started:

  1. Start small: Create one additional worktree for your most common secondary task (hotfixes, code review, etc.)
  2. Establish naming conventions: Consistent directory naming prevents confusion
  3. Integrate with your shell: Add branch info to prompts and create helper functions
  4. Build cleanup habits: Regularly remove completed worktrees to avoid clutter

The mental shift takes a few days, but once worktrees become part of your muscle memory, you'll find yourself significantly more productive and less frustrated with context switching.

Your future self will thank you for making this change.