Git Worktree: Work on Multiple Branches Simultaneously

David Childs

Git worktree is a hidden gem that lets you check out multiple branches simultaneously in separate directories. Instead of constantly switching branches, stashing changes, and losing context, you can have multiple working directories from the same repository.

Understanding Git Worktree

Traditional Git workflow forces you to work on one branch at a time. Git worktree breaks this limitation by creating additional working directories linked to your repository:

my-project/              # Main worktree (main branch)
my-project-feature/      # Additional worktree (feature branch)
my-project-hotfix/       # Additional worktree (hotfix branch)

Each directory is a fully functional working tree with its own index and HEAD.

Basic Worktree Operations

Creating a Worktree

# Add a new worktree for existing branch
git worktree add ../project-feature feature-branch

# Create new branch and worktree
git worktree add -b new-feature ../project-new-feature

# Create worktree in specific location
git worktree add /tmp/emergency-fix hotfix-branch

Listing Worktrees

# List all worktrees
$ git worktree list
/Users/dev/project           abc1234 [main]
/Users/dev/project-feature   def5678 [feature-branch]
/Users/dev/project-hotfix    ghi9012 [hotfix-branch]

# Verbose listing
git worktree list --verbose

Removing Worktrees

# Remove a worktree
git worktree remove ../project-feature

# Force remove (if there are uncommitted changes)
git worktree remove --force ../project-feature

# Clean up stale worktrees
git worktree prune

Practical Use Cases

1. Parallel Feature Development

Work on multiple features without context switching:

# Main repository for stable development
cd ~/projects/app
git checkout main

# Feature A in separate directory
git worktree add ../app-feature-a -b feature/payment-integration

# Feature B in another directory
git worktree add ../app-feature-b -b feature/user-dashboard

# Work on features independently
cd ../app-feature-a
npm install
npm run dev  # Port 3000

cd ../app-feature-b
npm install
npm run dev -- --port 3001  # Different port

2. Emergency Hotfixes

Handle urgent fixes without disrupting current work:

# Working on a feature
cd ~/project-feature
# ... in the middle of complex changes ...

# Emergency! Production bug reported
# No need to stash, just create new worktree
git worktree add ~/project-hotfix -b hotfix/critical-bug origin/main

cd ~/project-hotfix
# Fix the bug
git add .
git commit -m "Fix: Critical production issue"
git push origin hotfix/critical-bug

# Return to feature work - exactly where you left off
cd ~/project-feature

3. Code Review Workflow

Review PRs without disrupting your work:

#!/bin/bash
# review-pr.sh - Script to review pull requests

PR_NUMBER=$1
BRANCH_NAME="pr-$PR_NUMBER"

# Fetch PR branch
git fetch origin pull/$PR_NUMBER/head:$BRANCH_NAME

# Create worktree for review
git worktree add ../project-review-$PR_NUMBER $BRANCH_NAME

echo "PR #$PR_NUMBER ready for review in ../project-review-$PR_NUMBER"
cd ../project-review-$PR_NUMBER

# Run tests
npm install
npm test

# After review, cleanup
cd ..
git worktree remove project-review-$PR_NUMBER
git branch -D $BRANCH_NAME

4. Testing Multiple Versions

Test different versions simultaneously:

# Test current release
git worktree add ../app-v2.0 tags/v2.0.0
cd ../app-v2.0
npm test

# Test previous release
git worktree add ../app-v1.9 tags/v1.9.0
cd ../app-v1.9
npm test

# Compare performance
echo "Running benchmark on v2.0..."
cd ../app-v2.0 && npm run benchmark

echo "Running benchmark on v1.9..."
cd ../app-v1.9 && npm run benchmark

Advanced Worktree Patterns

Worktree Configuration

# Set up worktree-specific config
cd ~/project-feature
git config user.email "feature-test@example.com"

# This config only applies to this worktree
# Main worktree keeps its own configuration

Automated Worktree Management

#!/bin/bash
# worktree-manager.sh

create_feature_worktree() {
    FEATURE_NAME=$1
    WORKTREE_DIR="../project-$FEATURE_NAME"
    
    if [ -d "$WORKTREE_DIR" ]; then
        echo "Worktree already exists: $WORKTREE_DIR"
        return 1
    fi
    
    git worktree add -b "feature/$FEATURE_NAME" "$WORKTREE_DIR"
    cd "$WORKTREE_DIR"
    
    # Setup environment
    npm install
    cp ../.env.example .env
    
    echo "Worktree created: $WORKTREE_DIR"
    echo "Branch: feature/$FEATURE_NAME"
}

cleanup_old_worktrees() {
    # Remove worktrees older than 30 days
    git worktree list --porcelain | grep worktree | cut -d' ' -f2 | while read dir; do
        if [ ! -d "$dir" ]; then
            git worktree prune
        fi
    done
}

Worktree for Different Environments

# Production debugging
git worktree add ../app-prod production

# Staging environment
git worktree add ../app-staging staging

# Development environment
git worktree add ../app-dev develop

# Each can run with different configs
cd ../app-prod && npm start -- --env=production
cd ../app-staging && npm start -- --env=staging
cd ../app-dev && npm start -- --env=development

Worktree Best Practices

1. Naming Conventions

# Use consistent naming patterns
git worktree add ../project-feature-name feature/name
git worktree add ../project-bugfix-issue bugfix/issue
git worktree add ../project-release-2.0 release/2.0

2. Location Strategy

# Option 1: Sibling directories
project/
project-feature/
project-hotfix/

# Option 2: Subdirectory
project/
project-worktrees/
  ├── feature/
  ├── hotfix/
  └── release/

# Option 3: Temporary location for short-lived work
/tmp/project-quick-fix/

3. Cleanup Script

#!/bin/bash
# cleanup-worktrees.sh

echo "Current worktrees:"
git worktree list

# Find and remove orphaned worktrees
git worktree prune -v

# Interactive cleanup
git worktree list | tail -n +2 | while read -r line; do
    dir=$(echo $line | awk '{print $1}')
    branch=$(echo $line | awk '{print $3}' | tr -d '[]')
    
    read -p "Remove worktree $dir [$branch]? (y/n) " -n 1 -r
    echo
    if [[ $REPLY =~ ^[Yy]$ ]]; then
        git worktree remove "$dir"
    fi
done

Integration with Development Tools

VS Code Multi-Window Setup

#!/bin/bash
# open-worktrees-vscode.sh

# Open each worktree in separate VS Code window
git worktree list | while read -r line; do
    dir=$(echo $line | awk '{print $1}')
    code "$dir"
done

Docker Development

# docker-compose.yml for worktree
version: '3'
services:
  app-main:
    build: .
    volumes:
      - ./:/app
    ports:
      - "3000:3000"
  
  app-feature:
    build: ../project-feature
    volumes:
      - ../project-feature:/app
    ports:
      - "3001:3000"

tmux Session Management

#!/bin/bash
# tmux-worktrees.sh

# Create tmux session for each worktree
git worktree list | while read -r line; do
    dir=$(echo $line | awk '{print $1}')
    branch=$(echo $line | awk '{print $3}' | tr -d '[]')
    session_name="wt-$branch"
    
    tmux new-session -d -s "$session_name" -c "$dir"
    tmux send-keys -t "$session_name" "npm run dev" Enter
done

# Attach to main
tmux attach -t wt-main

Common Pitfalls and Solutions

1. Submodule Complications

# Worktrees with submodules need special handling
git worktree add ../project-with-submodules feature-branch

cd ../project-with-submodules
git submodule update --init --recursive

2. Large File Issues

# For repos with large files, consider shallow worktrees
git worktree add --no-checkout ../project-quick-look feature-branch
cd ../project-quick-look
git sparse-checkout init
git sparse-checkout set src/ tests/
git checkout

3. Branch Locking

# Can't checkout same branch in multiple worktrees
$ git worktree add ../another-main main
fatal: 'main' is already checked out at '/path/to/project'

# Solution: Create a tracking branch
git branch main-copy main
git worktree add ../another-main main-copy

Performance Considerations

Shared Repository Objects

# All worktrees share the same .git directory
# Check object database size
du -sh .git/objects

# Pack objects for better performance
git gc --aggressive

# This benefits all worktrees

Worktree-Specific Performance

# Each worktree has its own index
# Optimize individually if needed
cd ../project-feature
git update-index --refresh
git status  # Warms up file system cache

Scripting and Automation

Feature Development Script

#!/bin/bash
# feature-dev.sh

FEATURE_NAME=$1
BASE_BRANCH=${2:-main}

if [ -z "$FEATURE_NAME" ]; then
    echo "Usage: $0 <feature-name> [base-branch]"
    exit 1
fi

WORKTREE_DIR="../project-$FEATURE_NAME"
BRANCH_NAME="feature/$FEATURE_NAME"

# Create worktree
git worktree add -b "$BRANCH_NAME" "$WORKTREE_DIR" "$BASE_BRANCH"

# Setup development environment
cd "$WORKTREE_DIR"
npm install
cp ../.env.development .env
echo "PORT=30$(echo $FEATURE_NAME | wc -c)" >> .env

# Create feature documentation
cat > FEATURE.md << EOF
# Feature: $FEATURE_NAME
Base: $BASE_BRANCH
Created: $(date)

## Description
TODO: Add feature description

## Tasks
- [ ] Implementation
- [ ] Tests
- [ ] Documentation
EOF

echo "Feature worktree ready at: $WORKTREE_DIR"
echo "Branch: $BRANCH_NAME"
echo "Start development with: cd $WORKTREE_DIR && npm run dev"

Parallel Testing Script

#!/bin/bash
# parallel-test.sh

# Run tests in all worktrees simultaneously
git worktree list | while read -r line; do
    dir=$(echo $line | awk '{print $1}')
    branch=$(echo $line | awk '{print $3}' | tr -d '[]')
    
    echo "Testing $branch in $dir"
    (cd "$dir" && npm test) &
done

# Wait for all tests to complete
wait

echo "All tests completed"

Conclusion

Git worktree is a game-changer for developers who juggle multiple tasks. It eliminates the friction of branch switching, enables true parallel development, and makes complex workflows manageable.

Whether you're handling emergency fixes, reviewing code, or developing multiple features, worktrees let you maintain multiple working states without the overhead of cloning repositories or complex stashing strategies.

Start with simple use cases like code reviews and emergency fixes, then gradually incorporate worktrees into your daily workflow. Once you experience the freedom of having multiple branches checked out simultaneously, you'll wonder how you ever lived without it.

Share this article

DC

David Childs

Consulting Systems Engineer with over 10 years of experience building scalable infrastructure and helping organizations optimize their technology stack.

Related Articles