Git Worktree Management
Overview
Git worktrees enable isolated development by creating separate working directories for different branches. This skill teaches the default workflow for all feature and bugfix development: always create a worktree before starting work on a new branch.
Core principle: Never use git checkout or git switch for feature/bugfix work. Always create a worktree instead.
CRITICAL: Script Invocation
EVERY SINGLE workbranch command MUST be invoked with the FULL path:
${CLAUDE_PLUGIN_ROOT}/scripts/wb new feature-x
${CLAUDE_PLUGIN_ROOT}/scripts/wb list
${CLAUDE_PLUGIN_ROOT}/scripts/wb status
NEVER EVER run bare wb commands - they will fail with "command not found". The ${CLAUDEPLUGINROOT} prefix is MANDATORY and non-negotiable.
When you see wb new, wb list, wb done, etc. in this document, you MUST execute them as:
- ✅
${CLAUDEPLUGINROOT}/scripts/wb new <branch>
- ✅
${CLAUDEPLUGINROOT}/scripts/wb list
- ✅
${CLAUDEPLUGINROOT}/scripts/wb done <branch>
- ❌ NEVER:
wb new <branch>
- ❌ NEVER:
wb list
- ❌ NEVER:
wb done <branch>
Output Control Flags
All workbranch commands support these flags to control output verbosity:
--verbose
Show detailed output including git commands and progress steps. Use when:
- Debugging issues or understanding what went wrong
- Learning how the commands work
- Investigating git operations
Default behavior suppresses detailed output to reduce token usage by 60-80%.
--json
Output structured JSON instead of text. Use when:
- Need machine-readable output
- Integrating with other tools
- Parsing results programmatically
Examples
# Default: minimal output
${CLAUDE_PLUGIN_ROOT}/scripts/wb new feature-x
# Verbose: see all git commands and progress
${CLAUDE_PLUGIN_ROOT}/scripts/wb new feature-x --verbose
# JSON: structured output
${CLAUDE_PLUGIN_ROOT}/scripts/wb list --json
# Combine with other flags
${CLAUDE_PLUGIN_ROOT}/scripts/wb done --skip-merge --verbose
When Claude should use verbose mode:
- When a command fails and more context is needed
- When asked to explain what the command does
- When troubleshooting or investigating issues
When Claude should NOT use verbose mode:
- Normal operations (creates unnecessary token consumption)
- When user hasn't explicitly requested details
When to Use Worktrees
Create a worktree for:
- Any new feature development
- Any bug fix work
- Any branch that will have ongoing work
- Experimental changes that need isolation
The only exceptions:
- Quick one-line fixes that can be committed immediately
- Viewing code on another branch temporarily (read-only)
Commands
The workbranch plugin provides scripts that MUST be invoked via ${CLAUDEPLUGINROOT}/scripts/wb:
REMINDER: Every command below REQUIRES the ${CLAUDEPLUGINROOT}/scripts/ prefix!
Create Worktree: ${CLAUDEPLUGINROOT}/scripts/wb new
Create a new worktree for a branch:
${CLAUDE_PLUGIN_ROOT}/scripts/wb new <branch-name> [source-branch]
IMPORTANT: You MUST use the full path ${CLAUDEPLUGINROOT}/scripts/wb new - do NOT run wb new.
- If branch exists, checks it out in a new worktree
- If branch doesn't exist, creates it from source-branch (default: current HEAD)
- Copies config files based on
.workbranch configuration
- Runs post-create commands (e.g.,
npm install)
Example usage:
# Create worktree for new feature
${CLAUDE_PLUGIN_ROOT}/scripts/wb new feature-user-auth
# Create worktree from specific branch
${CLAUDE_PLUGIN_ROOT}/scripts/wb new hotfix-login-bug main
List Worktrees: ${CLAUDEPLUGINROOT}/scripts/wb list
Show all worktrees with their status:
${CLAUDE_PLUGIN_ROOT}/scripts/wb list
# JSON output for programmatic use
${CLAUDE_PLUGIN_ROOT}/scripts/wb list --json
IMPORTANT: You MUST use the full path ${CLAUDEPLUGINROOT}/scripts/wb list - do NOT run wb list.
Output includes:
- Worktree path
- Branch name
- Ahead/behind count vs default branch
Run this to check existing worktrees before creating new ones.
Pre-flight Check: ${CLAUDEPLUGINROOT}/scripts/wb status
Check current location before making changes:
${CLAUDE_PLUGIN_ROOT}/scripts/wb status
IMPORTANT: You MUST use the full path ${CLAUDEPLUGINROOT}/scripts/wb status - do NOT run wb status.
Output fields:
- LOCATION:
main or worktree
- BRANCH: Current branch name
- DEFAULT_BRANCH: Repository default (main/master)
- ON_DEFAULT: Whether on default branch
- WORKTREE_PATH: Current worktree path
- MAIN_WORKTREE: Main worktree path
- DIRTY: Whether uncommitted changes exist
Options:
--verbose: Show detailed output
--json: JSON output for programmatic use
--check-main: Exit 0 if on main, 1 otherwise
--check-worktree: Exit 0 if in worktree, 1 otherwise
Pre-flight pattern:
${CLAUDE_PLUGIN_ROOT}/scripts/wb status
# If LOCATION: main and ON_DEFAULT: true, run 'wb new <branch>' first
Remove Worktree: ${CLAUDEPLUGINROOT}/scripts/wb rm
Remove a worktree when done:
${CLAUDE_PLUGIN_ROOT}/scripts/wb rm <worktree-path> [--delete-branch]
IMPORTANT: You MUST use the full path ${CLAUDEPLUGINROOT}/scripts/wb rm - do NOT run wb rm.
- Removes the worktree directory
- With
--delete-branch: also deletes the branch (only if merged)
- Fails if worktree has uncommitted changes
Rescue Changes from Main: ${CLAUDEPLUGINROOT}/scripts/wb move
Move uncommitted changes and/or local commits from main to a new worktree:
${CLAUDE_PLUGIN_ROOT}/scripts/wb move <branch-name> [--commits N]
IMPORTANT: You MUST use the full path ${CLAUDEPLUGINROOT}/scripts/wb move - do NOT run wb move.
- Detects uncommitted changes and commits ahead of origin/main
- Stashes uncommitted work, resets main to match remote
- Creates new worktree and applies changes there
- Use
--commits N to move only the last N commits
Example usage:
# Move all divergent changes to a new branch
${CLAUDE_PLUGIN_ROOT}/scripts/wb move feature-login
# Move only the last 2 commits
${CLAUDE_PLUGIN_ROOT}/scripts/wb move hotfix-auth --commits 2
Merge and Cleanup: ${CLAUDEPLUGINROOT}/scripts/wb done
Finish work on a branch by merging to main and cleaning up:
${CLAUDE_PLUGIN_ROOT}/scripts/wb done [branch-name] [options]
IMPORTANT: You MUST use the full path ${CLAUDEPLUGINROOT}/scripts/wb done - do NOT run wb done.
Modes:
${CLAUDEPLUGINROOT}/scripts/wb done <branch> — Run from main worktree, specify branch to merge (recommended)
${CLAUDEPLUGINROOT}/scripts/wb done — Run from feature worktree, infers branch from HEAD (legacy)
Options:
--squash: Squash all commits into one before merging
--rebase: Rebase onto target branch before merging
--skip-merge: Skip merge (use when already merged via PR)
--target <branch>: Target branch to merge into (default: auto-detect)
--keep-remote: Don't delete the remote branch
--dry-run: Show what would be done without executing
--discard-changes: Discard uncommitted changes and force removal (DANGEROUS)
Preferred Usage (from main worktree)
Run from the main worktree with the branch name as argument. This avoids the deleted-directory problem:
# From main worktree
${CLAUDE_PLUGIN_ROOT}/scripts/wb done feature-branch # Standard merge + cleanup
${CLAUDE_PLUGIN_ROOT}/scripts/wb done feature-branch --squash # Squash merge
${CLAUDE_PLUGIN_ROOT}/scripts/wb done feature-branch --skip-merge # Already merged via PR
${CLAUDE_PLUGIN_ROOT}/scripts/wb done feature-branch --dry-run # Preview what would happen
Legacy Usage (from feature worktree)
Running from within a feature worktree still works but requires immediate navigation:
# From feature worktree
${CLAUDE_PLUGIN_ROOT}/scripts/wb done
cd /path/to/main # IMPORTANT: Navigate away immediately!
EXECUTE Output for Claude
When running ${CLAUDEPLUGINROOT}/scripts/wb done from a feature worktree, the script outputs an EXECUTE: line at the end:
EXECUTE: cd /path/to/main/worktree
When you see EXECUTE: in script output, immediately run that command.
Workflow for Feature/Bug Development
Starting Work
- Check existing worktrees: Run
${CLAUDEPLUGINROOT}/scripts/wb list to see current state
- Create worktree: Run
${CLAUDEPLUGINROOT}/scripts/wb new <branch-name> for the feature/fix
- Navigate to worktree: Change to the worktree directory
- Begin development: The worktree is isolated and ready
During Development
- Work proceeds in the worktree directory
- Commits go to the branch associated with that worktree
- Main worktree remains on the default branch, undisturbed
Finishing Work
Use ${CLAUDEPLUGINROOT}/scripts/wb done to complete work on a branch. The recommended approach is to run from the main worktree with the branch name:
# From main worktree (recommended)
${CLAUDE_PLUGIN_ROOT}/scripts/wb done feature-branch
This handles the entire workflow: merge to main, push, remove worktree, and delete branches.
Option A: Direct Merge (Default)
From the main worktree:
${CLAUDE_PLUGIN_ROOT}/scripts/wb done feature-branch # Standard merge
${CLAUDE_PLUGIN_ROOT}/scripts/wb done feature-branch --squash # Squash merge
${CLAUDE_PLUGIN_ROOT}/scripts/wb done feature-branch --rebase # Rebase then merge
Option B: With Pull Request
- Push branch:
git push -u origin <branch-name>
- Create PR: Open a pull request for code review
- After merge: Once the PR is merged, clean up from main worktree:
``bash ${CLAUDEPLUGINROOT}/scripts/wb done feature-branch --skip-merge ``
The --skip-merge flag skips the merge phase (since it's already merged via PR) and just cleans up the worktree and branches.
Legacy: Running from Feature Worktree
You can still run ${CLAUDEPLUGINROOT}/scripts/wb done from within a feature worktree (without a branch argument). In this case, you must navigate away immediately after completion:
# From feature worktree
${CLAUDE_PLUGIN_ROOT}/scripts/wb done
cd /path/to/main # REQUIRED - directory was deleted!
The script outputs EXECUTE: cd /path/to/main which should be run immediately.
Note: For manual cleanup without wb done, use ${CLAUDEPLUGINROOT}/scripts/wb rm <path> --delete-branch. This only deletes branches that have been merged. If you need to abandon unmerged work, use git branch -D <branch> manually after removing the worktree.
Handling Existing WIP Worktrees
When starting work and a worktree already exists for the target branch (from a previous interrupted session):
- Detect: Run
${CLAUDEPLUGINROOT}/scripts/wb list to check for existing worktree
- Ask user: Present options:
- Resume work in existing worktree - Clean up and create fresh worktree
- Act accordingly: Either navigate to existing worktree or remove it first
Never silently create duplicate worktrees or fail without explanation.
Configuration
Projects can customize worktree behavior with a .workbranch file in the project root:
# Files to copy (colon-separated globs)
copy=".env*:.vscode"
# Patterns to ignore when copying
ignore="node_modules:dist:.git"
# Path template ($NAME = branch name)
path="../$NAME"
# Commands to run after worktree creation
post_create="npm install"
# Delete branch when removing worktree (default: false)
delete_branch=false
Configuration Fields
| Field |
Description |
Default |
copy |
Colon-separated file globs to copy |
(none) |
ignore |
Colon-separated patterns to skip |
node_modules:dist:.git |
path |
Worktree path template |
../$NAME |
post_create |
Commands to run after creation |
(none) |
delete_branch |
Auto-delete branch on remove |
false |
If no .workbranch file exists, scripts use sensible defaults.
Error Handling
Scripts return structured error messages:
ERROR: <message> | ACTION: <what to do>
Common errors and actions:
| Error |
Action |
| Not in a git repository |
Navigate to a git repository first |
| Worktree already exists |
Use existing worktree or remove with wb rm |
| Branch already checked out |
Remove the other worktree first |
| Uncommitted changes |
Commit or stash changes, or use --discard-changes to force |
| Cannot delete unmerged branch |
Use git branch -D to force delete |
When an error occurs, read the ACTION portion and follow the guidance.
Important Behaviors
Default to Worktrees
When the user asks to work on a feature or fix a bug:
- First check if they're already in a worktree for that branch
- If not, create a worktree before starting any development
- Don't use
git checkout or git switch for feature branches
Stay in Worktree During Development
Once in a worktree:
- All file edits happen in that worktree
- Commits go to the worktree's branch
- Don't switch back to main worktree until work is complete
Clean Up After Merge
After work is merged (via PR or direct merge):
- Use
${CLAUDEPLUGINROOT}/scripts/wb done for automatic cleanup (preferred)
- Or use
${CLAUDEPLUGINROOT}/scripts/wb rm for manual cleanup
- The
--delete-branch flag safely deletes only merged branches
Recovering from Mistakes on Main
When changes are accidentally made on main instead of a worktree:
- Stop immediately: Don't continue making changes
- Run wb move:
${CLAUDEPLUGINROOT}/scripts/wb move <appropriate-branch-name>
- Navigate to worktree: Move to the new worktree directory
- Continue work: Resume development on the feature branch
This handles both uncommitted changes and local commits that diverged from origin/main.
Script Locations
All scripts are in ${CLAUDEPLUGINROOT}/scripts/:
wb — unified dispatcher (routes to wb-new, wb-list, wb-status, wb-rm, wb-move, wb-done, wb-nuke)
Quick Reference
| Task |
Command |
| Check status (pre-flight) |
${CLAUDEPLUGINROOT}/scripts/wb status |
| List worktrees |
${CLAUDEPLUGINROOT}/scripts/wb list |
| Create worktree |
${CLAUDEPLUGINROOT}/scripts/wb new <branch> |
| Create from branch |
${CLAUDEPLUGINROOT}/scripts/wb new <branch> <source> |
| Finish work (merge + cleanup) |
${CLAUDEPLUGINROOT}/scripts/wb done <branch> (from main) |
| Finish with squash merge |
${CLAUDEPLUGINROOT}/scripts/wb done <branch> --squash (from main) |
| Cleanup after PR merge |
${CLAUDEPLUGINROOT}/scripts/wb done <branch> --skip-merge (from main) |
| Remove worktree |
${CLAUDEPLUGINROOT}/scripts/wb rm <path> |
| Remove + delete branch |
${CLAUDEPLUGINROOT}/scripts/wb rm <path> --delete-branch |
| Rescue changes from main |
${CLAUDEPLUGINROOT}/scripts/wb move <branch> |
| Rescue specific commits |
${CLAUDEPLUGINROOT}/scripts/wb move <branch> --commits N |
Common Issues
"command not found: wb"
Cause: Attempting to run wb commands without ${CLAUDEPLUGINROOT} prefix. This is the MOST COMMON ERROR with this skill.
Solution: ALWAYS use the FULL path - there are NO exceptions:
${CLAUDE_PLUGIN_ROOT}/scripts/wb <command>
If you (Claude) see this error in a Bash tool result:
- You forgot to use the
${CLAUDEPLUGINROOT}/scripts/ prefix
- IMMEDIATELY retry with the correct full path
- Do NOT try alternatives - just add the prefix
Examples of fixing this error:
- ❌ You ran:
wb new feature-x
- ✅ Retry with:
${CLAUDEPLUGINROOT}/scripts/wb new feature-x
The ${CLAUDEPLUGINROOT} variable is only available within Claude Code and is MANDATORY for all workbranch commands.
Plugin Development
When developing the workbranch plugin, use relative paths:
./scripts/wb list
../workbranch/scripts/wb new feature-x