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.

published: reading time: 20 min read author: Geek Workbench updated: March 31, 2026

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.

Introduction

git worktree solves the everyday problem of needing two branches checked out at once. Instead of stashing, cloning, or juggling directories, worktrees give you parallel workspaces from a single repo — ideal for code review, hotfixes, and context switching. Understanding how it works and when to apply it can significantly improve your team’s collaboration, code quality, and release processes.

In this article, we’ll explore when to use worktrees and when not to, practical workflows, common patterns and pitfalls, and actionable guidance you can apply to your projects right away. By the end, you’ll have a solid foundation for making informed decisions about parallel development with Git worktree.

git worktree creates linked working directories that share a single repository database. The architecture is elegant: all worktrees share the same .git objects and refs, but each has its own working directory with independent HEAD and index. This means creating a worktree is nearly instant — Git just creates a new directory and checks out a branch there, without duplicating any objects.

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 show is 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:

ConceptDescription
Main worktreeThe original directory where you cloned the repo
Linked worktreeAdditional directories linked to the same .git
Shared .gitAll worktrees share the same object database and refs
Separate HEADEach worktree has its own HEAD and index
Branch lockingA 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

ScenarioWhat HappensMitigation
Branch checkout conflict — Trying to checkout a branch already used in another worktreeGit prevents this to avoid corruptionUse git worktree list to find where the branch is checked out
Stale worktree references — Deleting a directory without git worktree removegit worktree list shows ghost entriesRun git worktree prune regularly
Shared lock files — Two worktrees try to run git gc simultaneouslyLock file conflictsGit handles this automatically; retry after a moment
IDE confusion — IDE indexes both worktrees as separate projectsDuplicate search results, high memory usageExclude linked worktrees from IDE indexing
Disk space exhaustion — Too many worktrees with large build artifactsOut of disk spaceClean build artifacts in worktrees; use git worktree remove
Network drive issues — Worktrees on NFS or SMB sharesFile locking problems, corruptionKeep worktrees on local disks only

Trade-off Analysis

AspectAdvantageDisadvantage
No stashing — Keep changes in placeRequires disk space for each worktree
Parallel work — Multiple branches activeIDE may get confused by multiple instances
Shared database — Efficient storageBranch locking prevents duplicate checkouts
Fast creation — Instant branch checkoutNetwork drives can cause issues
Independent state — Each worktree has own HEADCleanup requires manual removal
Testing — Run tests in one, code in anotherBuild 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 / Anti-Patterns

  1. Branch Collision — Trying to checkout main in a worktree when it’s already checked out elsewhere. Use git worktree list to check.
  2. Stale References — Deleting directories without git worktree remove. Run git worktree prune regularly.
  3. IDE Indexing — IDEs indexing multiple worktrees causes performance issues. Exclude linked worktrees.
  4. Build Artifact Duplication — Each worktree has its own node_modules or target. Share artifacts or clean regularly.
  5. Network Drive Usage — Worktrees on network drives can corrupt. Keep them local.
  6. Forgetting Worktrees — Creating worktrees and forgetting them wastes disk space. Name them clearly and clean up.
  7. Force Remove on Dirty Worktrees--force deletes 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 list to view active worktrees
  • Use git worktree remove <path> to clean up
  • Run git worktree prune to 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 worktreesgit worktree list before creating new ones
  • Name clearly — Use descriptive directory names (e.g., ../wt-hotfix-payment)
  • Prune regularlygit worktree prune after 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_modules and build artifacts
  • Lock long-runninggit worktree lock for worktrees you don’t want auto-pruned
  • Force remove carefully--force deletes uncommitted changes; commit first
  • Cleanup stale refs — Run git worktree prune weekly to remove ghost entries

Interview Questions

1. What is the difference between git worktree and cloning the repository?

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.

2. Can I checkout the same branch in multiple worktrees?

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.

3. How do I recover a worktree I accidentally deleted?

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.

4. How does `git worktree` handle shared objects between multiple worktrees?

Git worktrees share a single .git directory, meaning all objects (blobs, trees, commits) are stored once across all worktrees. When a new worktree checks out a branch, Git creates hard links to existing objects rather than copying them.

  • Objects are reference-counted — when a worktree is removed, Git checks if objects are still referenced
  • New commits in any worktree immediately become available to all other worktrees
  • This makes worktree creation nearly instant and disk-space efficient
5. What happens when you lock a worktree, and when should you use it?

Locking a worktree prevents Git from pruning it automatically and protects against accidental removal. Use git worktree lock <path> to lock and git worktree unlock <path> to release.

  • Locked worktrees are skipped during git worktree prune
  • Prevents git worktree remove without the --force flag
  • Useful for long-running experiments, temporary test environments, or worktrees you want to keep for days
6. How do you move an existing worktree to a different directory path?

Moving a worktree requires locking it first, then using the move command. The sequence is: git worktree lock <old-path>mv <old-path> <new-path>git worktree move <old-path> <new-path>git worktree unlock <new-path>.

  • The lock prevents Git from marking it as stale during the move
  • The git worktree move command updates the internal Git reference
  • Always lock before moving to prevent reference corruption
7. How does `git worktree` interact with Git submodules?

Worktrees handle submodules normally — each worktree has its own submodule working directories. Submodule state is independent per worktree, but they share the same submodule database in the main repository's .git.

  • Checking out a branch in one worktree doesn't affect submodule state in another
  • You can have different submodule commits checked out in different worktrees simultaneously
  • Submodule updates in one worktree don't automatically propagate to others
8. What is the difference between `git worktree remove` and `git worktree prune`?

git worktree remove is for explicitly deleting a specific worktree you no longer need. git worktree prune cleans up stale references left behind when directories are deleted without using the remove command.

  • remove requires the worktree to be clean (no uncommitted changes) unless you use --force
  • prune runs automatically and removes entries for directories that no longer exist on disk
  • Best practice: always use remove when done; use prune as a fallback for cleanup
9. Can you create worktrees from a bare repository?

No, worktrees require a working directory, which a bare repository doesn't have. Bare repositories (created with git clone --bare) have no checkout — they only store the Git database. You'd need a regular repository to create worktrees.

  • Bare repositories are typically used as central/shared repositories on servers
  • To use worktrees with a shared repository, clone it normally first, then create worktrees from that clone
10. How does `git worktree` affect garbage collection and repository size?

Worktrees don't increase repository size because they share the same .git database. However, each worktree has its own working directory with checked-out files, which consumes disk space independently.

  • Git's garbage collection runs across all worktrees simultaneously
  • Objects referenced by any worktree's branches or commits are preserved
  • Build artifacts (node_modules, target, dist) in worktrees are not tracked by Git and must be cleaned manually
11. What are the best practices for naming worktree directories?

Use descriptive, consistent naming that indicates the branch purpose. Common patterns include: ../wt-<branch-name> (e.g., ../wt-hotfix-payment), ../<purpose>-<branch> (e.g., ../review-pr-123), or ../<date>-<purpose> for temporary worktrees.

  • Keep names short but descriptive — you'll type them in terminal
  • Avoid special characters that might break shell commands
  • Consider grouping worktrees in a dedicated parent directory (e.g., ~/project-worktrees/)
12. How does `git worktree` interact with `git stash` operations?

Each worktree has its own separate stash stack. Stashes created in one worktree are not accessible from another worktree — they're stored in that specific worktree's .git refs. However, committed work is shared across all worktrees.

  • Use git stash push within a worktree to save uncommitted changes
  • Commits are shared — you don't need to stash to switch worktrees
  • Stashes are local to each worktree's index, not the shared database
13. Can you use `git worktree` with `git bisect` for parallel debugging?

Yes, you can run git bisect in one worktree while continuing development in another. This is one of worktree's strongest use cases — when bisecting a regression, you can keep your current feature work untouched in a separate worktree.

  • Start bisect in one worktree: git bisect start
  • Continue feature work in another worktree without interference
  • When bisect completes, just delete the bisect worktree and switch back to your feature worktree
14. What happens to worktrees when their tracked branch is deleted?

Worktrees continue to work normally when a branch is deleted — the worktree simply becomes orphaned. The directory remains on disk, HEAD stays at the last commit, and you can continue working. However, Git will warn you when entering such a worktree.

  • Orphaned worktrees cannot be pushed anywhere (no upstream branch)
  • You can create a new branch from the orphaned HEAD to recover
  • Consider removing or repurposing orphaned worktrees to avoid confusion
15. How do you list all worktrees with detailed status information?

Use git worktree list --verbose or git worktree list --porcelain for detailed output. The verbose flag shows the branch and commit hash for each worktree, while porcelain outputs machine-readable format.

  • git worktree list shows: path, commit hash, current branch
  • --porcelain outputs one entry per line with key-value pairs
  • Locked worktrees show a locked marker in verbose output
16. Can you create a worktree from a specific commit rather than a branch?

Yes, use git worktree add <path> <commit-hash> with a commit hash instead of a branch name. This creates a worktree with a detached HEAD at that specific commit. You can then create a new branch from there if needed.

  • Useful for testing old releases or inspecting historical states
  • Add -b <new-branch-name> to create a branch from that commit
  • Detached HEAD worktrees are useful for experimentation without branch commitments
17. What are the security implications of using worktrees?

Worktrees inherit the repository's access control and contain the same code as the main repository. Treat them with the same security hygiene: same access controls, same protection for sensitive data, same compliance requirements.

  • Worktrees don't introduce new attack surfaces beyond standard Git repositories
  • Each worktree has independent file system permissions
  • Audit trails from worktree commits are identical to normal commits
18. Can worktrees be used effectively in CI/CD pipelines?

Worktrees are primarily for local development, not CI/CD. In CI, you typically want fresh, isolated environments per job. However, worktrees can be useful for developer-owned build agents where you want to reuse checkouts across jobs.

  • CI systems like Jenkins or Buildkite can use worktrees for shared build agents
  • Each CI job should use a clean worktree or container, not share with other jobs
  • Worktree creation is nearly instant, making it viable for ephemeral CI runners
19. How do worktrees interact with Git hooks?

Each worktree has its own Git configuration but shares the same hooks directory from the main repository's .git/hooks. Hooks run independently in each worktree — committing in one worktree triggers hooks just as it would in the main repository.

  • Hooks are shared, not copied — changes to hooks affect all worktrees immediately
  • Each worktree runs hooks with its own environment variables and gitdir
  • Pre-commit and post-commit hooks fire identically regardless of which worktree you're in
20. What happens if you try to create a worktree for a branch that has uncommitted changes?

Git will not prevent you from creating a worktree for a branch that has uncommitted changes in another worktree. However, if those uncommitted changes are staged in the index, the new worktree will share that index state. It's recommended to commit or stash changes before creating worktrees to avoid unintended state sharing.

  • Worktrees share the object database but have independent working directories
  • Uncommitted changes remain in the original worktree only
  • Always commit or stash before creating worktrees to ensure clean state

Further Reading

Conclusion

Worktrees solve the fundamental tension of needing two branches checked out at once. Instead of stashing, cloning, or juggling directories, worktrees give you parallel workspaces from a single repo — ideal for review, hotfixes, and context switching.

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.

#git #version-control #git-stash

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 #staging #git-add

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.

#git #version-control #aliases