Skip to main content

git-worktree

Git worktree management for isolated parallel development, and restacking a stack whose branches live in separate worktrees. Use when reviewing PRs in isolation, working on multiple features simultaneously, when workflows offer worktree option, or when a restack fails with already used by worktree.

Source facts

Repository
KingInYellows/yellow-plugins
Last source activity
October 22, 2026 at 16:00
Detected SKILL.md language
English
Stars
0
Forks
0

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
10 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
git-worktree
description
Git worktree management for isolated parallel development, and restacking a stack whose branches live in separate worktrees. Use when reviewing PRs in isolation, working on multiple features simultaneously, when workflows offer worktree option, or when a restack fails with already used by worktree.
argument-hint
[create|list|switch|cleanup] <name>
user-invocable
true
# Git Worktree Manager Manage git worktrees for isolated parallel development with a simple, safe interface. ## What It Does Creates and manages git worktrees — separate working directories from the same repository that allow you to: - Work on multiple branches simultaneously without stashing - Review PRs in complete isolation from your current work - Test features without switching branches in your main working directory - Keep separate .env configurations per worktree ## Critical Rule **ALWAYS use the manager script. NEVER use raw `git worktree add` directly.** The manager script provides: - Automatic .env file copying - .gitignore management - Safety validations - Consistent directory structure - Color-coded output ## Manager Script Location ```bash ${CLAUDE_PLUGIN_ROOT}/skills/git-worktree/scripts/worktree-manager.sh ``` Replace `${CLAUDE_PLUGIN_ROOT}` with the actual plugin installation path. ## Usage ### create Create a new worktree: ```bash worktree-manager.sh create <branch-name> [from-branch] ``` **Behavior:** - Creates worktree in `.worktrees/<branch-name>/` - Branches from `main` by default (or specify `from-branch`) - Copies all `.env*` files from main repo - Adds `.worktrees/` to `.gitignore` if missing - Symlinks the main repo's `.ruvector/` into the worktree if it exists (see [ruvector DB Sharing](#ruvector-db-sharing) below) - Fails safely if worktree already exists **Examples:** ```bash # Create worktree for feature branch worktree-manager.sh create feature-auth # Create worktree from specific branch worktree-manager.sh create hotfix-security develop ``` ### list / ls List all worktrees: ```bash worktree-manager.sh list worktree-manager.sh ls ``` **Output:** ``` Worktrees: main /home/user/repo (clean) feature-auth /home/user/repo/.worktrees/feature-auth (modified) pr-review-123 /home/user/repo/.worktrees/pr-review-123 (clean) ``` ### switch / go Switch to a worktree directory: ```bash worktree-manager.sh switch <name> worktree-manager.sh go <name> ``` **Note:** Prints `cd` command for shell evaluation: ```bash # Use with eval or source eval "$(worktree-manager.sh switch feature-auth)" # Or create shell function wtgo() { eval "$(worktree-manager.sh go "$1")"; } ``` ### copy-env Copy .env files to a worktree: ```bash worktree-manager.sh copy-env <name> ``` Copies all `.env*` files from main repo to specified worktree. Useful if you've updated environment configuration and need to sync. Also repairs a missing `.ruvector/` symlink for worktrees created before that feature existed (see below). ### ruvector DB Sharing When a Claude Code session runs inside a worktree, the ruvector MCP server resolves `${PWD}/.ruvector/` against the worktree path. Because `.ruvector/` is gitignored (`**/.ruvector/`), it is not present in a fresh worktree, so the MCP server and hook scripts would silently no-op (no recall, no session-start context, no post-edit indexing). `worktree-manager.sh create` injects an absolute symlink `${worktree}/.ruvector -> ${main_repo}/.ruvector` after the `.env` copy step, so MCP and hooks reach the project's shared DB. `worktree-manager.sh copy-env` applies the same fix retroactively. **Behavior:** - Skipped silently (with `info`) if the symlink already exists — idempotent. - Skipped (with `warning`) if a real `.ruvector/` directory already exists in the worktree — preserves the user's intentional isolated DB if they bypassed the manager script. - Skipped (with `warning`) if the main repo has no `.ruvector/` yet — no dangling symlinks. - Removed safely on `cleanup`: `[ -L ]` check, then `rm --` (no `-r`, no `-f`, no trailing slash). Cannot follow into the main repo's DB. **MCP-spawn-time qualifier:** yellow-ruvector's MCP launcher resolves the store from the git toplevel of the directory Claude Code was launched in, once, when it spawns the server (it also heals a missing worktree symlink at that point). The symlink only matters for sessions launched (or re-launched) **from inside the worktree**. A pre-existing session started in main that later `cd`s into a worktree continues to write to the main repo's DB directly. **Concurrent-write caveat:** When two Claude Code sessions run simultaneously (one in main, one in a worktree, or two worktrees), both MCP server processes write to the same shared DB without cross-process locking. Avoid running simultaneous sessions with active `hooks_remember` / `/ruvector:index` operations on the same project. See `plugins/yellow-ruvector/CLAUDE.md` Known Limitations. ### cleanup / clean Remove inactive worktrees: ```bash worktree-manager.sh cleanup worktree-manager.sh clean ``` **Behavior:** - Lists all worktrees - Prompts for confirmation - Removes worktrees one by one - Skips currently active worktree - Removes empty `.worktrees/` directory if all cleaned up ### Restacking across worktrees (`worktree-restack.sh`) A stack whose branches are each checked out in their own worktree cannot be restacked in one pass: the provider has to check a branch out, and git refuses with `'<branch>' is already used by worktree at <path>`. Use `/worktree:restack` (or the script directly) instead of restacking worktree by worktree: ```bash bash "${CLAUDE_PLUGIN_ROOT}/skills/git-worktree/scripts/worktree-restack.sh" \ <subcommand> [--provider graphite|github] [--submit] ``` | Subcommand | Does | | --- | --- | | `preflight` | Read-only. Prints the run worktree, the stack, the worktrees to detach and any `REFUSE` reasons | | `start` | Lock, detach, restack, verify ancestry, restore; `--submit` submits after | | `continue` | Resumes a paused conflict, then verifies and restores | | `abort` | Aborts the provider's restack (Graphite rolls back the whole restack) and any in-chain git rebase in a worktree the run recorded (other worktrees are left alone and named), returns the run worktree to the start branch, then restores | | `status` | Shows the recorded restack, or a worktree stranded detached at a branch tip | | `restore` | Restore only after partial restore, failed abort, mismatch, or hand finish | Run it from the worktree whose branch starts the restack; the restack set is that branch plus everything stacked on it. Graphite detaches the other stack worktrees for the run. GitHub needs gh-stack 0.2.0 or newer, which rebases across worktrees itself, so nothing is detached. Safety rules the script holds: - It refuses before any change when a stack worktree is dirty, locked, prunable or mid-operation, when the stack forks, or when a restack is already in progress. An untracked `.ruvector` symlink does not count as dirty. - Its own git calls never force a checkout, stash, hard-reset or pass `--ignore-other-worktrees`. `--abort` runs Graphite's abort (which rolls the whole restack back) and `git rebase --abort` in each recorded worktree (run worktree, Graphite's detached ones, GitHub's branch owners) holding an in-chain rebase, discarding its in-progress state. Unrecorded worktrees are left alone. It keeps the state (exit `31`) for a GitHub rebase in an unrecorded worktree that may be the run's own, a recorded worktree whose rebase state cannot be read (named) or that `git rebase --abort` did not clear (`rebase-stuck`), or a stack branch off its recorded start commit before or after cleanup (each gets a fix line; see `/worktree:restack`). A worktree that cannot be restored stays detached and the script prints the `git -C <path> checkout <branch>` line. - A conflict pauses the run (exit 10). Graphite: the stack worktrees stay detached and `git worktree lock`ed. Do not commit in them: a commit there lands on no branch, and the script refuses to restore over it. GitHub: nothing is detached or locked; gh-stack holds the paused rebase. - State lives in `<git-common-dir>/yellow-core/worktree-restack/` and is re-validated on every read; a rejected state file runs nothing. - Residual: the dirty check ignores gitignored files, and a restore checkout overwrites an ignored file when the restacked branch now tracks that path. A self-consistent forged state file is constrained to this repository's worktrees and the recorded stack branches, not stopped. Exit codes are in the script header and the `/worktree:restack` exit table. Exit `31`: a step failed with the state kept; run `status`, then `continue`, `abort` or `restore`. Exit `40`: restore kept the state (detached worktrees remain, or a GitHub restack is still paused). The restack engine needs the stacked-PR providers (GitHub also needs Node, `jq` and the github-workflow adapter); `worktree-manager.sh` does not. ## When to Use ### Code Review (/flow:review) When reviewing a PR and you're not on the target branch: ```bash # Workflow offers worktree option /flow:review # Choose worktree option # Skill automatically creates worktree for PR branch # You can review without affecting your current work ``` ### Parallel Feature Development (/flow:work) When working on multiple features: ```bash # Start feature 1 /flow:work # Creates worktree for feature-1 # In another terminal, start feature 2 cd .worktrees/feature-2 /flow:work # Both features developed independently ``` ### Manual Worktree Management When you need direct control: ```bash # Create worktree worktree-manager.sh create experimental-refactor # Switch to it eval "$(worktree-manager.sh go experimental-refactor)" # List all worktree-manager.sh list # Clean up when done worktree-manager.sh cleanup ``` ## Workflow Examples ### Example 1: Code Review with Worktree ```bash # You're on feature-auth branch, working on authentication $ git branch --show-current feature-auth # PR needs review on different branch $ /flow:review pr-123 # Workflow detects branch mismatch, offers worktree option # Select "Create worktree for isolated review" # Worktree created automatically: # - Branch: pr-review-123 # - Location: .worktrees/pr-review-123/ # - .env files copied # - Ready for isolated review # After review, cleanup: $ worktree-manager.sh cleanup ``` ### Example 2: Parallel Feature Development ```bash # Main repo: working on feature A $ pwd /home/user/myproject # Need to quickly prototype feature B $ worktree-manager.sh create feature-b Created worktree: .worktrees/feature-b $ eval "$(worktree-manager.sh go feature-b)" $ pwd /home/user/myproject/.worktrees/feature-b # Work on feature B $ nvim src/feature-b.ts $ git commit -m "feat: prototype feature B" # Switch back to main repo $ cd /home/user/myproject # Both features isolated, no stashing needed ``` ## Integration with Workflows ### /flow:review Integration When `/flow:review` detects you're not on the target branch: 1. Offers worktree option 2. Calls this skill: `/git-worktree create pr-review-<number>` 3. Switches to worktree 4. Proceeds with review in isolation ### /flow:work Integration When starting feature work: 1. Asks if you want isolated environment 2. Calls: `/git-worktree create <branch-name>` 3. Copies .env files automatically 4. Starts feature work in worktree ## Auto-Trust mise/direnv After Worktree Creation If your project uses [mise](https://mise.jdx.dev/) (`.mise.toml`, `.tool-versions`) or [direnv](https://direnv.net/) (`.envrc`), the new worktree directory starts **untrusted** — the tool refuses to load configs until the user explicitly opts in, so tooling silently fails to load after you `cd` in. Auto-trust the new worktree directory at creation time. The manager script handles common cases; the patterns below do it explicitly (e.g., a CI runner creating a throwaway worktree). **mise:** ```bash # After: worktree-manager.sh create feature-auth cd .worktrees/feature-auth # Trust the worktree's mise config mise trust 2>/dev/null || true # Or trust without cd (mise --cwd is supported on recent versions) mise --cwd .worktrees/feature-auth trust 2>/dev/null || true ``` **direnv:** ```bash # direnv requires both `allow` and a load on entry cd .worktrees/feature-auth direnv allow 2>/dev/null || true # Or non-interactively direnv allow .worktrees/feature-auth 2>/dev/null || true ``` **Suppress on absent tools:** `2>/dev/null || true` keeps the trust step quiet when neither mise nor direnv is installed. Do **not** drop the redirect — without it, missing-binary stderr leaks into worktree creation logs. **Why this is per-worktree:** mise and direnv key trust on the absolute path of the directory containing the config. A worktree at `.worktrees/feature-auth/` is a different absolute path from the main repo, even when the `.mise.toml` content is identical. ## `.git`-Is-a-File Detection (Submodule and Worktree Cases) In a normal repo, `.git` is a directory. But in two important cases it is a **plain file** containing a `gitdir: <path>` pointer: 1. **Inside a submodule:** the submodule's `.git` is a file pointing at `<superproject>/.git/modules/<submodule-name>`. 2. **Inside an existing worktree:** the worktree's `.git` is a file pointing at `<main-repo>/.git/worktrees/<worktree-name>`. Naive scripts that do `[ -d .git ]` to detect a git repo will misclassify both cases as "not a git repo" and fail in confusing ways. **Detection pattern:** ```bash # Correct: handles both directory and file forms is_git_repo() { [ -e .git ] && git rev-parse --git-dir >/dev/null 2>&1 } # Or check the type explicitly git_dir_kind() { if [ -d .git ]; then echo "directory" # main repo elif [ -f .git ]; then # Read the gitdir pointer to know whether it's a worktree or submodule case "$(head -n 1 .git)" in "gitdir: "*/.git/worktrees/*) echo "worktree" ;; "gitdir: "*/.git/modules/*) echo "submodule" ;; "gitdir: "*) echo "linked" ;; *) echo "unknown" ;; esac else echo "none" fi } ``` **Worktree creation inside a submodule:** Avoid creating a worktree **inside** a directory whose `.git` is the submodule pointer file — `git worktree add` from a submodule treats the submodule's gitdir as the parent, which lands the new worktree under `<superproject>/.git/modules/<sub>/worktrees/`, far from where users expect. Always run worktree commands from the **superproject root**, or explicitly pass `-C <superproject-root>` to `git worktree add`. **Why this matters for the manager script:** `get_repo_root` uses `git rev-parse --show-toplevel`, which handles both forms, but a caller that pre-checks `[ -d .git ]` short-circuits before reaching it. Use `git rev-parse --git-dir` (which handles both forms) instead. ## Troubleshooting See [troubleshooting.md](troubleshooting.md) for common issues and solutions. ## Design Principles ### KISS (Keep It Simple, Stupid) - One script does everything - Clear command names - No complex configuration - Fails fast with clear errors ### Opinionated Defaults - Worktrees always in `.worktrees/` directory - Always branch from `main` (unless specified) - Always copy .env files - Branch name = worktree name (1:1 mapping) ### Safety First - Never overwrites existing worktrees - Requires confirmation for cleanup - Adds .gitignore automatically - Color-coded warnings and errors ## Reference
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub