Git Worktree for Parallel Work: Multiple Branches Simultaneously
Master git worktree to work on multiple branches simultaneously without stashing or cloning. Learn parallel development workflows, management commands, and best practices.
Git Worktree for Parallel Work: Multiple Branches Simultaneously
git worktree is the feature that eliminates the “stash and switch” dance. It allows you to check out multiple branches of the same repository in different directories simultaneously, all sharing the same .git database. No cloning, no stashing, no context switching overhead.
Imagine you’re deep into a feature branch when a critical production bug report comes in. Normally, you’d stash your changes, switch to main, fix the bug, push, switch back, and unstash. With worktrees, you just create a new directory for the hotfix, fix it, push, and delete the directory. Your feature branch keeps running in the original directory, untouched.
This post covers the complete worktree toolkit: creating and managing worktrees, handling shared state, automation scripts, and the scenarios where worktrees save hours of productivity.
When to Use / When Not to Use
Use Git Worktree When
- Hotfixes during active development — Fix production bugs without stashing feature work
- Code review — Check out a PR branch in a separate directory to test it locally
- Long-running builds/tests — Keep working while a build runs in another worktree
- Comparing branches — Diff two branches side-by-side in your file explorer
- Experimentation — Try a risky refactor in a separate worktree without risking your main work
Do Not Use Git Worktree When
- Simple context switches — If you’re just checking a file,
git showis faster - Limited disk space — Each worktree consumes disk space for checked-out files
- Shared network drives — Worktrees can have issues on NFS or network mounts
- IDE conflicts — Some IDEs get confused by multiple instances of the same repo
Core Concepts
Git worktrees create linked working directories that share a single repository database:
| Concept | Description |
|---|---|
| Main worktree | The original directory where you cloned the repo |
| Linked worktree | Additional directories linked to the same .git |
Shared .git | All worktrees share the same object database and refs |
| Separate HEAD | Each worktree has its own HEAD and index |
| Branch locking | A branch checked out in one worktree cannot be checked out in another |
The architecture looks like this:
repo/
.git/ # Shared repository database
src/ # Main worktree (branch: main)
../hotfix/ # Linked worktree (branch: hotfix/urgent)
../review/ # Linked worktree (branch: pr/123)
graph TD
A[.git Directory] --> B[Main Worktree]
A --> C[Linked Worktree 1]
A --> D[Linked Worktree 2]
B --> E[HEAD: main]
C --> F[HEAD: feature/auth]
D --> G[HEAD: hotfix/bug]
A --> H[Shared Objects]
A --> I[Shared Refs]
Architecture and Flow Diagram
The worktree lifecycle from creation through cleanup:
graph TD
A[Main Repository] -->|git worktree add| B[New Directory]
B -->|Checkout Branch| C[Linked Worktree]
C -->|Independent Work| D[Commits & Pushes]
D -->|Shared Database| A
C -->|Done| E[git worktree remove]
E --> F[Directory Deleted]
A -->|Cleanup| G[git worktree prune]
Step-by-Step Guide
1. Creating a Worktree
Create a new linked worktree for a different branch:
# Create a worktree for a hotfix
git worktree add ../hotfix-urgent hotfix/urgent
# Create a worktree for a PR review
git worktree add ../pr-review pr/feature-auth
# Create a worktree with a new branch
git worktree add ../experiment -b experiment/new-algo
# Create a worktree with a detached HEAD
git worktree add ../detached --detach v1.0.0
The command creates the directory, checks out the branch, and links it to the main repository.
2. Working in Parallel
Each worktree operates independently:
# In main worktree (~/project)
git checkout feature/user-dashboard
# Edit files, run tests, continue development
# In hotfix worktree (~/hotfix-urgent)
cd ../hotfix-urgent
# Fix the bug
git add .
git commit -m "fix: resolve payment timeout"
git push origin hotfix-urgent
# Back to main worktree
cd ~/project
# Feature work is untouched, no stash needed
3. Listing and Managing Worktrees
Keep track of your active worktrees:
# List all worktrees
git worktree list
# /home/user/project abc1234 [main]
# /home/user/hotfix-urgent def5678 [hotfix/urgent]
# /home/user/pr-review ghi9012 [pr/feature-auth]
# Remove a worktree (directory must be clean)
git worktree remove ../hotfix-urgent
# Force remove (even if dirty)
git worktree remove ../experiment --force
# Prune stale worktree references
git worktree prune
4. Moving Worktrees
If you need to relocate a worktree:
# Lock the worktree (prevents pruning)
git worktree lock ../experiment
# Move the directory
mv ../experiment ../new-location/experiment
# Update the path
git worktree move ../new-location/experiment ../experiment
# Unlock
git worktree unlock ../experiment
5. Cleaning Up
Remove worktrees you no longer need:
# Remove and delete the directory
git worktree remove ../pr-review
# If the worktree has uncommitted changes:
git worktree remove ../experiment --force
# Prune references to deleted worktrees
git worktree prune
# Complete cleanup
rm -rf ../old-worktree
git worktree prune
Production Failure Scenarios + Mitigations
| Scenario | What Happens | Mitigation |
|---|---|---|
| Branch checkout conflict — Trying to checkout a branch already used in another worktree | Git prevents this to avoid corruption | Use git worktree list to find where the branch is checked out |
Stale worktree references — Deleting a directory without git worktree remove | git worktree list shows ghost entries | Run git worktree prune regularly |
Shared lock files — Two worktrees try to run git gc simultaneously | Lock file conflicts | Git handles this automatically; retry after a moment |
| IDE confusion — IDE indexes both worktrees as separate projects | Duplicate search results, high memory usage | Exclude linked worktrees from IDE indexing |
| Disk space exhaustion — Too many worktrees with large build artifacts | Out of disk space | Clean build artifacts in worktrees; use git worktree remove |
| Network drive issues — Worktrees on NFS or SMB shares | File locking problems, corruption | Keep worktrees on local disks only |
Trade-offs
| Aspect | Advantage | Disadvantage |
|---|---|---|
| No stashing — Keep changes in place | Requires disk space for each worktree | |
| Parallel work — Multiple branches active | IDE may get confused by multiple instances | |
| Shared database — Efficient storage | Branch locking prevents duplicate checkouts | |
| Fast creation — Instant branch checkout | Network drives can cause issues | |
| Independent state — Each worktree has own HEAD | Cleanup requires manual removal | |
| Testing — Run tests in one, code in another | Build artifacts may duplicate across worktrees |
Implementation Snippets
Worktree Aliases
# Add to ~/.gitconfig
[alias]
wt-add = "!f() { git worktree add ../wt-\"$1\" \"$1\"; }; f"
wt-list = git worktree list
wt-rm = "!f() { git worktree remove ../wt-\"$1\"; }; f"
wt-prune = git worktree prune
wt-clean = "!f() { git worktree list --porcelain | grep '^worktree' | awk '{print $2}' | while read wt; do if [ ! -d \"$wt\" ]; then git worktree prune; fi; done; }; f"
Worktree Setup Script
#!/bin/bash
# scripts/setup-worktrees.sh
# Create standard worktree structure
REPO_ROOT=$(git rev-parse --show-toplevel)
BASE_NAME=$(basename "$REPO_ROOT")
echo "Setting up worktrees for $BASE_NAME..."
# Create parent directory for worktrees if it doesn't exist
PARENT_DIR=$(dirname "$REPO_ROOT")
WT_DIR="$PARENT_DIR/${BASE_NAME}-worktrees"
mkdir -p "$WT_DIR"
# Create worktree for main branch
git worktree add "$WT_DIR/main" main
# Create worktree for develop branch
git worktree add "$WT_DIR/develop" develop
echo "Worktrees created in $WT_DIR"
echo " - main: $WT_DIR/main"
echo " - develop: $WT_DIR/develop"
IDE Exclusion Configuration
// .vscode/settings.json
{
"files.watcherExclude": {
"**/../project-worktrees/**": true
},
"search.exclude": {
"**/../project-worktrees/**": true
},
"files.exclude": {
"**/../project-worktrees/**": true
}
}
Worktree Cleanup Cron Job
#!/bin/bash
# scripts/cleanup-worktrees.sh
# Remove worktrees older than 7 days
find ../ -maxdepth 1 -type d -name "wt-*" -mtime +7 | while read -r wt; do
if [ -d "$wt/.git" ]; then
echo "Removing stale worktree: $wt"
git worktree remove "$wt" --force 2>/dev/null || rm -rf "$wt"
fi
done
git worktree prune
Observability Checklist
- Logs: Not typically applicable — worktrees are local
- Metrics: Track worktree creation frequency and average lifetime
- Alerts: Alert when disk usage from worktrees exceeds threshold
- Dashboards: Display active worktrees per developer and disk space usage
- Cleanup: Automate worktree pruning to prevent stale references
Security and Compliance Notes
- Local only: Worktrees don’t push data; they’re local directories
- Access control: Worktrees inherit repository permissions
- Sensitive data: Worktrees contain the same code as the main repo — protect them equally
- Audit trail: Commits from worktrees appear normally in history
- Compliance: Worktrees don’t change compliance requirements; treat them as part of the repo
Common Pitfalls and Anti-Patterns
- Branch Collision — Trying to checkout
mainin a worktree when it’s already checked out elsewhere. Usegit worktree listto check. - Stale References — Deleting directories without
git worktree remove. Rungit worktree pruneregularly. - IDE Indexing — IDEs indexing multiple worktrees causes performance issues. Exclude linked worktrees.
- Build Artifact Duplication — Each worktree has its own
node_modulesortarget. Share artifacts or clean regularly. - Network Drive Usage — Worktrees on network drives can corrupt. Keep them local.
- Forgetting Worktrees — Creating worktrees and forgetting them wastes disk space. Name them clearly and clean up.
- Force Remove on Dirty Worktrees —
--forcedeletes uncommitted work. Commit or stash first.
Quick Recap Checklist
- Use
git worktree add <path> <branch>to create linked worktrees - Each worktree has independent HEAD and index
- Branches cannot be checked out in multiple worktrees simultaneously
- Use
git worktree listto view active worktrees - Use
git worktree remove <path>to clean up - Run
git worktree pruneto remove stale references - Exclude worktrees from IDE indexing to prevent performance issues
- Keep worktrees on local disks, not network drives
- Clean build artifacts regularly to save disk space
- Use worktrees for hotfixes, reviews, and parallel development
Worktree Management Checklist
- List active worktrees —
git worktree listbefore creating new ones - Name clearly — Use descriptive directory names (e.g.,
../wt-hotfix-payment) - Prune regularly —
git worktree pruneafter deleting directories manually - Clean on branch delete — Remove worktrees when their branches are merged and deleted
- Exclude from IDE — Configure VS Code/IntelliJ to ignore linked worktree directories
- Keep local — Never place worktrees on network drives (NFS, SMB)
- Monitor disk usage — Each worktree duplicates
node_modulesand build artifacts - Lock long-running —
git worktree lockfor worktrees you don’t want auto-pruned - Force remove carefully —
--forcedeletes uncommitted changes; commit first - Cleanup stale refs — Run
git worktree pruneweekly to remove ghost entries
Interview Q&A
Git worktree creates linked directories that share the same .git database. All worktrees share objects, refs, and configuration. Creating a worktree is instant and uses minimal additional disk space.
Cloning creates a completely independent repository with its own .git database. It duplicates all objects and requires a full network fetch. Clones are independent; worktrees are connected.
Use worktrees when you need multiple branches of the same repo. Use clones when you need independent repositories or want to test on a different machine.
No. Git prevents checking out the same branch in multiple worktrees to avoid corruption. If you try, you'll get an error: 'main' is already checked out at '/path/to/main'.
If you need to work on the same code in two places, use --detach to create a detached HEAD worktree, or create a temporary branch from the same commit.
If you deleted the directory without git worktree remove, the reference still exists in Git. Run git worktree prune to clean up the stale reference.
Your work is safe if you committed it — commits are stored in the shared .git database. If you had uncommitted changes, they're lost unless you stashed them or have IDE local history.
No. Each worktree has its own working directory, so node_modules, target, dist, and other build artifacts are duplicated. This can consume significant disk space.
To save space, you can symlink shared directories or use build tools that support output directories outside the worktree. However, be careful with symlinked node_modules as native modules may be platform-specific.
Resources
- Git worktree documentation — Official Git documentation
- Git worktree best practices — Usage patterns
- Worktree and IDE configuration — VS Code multi-root setup
- Disk space management — Atlassian guide
- Parallel development workflows — Trunk-based development patterns
Category
Related Posts
Git Stash and Stash Management: Save Work Without Committing
Master git stash for saving uncommitted changes, named stashes, stash list management, and when to use stash vs commit in production workflows.
Master git add: Selective Staging, Patch Mode, and Staging Strategies
Master git add including selective staging, interactive mode, patch mode, and staging strategies for clean atomic commits in version control.
Git Aliases and Custom Commands: Productivity Through Automation
Create powerful Git aliases, custom scripts, and command extensions. Learn git extras, shell function integration, and team-wide alias standardization for faster workflows.