Git Worktree Manager
This skill provides a unified interface for managing Git worktrees across your development workflow. Whether you're reviewing PRs in isolation or working on features in parallel, this skill handles all the complexity.
What This Skill Does
- Create worktrees from main branch with clear branch names
- List worktrees with current status
- Switch between worktrees for parallel work
- Clean up completed worktrees automatically
- Interactive confirmations at each step
- Automatic .gitignore management for worktree directory
- Automatic .env file copying from main repo to new worktrees
- Write guard enforcement via PreToolUse hook (
.claude/hooks/worktree-write-guard.sh) -- blocks Write/Edit to main checkout when worktrees exist
CRITICAL: Always Use the Manager Script
NEVER call git worktree add directly. Always use the worktree-manager.sh script.
The script handles critical setup that raw git commands don't:
- Copies
.env,.env.local,.env.test, etc. from main repo - Ensures
.worktreesis in.gitignore - Creates consistent directory structure
- Detects bare repos (
core.bare = true) and derivesGIT_ROOTvia--absolute-git-dirinstead of--show-toplevel - Sources the shared
plugins/soleur/scripts/resolve-git-root.shhelper -- all scripts that needGIT_ROOTshould source this helper instead of inlining their own detection logic
After creating a worktree, run npm install if the project has a package.json — worktrees do not share node_modules/ with the main working tree, and build commands (npx @11ty/eleventy, etc.) will silently hang instead of erroring.
# ✅ CORRECT - Always use the script
bash ${CLAUDE_PLUGIN_ROOT:-./plugins/soleur}/skills/git-worktree/scripts/worktree-manager.sh create feature-name
# ❌ WRONG - Never do this directly
git worktree add .worktrees/feature-name -b feature-name main
When to Use This Skill
Use this skill in these scenarios:
- Code Review (
soleur:review): If NOT already on the target branch (PR branch or requested branch), offer worktree for isolated review - Feature Work (
soleur:work): Always ask if user wants parallel worktree or live branch work - Parallel Development: When working on multiple features simultaneously
- Cleanup: After completing work in a worktree
How to Use
In Claude Code Workflows
The skill is automatically called from the soleur:review and soleur:work skills:
# For review: offers worktree if not on PR branch
# For work: always asks - new branch or worktree?
Manual Usage
You can also invoke the skill directly from bash:
# Create a new worktree (copies .env files automatically)
bash ${CLAUDE_PLUGIN_ROOT:-./plugins/soleur}/skills/git-worktree/scripts/worktree-manager.sh create feature-login
# List all worktrees
bash ${CLAUDE_PLUGIN_ROOT:-./plugins/soleur}/skills/git-worktree/scripts/worktree-manager.sh list
# Switch to a worktree
bash ${CLAUDE_PLUGIN_ROOT:-./plugins/soleur}/skills/git-worktree/scripts/worktree-manager.sh switch feature-login
# Copy .env files to an existing worktree (if they weren't copied)
bash ${CLAUDE_PLUGIN_ROOT:-./plugins/soleur}/skills/git-worktree/scripts/worktree-manager.sh copy-env feature-login
# Clean up completed worktrees
bash ${CLAUDE_PLUGIN_ROOT:-./plugins/soleur}/skills/git-worktree/scripts/worktree-manager.sh cleanup
Commands
create <branch-name> [from-branch]
Creates a new worktree with the given branch name.
Options:
branch-name(required): The name for the new branch. The worktree DIRECTORY is the slug of it — every/becomes-, soci/rule-metricscreates branchci/rule-metricsin.worktrees/ci-rule-metrics. Identical for any name without a slash. Read the path the script prints; do not construct.worktrees/<branch-name>yourself.createrefuses if the target directory already holds a different branch (SOLEUR_WORKTREE_SLUG_COLLISION) — the transform is many-to-one, soci/fooandci-foowould otherwise share one directory.from-branch(optional): Base branch to create from (defaults tomain)
Example:
bash ${CLAUDE_PLUGIN_ROOT:-./plugins/soleur}/skills/git-worktree/scripts/worktree-manager.sh create feature-login
What happens:
- Checks if worktree already exists
- Fetches
refs/remotes/origin/<from-branch>(the local<from-branch>ref is NOT touched — this letscreatesucceed even when a sibling worktree has<from-branch>checked out; see #3741) - Creates the new worktree from
origin/<from-branch>with--no-track(preserves the pre-fix upstream-unset state so downstreamgit push -u origin <branch>flows are unchanged) - Copies all .env files from main repo (.env, .env.local, .env.test, etc.)
- Shows path for cd-ing to the worktree
Opt-in: also update local <from-branch>
Pass --update-local-main (as a global flag, before create) to additionally fast-forward the local <from-branch> ref. Default behavior leaves the local ref untouched.
bash ${CLAUDE_PLUGIN_ROOT:-./plugins/soleur}/skills/git-worktree/scripts/worktree-manager.sh --update-local-main create feature-login
list or ls
Lists all available worktrees with their branches and current status.
Example:
bash ${CLAUDE_PLUGIN_ROOT:-./plugins/soleur}/skills/git-worktree/scripts/worktree-manager.sh list
Output shows:
- Worktree name
- Branch name
- Which is current (marked with ✓)
- Main repo status
switch <name> or go <name>
Switches to an existing worktree and cd's into it.
Example:
bash ${CLAUDE_PLUGIN_ROOT:-./plugins/soleur}/skills/git-worktree/scripts/worktree-manager.sh switch feature-login
Optional:
- If name not provided, lists available worktrees and prompts for selection
cleanup or clean
Interactively cleans up inactive worktrees with confirmation.
Example:
bash ${CLAUDE_PLUGIN_ROOT:-./plugins/soleur}/skills/git-worktree/scripts/worktree-manager.sh cleanup
What happens:
- Lists all inactive worktrees
- Asks for confirmation
- Removes selected worktrees
- Cleans up empty directories
sync-bare-files or sync
Syncs stale on-disk files from git HEAD in a bare repo. Only needed when the repo uses core.bare=true — on-disk files at the bare root become stale after merges since git never updates them. Auto-called after cleanup-merged cleans branches in bare repo context.
Example:
bash ${CLAUDE_PLUGIN_ROOT:-./plugins/soleur}/skills/git-worktree/scripts/worktree-manager.sh sync-bare-files
What it syncs: EVERY tracked file at HEAD — there is no allowlist.
The implementation builds a throwaway index from HEAD and runs git checkout-index -a -f against the bare root, so every path git tracks is materialized. That pass is additive — it never removes anything — so a separate prune step afterwards deletes on-disk leftovers for paths that were tracked once and are absent from HEAD. The two together are what make the bare root equal HEAD exactly. It then re-applies execute bits for the scripts and hooks the plugin loader and SessionStart hooks exec.
Corrected 2026-08-10 (#7409). This section previously enumerated a
seven-entry list (AGENTS.md,plugins/soleur/hooks/,.claude/hooks/.sh,
resolve-git-root.sh, …) and told readers that "any file Claude Code executes
at runtime from the bare repo root must be added to the sync list". Both
halves were wrong: the enumeration described a whitelist the code has not
had, and the instruction sent readers to register files in a list that does
not exist. Worth stating precisely rather than deleting, because the
difference is load-bearing — when #7409 moved the session-state lock/lease
library to plugins/soleur/scripts/lib/, a genuine whitelist would have left
the bare root's repointed `.claude/ho