
Using Git Worktrees
- 93 installs
- 6 repo stars
- Updated July 22, 2026
- julianobarbosa/claude-code-skills
Git worktree management with tmux integration and task dispatch. Use when creating isolated environments, launching parallel work, running multiple Claude instances.
About
Git worktree management with tmux integration and task dispatch.. Use for isolated dev environments, parallel feature work, multiple Claude instances, task dispatch.
- intermediate skill
- core: git & pull requests
Using Git Worktrees by the numbers
- 93 all-time installs (skills.sh)
- +1 installs in the week ending Aug 2, 2026 (Skillselion tracking)
- Ranked #238 of 733 Git & Pull Requests skills by installs in the Skillselion catalog
- Data as of Aug 3, 2026 (Skillselion catalog sync)
npx skills add https://github.com/julianobarbosa/claude-code-skills --skill using-git-worktreesAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 93 |
|---|---|
| repo stars | ★ 6 |
| Last updated | July 22, 2026 |
| Repository | julianobarbosa/claude-code-skills ↗ |
What it does
Git worktree management with tmux integration and task dispatch. Use when creating isolated environments, launching parallel work, running multiple Claude instances.
Files
Git Worktrees with tmux Integration
Create isolated workspaces, open them in tmux windows within your current session, and dispatch tasks — all in one flow.
Core Flow
1. Create worktree → git worktree add .claude/worktrees/{name} -b {branch}
2. Create tmux window → new window in CURRENT session named {session}-{name}
3. cd into worktree → send-keys to the new window
4. Dispatch task → send-keys with the command to executeWorkflow Routing
| Intent | Action |
|---|---|
| "create worktree for X" | Create → steps 1-3 only |
| "create worktree and run Y" | Create + Dispatch → steps 1-4 |
| "clean up worktree X" | Cleanup → remove worktree + tmux window + optionally delete branch |
| "list worktrees" | Show git worktree list |
| "analyze for parallelization" | Read references/bmad-orchestration.md for BMAD-specific dependency analysis |
| "merge worktree branches" | Read references/bmad-orchestration.md for merge workflow |
Step 1: Create Worktree
Safety Check
Before creating, verify .claude/worktrees/ is git-ignored:
# Check if ignored (test with a hypothetical file)
git check-ignore .claude/worktrees/test 2>/dev/nullIf NOT ignored, add to .gitignore immediately:
echo ".claude/worktrees/" >> .gitignore
# Stage and commit the gitignore changeCreate
REPO_ROOT=$(git rev-parse --show-toplevel)
WORKTREE_NAME="the-feature-name"
BRANCH_NAME="feature/the-feature-name" # or bmad/story-1-3 etc.
BASE_BRANCH="main" # or current branch
mkdir -p "$REPO_ROOT/.claude/worktrees"
git worktree add "$REPO_ROOT/.claude/worktrees/$WORKTREE_NAME" -b "$BRANCH_NAME" "$BASE_BRANCH"Verify
git worktree listStep 2: Create tmux Window
Create a new window in the current tmux session (not a new session). The window name follows the pattern {current-session-name}-{worktree-name} so it's easy to identify.
# Get current tmux session name
SESSION=$(tmux display-message -p '#S')
WINDOW_NAME="${SESSION}-${WORKTREE_NAME}"
WORKTREE_PATH="$REPO_ROOT/.claude/worktrees/$WORKTREE_NAME"
# Create window in current session, starting in worktree directory
tmux new-window -t "$SESSION" -n "$WINDOW_NAME" -c "$WORKTREE_PATH"Step 3: Ensure Working Directory
The -c flag in step 2 already sets the initial directory, but if you need to explicitly cd (e.g., shell profile overrides it):
tmux send-keys -t "${SESSION}:${WINDOW_NAME}" "cd '$WORKTREE_PATH'" EnterStep 4: Dispatch Task (Optional)
Send a command to the new tmux window:
# Example: launch Claude Code with a task
tmux send-keys -t "${SESSION}:${WINDOW_NAME}" "claude 'your task here'" Enter
# Example: run a BMAD skill
tmux send-keys -t "${SESSION}:${WINDOW_NAME}" "claude '/bmad-create-story story 1-3'" Enter
# Example: run any shell command
tmux send-keys -t "${SESSION}:${WINDOW_NAME}" "make test" EnterFor unattended execution (no permission prompts):
tmux send-keys -t "${SESSION}:${WINDOW_NAME}" "claude --dangerously-skip-permissions 'your task'" EnterImportant: Only use --dangerously-skip-permissions if the user explicitly requests it.
Cleanup Workflow
After work is complete and merged:
WORKTREE_NAME="the-feature-name"
REPO_ROOT=$(git rev-parse --show-toplevel)
SESSION=$(tmux display-message -p '#S')
# 1. Kill the tmux window
tmux kill-window -t "${SESSION}:${SESSION}-${WORKTREE_NAME}" 2>/dev/null
# 2. Remove the git worktree
git worktree remove "$REPO_ROOT/.claude/worktrees/$WORKTREE_NAME"
# 3. Optionally delete the branch (only if merged)
git branch -d "$BRANCH_NAME" 2>/dev/null
# 4. Prune stale worktree references
git worktree pruneQuick Reference
| Situation | Action |
|---|---|
.claude/worktrees/ exists | Use it (verify ignored) |
Not in .gitignore | Add .claude/worktrees/ and commit |
| Not in tmux | Skip tmux steps, just create worktree and report path |
| Branch already exists | Use git worktree add <path> <existing-branch> (no -b) |
| Worktree path exists | Report error, ask user to remove or pick different name |
Naming Conventions
| Element | Pattern | Example |
|---|---|---|
| Worktree directory | .claude/worktrees/{name} | .claude/worktrees/story-1-3 |
| Branch | {convention}/{name} | bmad/story-1-3-deploy-nat-gateway |
| tmux window | {session}-{name} | hypera-golden-image-story-1-3 |
The branch naming convention depends on the project. Check CLAUDE.md for project-specific patterns (e.g., bmad/story-{id} for BMAD projects).
Troubleshooting
Branch already checked out:
# Another worktree has this branch — remove it first or use a different name
git worktree list # find which worktree has the branchtmux window name conflict:
# Rename or kill the conflicting window
tmux kill-window -t "session:conflicting-name" 2>/dev/nullWorktree not in .gitignore after adding:
# .gitignore uses directory patterns — ensure trailing slash
# Check with: git check-ignore .claude/worktrees/testfileReferences
- WORKFLOW.md — Detailed step-by-step workflow with edge cases
- references/bmad-orchestration.md — BMAD sprint parallelization, dependency analysis, and merge workflows
- references/tmux-integration.md — Advanced tmux configuration for worktrees
- scripts/setup-worktree.sh — Shell script for automated worktree setup
---
Gotchas
- `.claude/worktrees/` conflicts with `.gitignore` defaults — must explicitly ignore it or the parent repo sees worktree files as untracked.
- tmux session names with worktree paths hit filename length limits — use short branch-based names or the socket path errors.
- Concurrent `git status` across worktrees can fail with index.lock errors — git locks the index per-repo, not per-worktree.
- BMAD-specific parallel work assumes disjoint files: overlapping edits across stories cause merge headaches at integration.
- Shell prompts that read git branch via the worktree path can be slow — disable expensive prompt parts in worktrees.
BMAD Sprint Orchestration
Extends the core worktree skill with BMAD-specific parallelization analysis, execution, and merge workflows.
Analyze: Find Parallelization Opportunities
Step 1: Load Sprint State
Read {project-root}/_bmad-output/implementation-artifacts/sprint-status.yamlIdentify:
- Which epic is
in-progress - Which stories are
backlogorready-for-dev(candidates) - Which stories are
doneorin-progress
Cross-validate: if a story file exists, compare its Status: header to sprint-status.yaml. Story file is source of truth.
Step 2: Load Epic Definitions
Read {project-root}/_bmad-output/planning-artifacts/epics.mdFor each candidate story, extract:
- Acceptance criteria (look for cross-story references like "Given X from Story N.M")
- Infrastructure domain (Terraform, Kubernetes, Helm, etc.)
Step 3: Build Dependency Graph
Independent (parallelizable):
- Different infrastructure domains
- Create separate files with no overlap
- No cross-references in acceptance criteria
- Don't modify the same Terraform state
Dependent (sequential):
- Story B references Story A's outputs
- Both modify the same files
- One extends what the other creates
- Shared Terraform state with
terraform apply
Step 4: Design Phase Plan
Phase 1 (parallel): [items with no dependencies on each other]
Phase 2 (parallel): [items depending on Phase 1 but not each other]
Final: [Retrospective, sprint status update]BMAD Workflow Parallelization
| BMAD Step | Parallelizable? | Notes |
|---|---|---|
| Create Story (CS) | YES | Spec files are independent |
| Dev Story (DS) | CONDITIONAL | Only if stories are independent |
| Code Review (CR) | YES | Reviews are per-story |
| Retrospective (ER) | NO | Requires all stories done |
Execute: Launch Parallel Worktrees
Uses the core worktree skill's Create flow for each parallel item:
- Worktree naming:
.claude/worktrees/wt-{story-id} - Branch naming:
bmad/story-{story-id} - tmux window naming:
{session}-wt-{story-id}
Execution State Tracking
Create a tracking file:
# .claude/worktrees/execution-state.yaml
phase: 1
epic: 4
worktrees:
- path: .claude/worktrees/wt-4-2
branch: bmad/story-4-2
command: /bmad-create-story
story: "CI Pipeline Setup"
status: running
- path: .claude/worktrees/wt-4-4
branch: bmad/story-4-4
command: /bmad-create-story
story: "Monitoring Stack"
status: runningMerge: Combine Parallel Branches
Step 1: Verify All Worktrees Complete
for wt in .claude/worktrees/wt-*; do
branch=$(cd "$wt" && git rev-parse --abbrev-ref HEAD)
commits=$(git log --oneline main.."$branch" | wc -l)
echo "$branch: $commits commits"
doneStep 2: Merge in Dependency Order
Independent stories first, then dependent ones:
git checkout main
git merge bmad/story-{id} --no-ff -m "feat: merge story {id} - {title}"Step 3: Handle Conflicts
sprint-status.yaml (always conflicts):
- Accept ALL story status changes (different lines, always safe)
- Keep the latest
generateddate
Terraform files (additive modules):
- Accept both module blocks
- Verify no duplicate resource names
- Run
terraform validate
Step 4: Cleanup
# Remove worktrees
for wt in .claude/worktrees/wt-*; do
git worktree remove "$wt"
done
# Delete branches
git branch -d bmad/story-{id} # repeat for each
# Remove tracking
rm -f .claude/worktrees/execution-state.yaml
# Kill tmux windows
# (handled by core cleanup workflow)Dependency Patterns Reference
Infrastructure Domain Classification
| Domain | Indicators |
|---|---|
| Terraform Networking | VNet, subnets, NSG, NAT Gateway |
| Terraform Compute | VMs, AKS, node pools |
| Terraform Security | Key Vault, managed identities |
| Kubernetes/Helm | Helm charts, K8s manifests |
| Azure DevOps | Pipeline YAML, build definitions |
| Container Images | Dockerfiles, ACR |
| Observability | Grafana, Prometheus |
Conflict Hotspots
| File | Resolution |
|---|---|
sprint-status.yaml | Accept all status changes (different lines) |
terraform/main.tf | Accept both module blocks (additive) |
terraform/variables.tf | Accept both variable blocks (additive) |
terraform/providers.tf | Deduplicate, keep one copy |
terraform/backend.tf | Should NOT differ — flag if it does |
Terraform State Considerations
Most projects use a single shared state file. This means:
- Steps that DON'T run
terraform apply(Create Story, Code Review) are always safe to parallelize - Steps that DO run
terraform applymust be serialized (state lock contention) - Stories touching non-Terraform domains (Helm, K8s, pipelines) remain fully parallelizable
tmux Integration for Worktrees
Advanced tmux configuration and shell functions for worktree management.
Recommended tmux.conf Settings
# Prevent automatic window renaming (keeps worktree names stable)
set-option -g automatic-rename off
set-option -g allow-rename off
# Start windows at 1
set -g base-index 1
setw -g pane-base-index 1
# Renumber windows when one is closed
set -g renumber-windows on
# Status bar showing git branch and path
set -g status-right '#[fg=cyan]#(cd #{pane_current_path}; git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "no git") #[fg=white]| #[fg=yellow]#{pane_current_path}'
set -g status-right-length 120
set -g status-interval 5
# Quick window switching with Alt+number
bind -n M-1 select-window -t 1
bind -n M-2 select-window -t 2
bind -n M-3 select-window -t 3
bind -n M-4 select-window -t 4
bind -n M-5 select-window -t 5Worktree-Specific Bindings
# List worktrees in a popup
bind G display-popup -E "git worktree list | less"
# Switch to worktree window using fzf
bind f display-popup -E "tmux list-windows -F '#W' | fzf --reverse | xargs tmux select-window -t"
# Split and cd to same worktree
bind | split-window -h -c "#{pane_current_path}"
bind - split-window -v -c "#{pane_current_path}"Shell Functions
Add to ~/.zshrc or ~/.bashrc:
# Create worktree with tmux window in current session
wt() {
local name="$1"
local base_branch="${2:-main}"
local repo_root=$(git rev-parse --show-toplevel 2>/dev/null)
if [[ -z "$repo_root" ]]; then
echo "Error: Not in a git repository"
return 1
fi
local worktree_path="$repo_root/.claude/worktrees/$name"
mkdir -p "$repo_root/.claude/worktrees"
# Create worktree
if git worktree add -b "$name" "$worktree_path" "$base_branch" 2>/dev/null; then
echo "Created worktree: $name"
elif git worktree add "$worktree_path" "$name" 2>/dev/null; then
echo "Attached to existing branch: $name"
else
echo "Error: Failed to create worktree"
return 1
fi
# tmux window in current session
if [[ -n "$TMUX" ]]; then
local session=$(tmux display-message -p '#S')
tmux new-window -n "${session}-${name}" -c "$worktree_path"
echo "Created tmux window: ${session}-${name}"
else
cd "$worktree_path"
fi
}
# Remove worktree and tmux window
wt-rm() {
local name="$1"
local repo_root=$(git rev-parse --show-toplevel 2>/dev/null)
local worktree_path="$repo_root/.claude/worktrees/$name"
git worktree remove "$worktree_path" --force 2>/dev/null
if [[ -n "$TMUX" ]]; then
local session=$(tmux display-message -p '#S')
tmux kill-window -t "${session}-${name}" 2>/dev/null
fi
git branch -d "$name" 2>/dev/null
echo "Removed worktree: $name"
}
# List worktrees
wt-ls() { git worktree list; }
# Status of all worktrees
wt-status() {
git worktree list | while read -r line; do
local wt_path=$(echo "$line" | awk '{print $1}')
local wt_branch=$(echo "$line" | awk '{print $3}' | tr -d '[]')
local status=$(cd "$wt_path" 2>/dev/null && git status --porcelain | wc -l | tr -d ' ')
if [[ "$status" -gt 0 ]]; then
echo "$wt_branch: $status uncommitted changes"
else
echo "$wt_branch: clean"
fi
done
}
# Cleanup merged worktrees
wt-cleanup-merged() {
git worktree list | tail -n +2 | while read -r line; do
local wt_path=$(echo "$line" | awk '{print $1}')
local wt_branch=$(echo "$line" | awk '{print $3}' | tr -d '[]')
if git branch --merged main 2>/dev/null | grep -q "$wt_branch"; then
echo "Removing merged: $wt_branch"
git worktree remove "$wt_path" --force 2>/dev/null
git branch -d "$wt_branch" 2>/dev/null
fi
done
}Shell Completions (zsh)
_wt_completion() {
local branches=$(git branch --format='%(refname:short)' 2>/dev/null)
local worktrees=$(git worktree list --porcelain 2>/dev/null | grep '^worktree' | cut -d' ' -f2 | xargs -I{} basename {} 2>/dev/null)
_alternative \
"branches:branch:($branches)" \
"worktrees:worktree:($worktrees)"
}
compdef _wt_completion wt wt-rm#!/bin/bash
# Create a git worktree with tmux window in the current session
# Usage: setup-worktree.sh <worktree-name> [branch-name] [base-branch] [task-command]
#
# Examples:
# setup-worktree.sh story-1-3 bmad/story-1-3 main
# setup-worktree.sh story-1-3 bmad/story-1-3 main "claude '/bmad-create-story 1-3'"
set -euo pipefail
WORKTREE_NAME="${1:?Usage: setup-worktree.sh <name> [branch] [base-branch] [task-command]}"
BRANCH_NAME="${2:-$WORKTREE_NAME}"
BASE_BRANCH="${3:-main}"
TASK_COMMAND="${4:-}"
# Ensure we're in a git repo
REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null) || {
echo "Error: Not in a git repository"
exit 1
}
WORKTREE_DIR="$REPO_ROOT/.claude/worktrees"
WORKTREE_PATH="$WORKTREE_DIR/$WORKTREE_NAME"
# Create worktree directory
mkdir -p "$WORKTREE_DIR"
# Ensure .gitignore includes worktree dir
if ! git check-ignore -q "$WORKTREE_DIR/test" 2>/dev/null; then
echo ".claude/worktrees/" >>"$REPO_ROOT/.gitignore"
echo "Added .claude/worktrees/ to .gitignore"
fi
# Check if worktree already exists
if [ -d "$WORKTREE_PATH" ]; then
echo "Error: Worktree already exists at $WORKTREE_PATH"
exit 1
fi
# Create worktree
echo "Creating worktree: $WORKTREE_NAME (branch: $BRANCH_NAME from $BASE_BRANCH)"
git worktree add "$WORKTREE_PATH" -b "$BRANCH_NAME" "$BASE_BRANCH"
# Auto-detect and run project setup
cd "$WORKTREE_PATH"
if [ -f "package.json" ]; then
echo "Installing npm dependencies..."
npm install --silent 2>/dev/null || true
elif [ -f "go.mod" ]; then
echo "Downloading Go modules..."
go mod download 2>/dev/null || true
elif [ -f "pyproject.toml" ]; then
echo "Installing Python dependencies..."
uv sync 2>/dev/null || pip install -e ".[dev]" 2>/dev/null || true
elif [ -f "Cargo.toml" ]; then
echo "Building Rust project..."
cargo build 2>/dev/null || true
fi
# tmux integration
if [ -n "${TMUX:-}" ]; then
SESSION=$(tmux display-message -p '#S')
WINDOW_NAME="${SESSION}-${WORKTREE_NAME}"
# Create window in current session
tmux new-window -t "$SESSION" -n "$WINDOW_NAME" -c "$WORKTREE_PATH"
echo "Created tmux window: $WINDOW_NAME"
# Dispatch task if provided
if [ -n "$TASK_COMMAND" ]; then
sleep 0.5 # Brief pause for shell init
tmux send-keys -t "${SESSION}:${WINDOW_NAME}" "$TASK_COMMAND" Enter
echo "Dispatched: $TASK_COMMAND"
fi
else
echo "Not in tmux — skipping window creation"
fi
echo ""
echo "Worktree ready at: $WORKTREE_PATH"
echo "Branch: $BRANCH_NAME"
Git Worktrees Workflow
Detailed step-by-step for creating worktrees with tmux integration and task dispatch.
Phase 1: Pre-flight Checks
1.1 Verify Git Repository
REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)
if [ -z "$REPO_ROOT" ]; then
echo "Error: Not in a git repository"
exit 1
fi1.2 Verify tmux Session
if [ -z "$TMUX" ]; then
echo "Warning: Not in a tmux session — tmux window creation will be skipped"
TMUX_AVAILABLE=false
else
SESSION=$(tmux display-message -p '#S')
TMUX_AVAILABLE=true
fi1.3 Ensure Worktree Directory is Ignored
mkdir -p "$REPO_ROOT/.claude/worktrees"
# Test if the directory is ignored
if ! git check-ignore -q "$REPO_ROOT/.claude/worktrees/test" 2>/dev/null; then
# Add to .gitignore
echo ".claude/worktrees/" >> "$REPO_ROOT/.gitignore"
echo "Added .claude/worktrees/ to .gitignore"
# Note: Don't auto-commit — let the user decide
fi1.4 Verify Clean State (Optional)
If creating worktrees for parallel work, a clean working tree avoids confusion:
if [ -n "$(git status --porcelain)" ]; then
echo "Warning: Working tree has uncommitted changes"
echo "Worktree creation will proceed, but consider committing first"
fiPhase 2: Create Worktree
2.1 Determine Parameters
Required:
WORKTREE_NAME— short identifier (e.g.,story-1-3)BRANCH_NAME— git branch name (e.g.,bmad/story-1-3-deploy-nat-gateway)BASE_BRANCH— branch to fork from (e.g.,main, current branch)
2.2 Create
WORKTREE_PATH="$REPO_ROOT/.claude/worktrees/$WORKTREE_NAME"
# Check if path already exists
if [ -d "$WORKTREE_PATH" ]; then
echo "Error: Worktree already exists at $WORKTREE_PATH"
echo "Remove it first: git worktree remove $WORKTREE_PATH"
exit 1
fi
# Create with new branch
git worktree add "$WORKTREE_PATH" -b "$BRANCH_NAME" "$BASE_BRANCH"
# Or attach to existing branch
# git worktree add "$WORKTREE_PATH" "$BRANCH_NAME"2.3 Project Setup (Auto-detect)
cd "$WORKTREE_PATH"
# Node.js
[ -f package.json ] && npm install
# Python
[ -f pyproject.toml ] && uv sync 2>/dev/null || pip install -e ".[dev]" 2>/dev/null
[ -f requirements.txt ] && pip install -r requirements.txt
# Go
[ -f go.mod ] && go mod download
# Rust
[ -f Cargo.toml ] && cargo build2.4 Verify
git worktree list
echo "Worktree ready at: $WORKTREE_PATH"
echo "Branch: $BRANCH_NAME (based on $BASE_BRANCH)"Phase 3: tmux Window
Skip this phase if TMUX_AVAILABLE=false.
3.1 Create Window
WINDOW_NAME="${SESSION}-${WORKTREE_NAME}"
# Create window in current session, starting in worktree directory
tmux new-window -t "$SESSION" -n "$WINDOW_NAME" -c "$WORKTREE_PATH"
echo "Created tmux window: $WINDOW_NAME in session $SESSION"3.2 Verify Directory
# The -c flag should handle this, but verify
tmux send-keys -t "${SESSION}:${WINDOW_NAME}" "pwd" EnterPhase 4: Dispatch Task (Optional)
Only execute if the user provided a task/command to run.
4.1 Send Command
TASK_COMMAND="claude '/bmad-create-story story 1-3'" # example
tmux send-keys -t "${SESSION}:${WINDOW_NAME}" "$TASK_COMMAND" Enter
echo "Dispatched task to window $WINDOW_NAME"4.2 Monitor
The user can switch to the window to monitor progress:
Ctrl-bthen window number to switchtmux select-window -t "${SESSION}:${WINDOW_NAME}"from another pane
Phase 5: Cleanup
After work is done and merged back.
5.1 Kill tmux Window
tmux kill-window -t "${SESSION}:${WINDOW_NAME}" 2>/dev/null5.2 Remove Worktree
git worktree remove "$WORKTREE_PATH"5.3 Delete Branch (if merged)
git branch -d "$BRANCH_NAME" 2>/dev/null5.4 Prune
git worktree pruneEdge Cases
Multiple Worktrees in Parallel
Create each one sequentially — each gets its own tmux window:
for story in "1-3" "1-4" "2-1"; do
# Each iteration creates worktree + tmux window
# Use unique WORKTREE_NAME and BRANCH_NAME per story
doneWorktree from Remote Branch
git fetch origin
git worktree add "$WORKTREE_PATH" "origin/feature-branch"Resume After Disconnect
Worktrees persist across tmux detach/reattach. If the tmux window was lost:
# Recreate window for existing worktree
tmux new-window -t "$SESSION" -n "$WINDOW_NAME" -c "$WORKTREE_PATH"