Git Worktree Workflow
Create and manage isolated git worktrees for parallel development with automatic permission inheritance.
Permission Handling
Claude Code permissions work as follows in worktrees:
| Settings File | Location | Behavior in Worktrees |
|---|---|---|
.claude/settings.json | Project (committed) | Automatically inherited - shared via git |
.claude/settings.local.json | Project (gitignored) | Not inherited - must be copied manually |
~/.claude/settings.json | User global | Always available in all worktrees |
Key insight: If your team's permissions are in .claude/settings.json (committed), all worktrees automatically get them with zero additional setup.
Creating a Worktree
Step 1: Gather Information
If not already clear, ask:
- •Feature name: What are you working on? (will be used for branch/directory name)
- •Base branch: Create from main/master or another branch?
Step 2: Verify Prerequisites
# Ensure we're in a git repository
git rev-parse --show-toplevel || { echo "Not a git repository"; exit 1; }
# Check for uncommitted changes that might cause issues
git status --porcelain
Step 3: Create the Worktree
# Set up variables
REPO_ROOT=$(git rev-parse --show-toplevel)
REPO_NAME=$(basename "$REPO_ROOT")
PARENT_DIR=$(dirname "$REPO_ROOT")
FEATURE_NAME="<kebab-case-feature-name>" # e.g., add-auth, fix-pagination
BASE_BRANCH="${BASE_BRANCH:-main}" # or master, develop, etc.
# Create worktree with new branch
WORKTREE_PATH="$PARENT_DIR/$REPO_NAME-$FEATURE_NAME"
git worktree add "$WORKTREE_PATH" -b "$FEATURE_NAME" "$BASE_BRANCH"
Step 4: Copy Local Settings (if they exist)
# Copy local settings if present (these are gitignored so not shared automatically)
if [ -f "$REPO_ROOT/.claude/settings.local.json" ]; then
mkdir -p "$WORKTREE_PATH/.claude"
cp "$REPO_ROOT/.claude/settings.local.json" "$WORKTREE_PATH/.claude/"
echo "Copied .claude/settings.local.json to worktree"
fi
Step 5: Initialize Environment
Detect and run appropriate setup commands:
cd "$WORKTREE_PATH"
# Node.js projects
if [ -f "package-lock.json" ]; then
npm ci # or npm install
elif [ -f "yarn.lock" ]; then
yarn install --frozen-lockfile
elif [ -f "pnpm-lock.yaml" ]; then
pnpm install --frozen-lockfile
elif [ -f "bun.lockb" ]; then
bun install
# Python projects
elif [ -f "requirements.txt" ]; then
# Suggest virtual environment
echo "Python project detected. Consider:"
echo " python -m venv .venv && source .venv/bin/activate && pip install -r requirements.txt"
elif [ -f "pyproject.toml" ]; then
# Poetry or other Python build system
if command -v poetry &> /dev/null && grep -q "\[tool.poetry\]" pyproject.toml; then
poetry install
elif command -v uv &> /dev/null; then
uv sync
fi
# Go projects
elif [ -f "go.mod" ]; then
go mod download
# Rust projects
elif [ -f "Cargo.toml" ]; then
cargo fetch
fi
Step 6: Confirm Setup
echo "" echo "Worktree created successfully!" echo " Directory: $WORKTREE_PATH" echo " Branch: $FEATURE_NAME" echo " Based on: $BASE_BRANCH" echo "" echo "To start working:" echo " cd $WORKTREE_PATH" echo " claude"
Managing Worktrees
List All Worktrees
git worktree list
Switch to an Existing Worktree
# Just cd to the worktree directory cd "$PARENT_DIR/$REPO_NAME-<feature-name>"
Check Worktree Status
# From any worktree, list all with status git worktree list --porcelain
Completing Work
After Making Changes
- •
Commit your changes:
bashgit add -A git commit -m "feat: description of changes"
- •
Push the branch:
bashgit push -u origin "$FEATURE_NAME"
- •
Create a PR (optional):
bashgh pr create --fill
Cleanup
# Return to main repository cd "$PARENT_DIR/$REPO_NAME" # Remove the worktree (use -f if there are uncommitted changes) git worktree remove "$WORKTREE_PATH" # If branch was merged, delete it git branch -d "$FEATURE_NAME"
Bulk Cleanup (remove stale worktrees)
# Preview what would be pruned git worktree prune --dry-run # Actually prune stale worktree entries git worktree prune
Error Handling
Worktree Already Exists
# Check if worktree exists
if git worktree list | grep -q "$FEATURE_NAME"; then
echo "Worktree for '$FEATURE_NAME' already exists."
# Offer: reuse existing, create with suffix, or abort
fi
Branch Already Exists
# If branch exists but no worktree, use it git worktree add "$WORKTREE_PATH" "$FEATURE_NAME" # Or create with a unique suffix git worktree add "$WORKTREE_PATH-2" -b "$FEATURE_NAME-2" "$BASE_BRANCH"
Dirty Worktree During Removal
# Force remove (discards uncommitted changes!) git worktree remove --force "$WORKTREE_PATH"
Best Practices
- •
Permission Setup: Put common tool permissions in
.claude/settings.json(committed) so all worktrees inherit them automatically - •
Naming Convention: Use descriptive names like
repo-feature-auth,repo-fix-login-bug - •
Environment Variables: Keep
.envfiles consistent or copy them to new worktrees - •
Session Isolation: Each worktree gets its own Claude Code session context - use
/resumeto see sessions from all worktrees in the same repo - •
Cleanup Regularly: Remove worktrees after PRs are merged to avoid confusion
Quick Reference
| Task | Command |
|---|---|
| Create worktree | git worktree add ../repo-feature -b feature main |
| List worktrees | git worktree list |
| Remove worktree | git worktree remove ../repo-feature |
| Prune stale | git worktree prune |
| Lock worktree | git worktree lock ../repo-feature |
| Unlock worktree | git worktree unlock ../repo-feature |