Parallel Git Worktrees with Claude Code: Run Multiple AI Agents Simultaneously
I was stuck. I had Claude Code running in one terminal, happily working on a feature, when I got a Slack notification about a critical bug. I needed to switch context immediately, but I didn’t want to lose my AI assistant’s context. Do I stash? Commit half-done work? Or just open a new terminal and… wait, that won’t work either because they’d both be editing the same files.
This was the moment I realized I needed git worktrees.
The Context Switching Problem
Traditional git branching forces you into sequential work:
- Start feature A, make progress
- Need to fix bug B? Stash or commit A
- Switch branches, fix bug
- Switch back, remember where you were
With Claude Code, this problem compounds. The AI has built up context about your current work—variable names, patterns you’ve established, the direction you’re heading. When you switch branches, all that context is lost. You have to re-explain everything.
I tried multiple solutions:
Attempt 1: Multiple terminals, same directory
- Opened two terminal tabs
- Ran Claude Code in both
- Disaster: Both instances edited the same files simultaneously
- Conflict after conflict
Attempt 2: Git stash dance
- Stash work, switch branches, fix bug
- Switch back, pop stash
- Problem: Lost Claude’s mental model of the code
- Had to re-explain the entire feature context
Attempt 3: Quick commits
- Commit work-in-progress with “WIP” message
- Switch branches, fix bug
- Switch back, amend or reset
- Problem: Dirty git history, and still lost AI context
Then I remembered something from an X thread about Claude Code tips: Boris (the Claude Code creator) and his team use git worktrees with 5+ parallel Claude instances in numbered terminal tabs.
What Are Git Worktrees?
Git worktrees let you have multiple working directories from a single repository. Each worktree:
- Has its own checked-out branch
- Shares the same
.gitdirectory (history, refs, config) - Operates independently of other worktrees
Think of it like this:
Traditional Approach:┌─────────────────────────────────┐│ my-app/ ││ ├── .git/ ││ ├── src/ │ ← Only ONE branch at a time│ └── package.json │└─────────────────────────────────┘
Git Worktrees Approach:┌─────────────────────────────────┐│ my-app/ ││ ├── .git/ │ ← Shared history│ ├── src/ │ ← main branch│ └── package.json │└─────────────────────────────────┘
┌─────────────────────────────────┐│ my-app-auth/ ││ ├── src/ │ ← auth-feature branch│ └── package.json │└─────────────────────────────────┘
┌─────────────────────────────────┐│ my-app-api/ ││ ├── src/ │ ← api-refactor branch│ └── package.json │└─────────────────────────────────┘Each directory is a full working copy. You can have VS Code open in one, Claude Code running in another, and tests executing in a third—all on different branches, all from the same repository.
Setting Up Parallel Claude Code Sessions
Step 1: Create Worktrees for Each Task
I started with a simple structure:
# From my main project directorycd ~/projects/my-app
# Create worktree for auth featuregit worktree add ../my-app-auth -b auth-feature
# Create worktree for API refactorgit worktree add ../my-app-api -b api-refactor
# Create worktree for critical bugfixgit worktree add ../my-app-hotfix -b critical-bugThe -b flag creates a new branch. If you have an existing branch:
git worktree add ../my-app-existing existing-branchStep 2: Open Terminal Tabs for Each Worktree
Here’s where Boris’s team’s numbering strategy comes in:
┌─────────────────────────────────────────┐│ Tab 01: my-app (main branch) │├─────────────────────────────────────────┤│ Tab 02: my-app-auth (auth-feature) │├─────────────────────────────────────────┤│ Tab 03: my-app-api (api-refactor) │├─────────────────────────────────────────┤│ Tab 04: my-app-hotfix (critical-bug) │└─────────────────────────────────────────┘I use a naming convention: ##-project-branch to keep track.
Step 3: Launch Claude Code in Each Tab
# In each terminal tab:cd ~/projects/my-app-authclaude
# Or with specific instructions:claude --instructions "Focus on authentication flow, no API changes"Now I have four independent Claude Code instances, each with its own context, working directory, and focus area.
The Productivity Boost
This changed my workflow completely.
Before: Context switch overhead of 5-15 minutes per switch. Re-explaining to Claude what we were doing. Mental model fragmentation.
After: Instant context availability. Each Claude instance knows exactly what it’s working on. No stash/pop dance.
Here’s how I work now:
Morning:├── Tab 01 (main): Code review, merge PRs├── Tab 02 (auth-feature): Implementing OAuth flow├── Tab 03 (api-refactor): Refactoring REST endpoints└── Tab 04 (hotfix): Emergency bug fix
Afternoon:├── Auth feature done → Merge PR, close tab├── Hotfix deployed → Merge PR, close tab├── Tab 05 (test-coverage): New worktree for tests└── Continue on API refactorThe key insight: I never lose context. Claude in Tab 02 remembers the authentication flow decisions. Claude in Tab 03 knows the API refactor strategy. They don’t interfere with each other.
Common Pitfalls I Hit
Pitfall 1: Too Many Worktrees
I went overboard initially and created 8 worktrees. Bad idea.
- Too many terminal tabs to track
- Disk space usage grew (each worktree has its own
node_modules) - Lost track of which Claude was working on what
Solution: I limit myself to 3-5 active worktrees. When one task is done, I clean it up before creating another.
Pitfall 2: Forgetting to Clean Up
After a month, I had 12 worktrees accumulated from abandoned experiments.
# Check what you havegit worktree list
# My embarrassing output:/home/user/projects/my-app abc123 [main]/home/user/projects/my-app-auth def456 [auth-feature] # merged 2 weeks ago/home/user/projects/my-app-test ghi789 [test-coverage] # abandoned/home/user/projects/my-app-exp1 jkl012 [experiment-1] # ??? no idea...Solution: Weekly cleanup routine:
# Remove worktrees for merged branchesfor wt in $(git worktree list --porcelain | grep "worktree" | cut -d' ' -f2); do branch=$(git -C "$wt" branch --show-current) if git branch --merged main | grep -q "$branch"; then echo "Merged: $branch - removing worktree" git worktree remove "$wt" git branch -d "$branch" fidone
# Clean up any stale referencesgit worktree prunePitfall 3: Shared Build Artifacts
I ran npm install in the main directory, then tried to run the app in a worktree. Didn’t work—each worktree needs its own dependencies.
# In EACH worktree:npm install# orpnpm installThis also means each worktree has its own node_modules directory. Plan for disk space.
Pitfall 4: No Naming Convention
Initially I used random names:
git worktree add ../temp-stuffgit worktree add ../working-heregit worktree add ../testing-thingThree days later, I couldn’t remember which was which.
Solution: Descriptive names with project prefix:
git worktree add ../myapp-auth-featuregit worktree add ../myapp-api-refactorgit worktree add ../myapp-bug-1234A Practical Example: Emergency Hotfix
Here’s how worktrees saved me during a production incident:
Scenario: 2pm, working on a feature branch. Production goes down.
Without worktrees (old way):
- Stash current work
- Commit WIP changes
- Switch to main
- Create hotfix branch
- Fix issue
- Switch back
- Unstash/pop
- Try to remember where I was
With worktrees:
Cmd+Tto open new terminal tabcd ~/projects/myapp-hotfixclaude --instructions "Fix production bug, no new features"- Claude already knows the codebase from shared git history
- Fix, test, commit, push
- Close tab
- Continue in original tab like nothing happened
Time saved: ~20 minutes of context recovery.
Automating Worktree Setup
I created helper scripts to streamline this:
Setup Script
#!/bin/bashPROJECT_NAME="myapp"BASE_DIR=~/projects
# Define worktrees: branch:descriptiondeclare -a WORKTREES=( "auth-feature:Authentication flow improvements" "api-refactor:API endpoint optimization" "test-coverage:Increase test coverage to 80%")
for item in "${WORKTREES[@]}"; do IFS=':' read -r branch desc <<< "$item" worktree_path="$BASE_DIR/${PROJECT_NAME}-${branch}"
echo "Creating worktree: $worktree_path" echo " Branch: $branch" echo " Purpose: $desc"
git worktree add "$worktree_path" -b "$branch"done
echo ""echo "Worktrees created:"git worktree listLaunch Claude Sessions
#!/bin/bash# launch-claude.sh - Open Claude in each worktree
WORKTREES=$(git worktree list --porcelain | grep "worktree" | cut -d' ' -f2)
for wt in $WORKTREES; do branch=$(git -C "$wt" branch --show-current) echo "Opening Claude for: $branch" # macOS Terminal osascript -e "tell application \"Terminal\" to do script \"cd $wt && claude\""doneWhen Worktrees Don’t Make Sense
Worktrees aren’t always the answer. I avoid them for:
- Quick single-file fixes: Not worth the setup
- Docs-only changes: Just switch branches
- Reviewing PRs: Check out the PR branch in main worktree
- Learning/experimenting with small changes: Overkill
Rule of thumb: If I’m going to spend more than 30 minutes on a task, I consider a worktree.
Integration with IDEs
VS Code
Each worktree opens as a separate VS Code window:
# Open worktree in new VS Code windowcode -n ~/projects/myapp-auth-featureI use the VS Code “Project Manager” extension to quickly switch between them.
JetBrains IDEs (IntelliJ, WebStorm)
Same approach—each worktree is a separate project:
# Open in IntelliJidea ~/projects/myapp-auth-featureWhy This Matters for AI-Assisted Development
The real power emerges when combining worktrees with Claude Code:
Traditional development: Sequential, context-switching, mentally draining
Parallel AI development: Concurrent, isolated, context-preserved
Traditional:Time →[Feature A] ──── stash ──── [Bug fix] ──── unstash ──── [Feature A continues] ╰──────────────────────────────────────────────────────────╯ Context switching overhead
Parallel Worktrees:Time →[Feature A] ════════════════════════════════════════════════════▶[Bug fix] ═════════════════════▶[Feature B] ══════════════════════════════════════════════════▶ ╰─────────────────────────────────────────────────────╯ Each Claude instance maintains its own contextSummary
Git worktrees solved my biggest pain point with AI-assisted development: context switching. Instead of losing Claude’s understanding every time I needed to work on something else, I can maintain multiple parallel contexts.
Key practices I follow:
- Limit to 3-5 active worktrees — beyond that, it’s chaos
- Use descriptive names —
project-feature-descriptionformat - Weekly cleanup — remove merged/abandoned worktrees
- Number terminal tabs — matches Boris’s team approach
- Each worktree gets its own dependencies — plan disk space
The setup takes 2-3 minutes, but saves hours of context recovery. When a production issue hits, I can spin up a hotfix worktree, let Claude work its magic, and continue my feature work uninterrupted.
Final Words + More Resources
My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments