---
name: git-worktree
class: tool
description: >-
  Manage Git worktrees for isolated parallel development. Use when creating,
  listing, switching, or cleaning up git worktrees, or when needing isolated
  branches for concurrent reviews or feature work.
---

# Git worktree manager

## 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:
1. Copies `.env`, `.env.local`, `.env.test`, etc. from main repo
2. Ensures `.worktrees` is in `.gitignore`
3. Creates consistent directory structure
4. After creation, install dependencies if detected: `package.json` → `npm install`, `composer.json` → `composer install`, `pyproject.toml` → `pip install -e .`, `go.mod` → `go mod download`

## Safety Verification

Before creating a worktree, verify the worktree directory is gitignored:

```bash
# Verify .worktrees is ignored (should output ".worktrees")
git check-ignore .worktrees || echo "WARNING: .worktrees not in .gitignore"
```

If not ignored, add it to `.gitignore` before proceeding. The manager script handles this, but verify when troubleshooting.

After creating a worktree, run the project's test suite to establish a clean baseline. Pre-existing failures in the worktree should be caught before starting new work -- not discovered mid-implementation.

```bash
# CORRECT - Always use the script
bash ${CLAUDE_PLUGIN_ROOT}/skills/ia-git-worktree/scripts/worktree-manager.sh create feature-name

# WRONG - Never do this directly
git worktree add .worktrees/feature-name -b feature-name main
```

## Commands

| Command | Description | Example |
|---------|-------------|---------|
| `create <branch> [from]` | Create worktree + branch (default: from main) | `...worktree-manager.sh create feature-login` |
| `list` / `ls` | List all worktrees with status | `...worktree-manager.sh list` |
| `switch <name>` / `go` | Switch to existing worktree | `...worktree-manager.sh switch feature-login` |
| `copy-env <name>` | Copy .env files to existing worktree | `...worktree-manager.sh copy-env feature-login` |
| `cleanup` / `clean` | Interactively remove inactive worktrees | `...worktree-manager.sh cleanup` |

After cleanup, run `git worktree prune` to remove any orphaned worktree metadata from manually deleted directories.

All commands use: `bash ${CLAUDE_PLUGIN_ROOT}/skills/ia-git-worktree/scripts/worktree-manager.sh <command>`

## Environment Detection

Before creating worktrees, detect the execution context:

1. **Already in a worktree?** Check `git rev-parse --show-toplevel` against `git worktree list`. If the current directory is already a linked worktree, skip creation -- work directly in the existing worktree.
2. **Codex/sandbox environment?** If `$CODEX_SANDBOX` is set or the repo is at a non-standard path (e.g., `/tmp/`, `/workspace/`), worktrees may not be supported. Fall back to regular branch switching.
3. **Bare repo?** If `git rev-parse --is-bare-repository` returns true, worktrees are the only way to have a working directory. Adjust paths accordingly.

Adapt the workflow to the detected context rather than failing with a generic error.

## Integration with Workflows

### `/ia-review`

1. Check current branch
2. If ALREADY on target branch -> stay there, no worktree needed
3. If DIFFERENT branch -> offer worktree: "Use worktree for isolated review? (y/n)"

### `/ia-work`

Always offer choice:
1. New branch on current worktree (live work)
2. Worktree (parallel work)

## Branch Completion

When work in a worktree is done, verify tests pass, then present exactly 4 options:

1. **Merge locally** -- merge into base branch, delete worktree branch, clean up worktree
2. **Push + PR** -- push branch, create PR with `gh pr create`, keep worktree until merged
3. **Keep as-is** -- leave branch and worktree for later
4. **Discard** -- requires typing "discard" to confirm. Deletes branch and worktree. No silent discards.

Clean up the worktree directory only for options 1 and 4. For option 2, the worktree stays until the PR merges.

## Change Summary

When completing work in a worktree (before merge or PR), output a structured summary:

```
CHANGES MADE:
- src/routes/tasks.ts: Added validation middleware

THINGS I DIDN'T TOUCH (intentionally):
- src/routes/auth.ts: Has similar validation gap but out of scope

POTENTIAL CONCERNS:
- The Zod schema is strict -- rejects extra fields. Confirm this is desired.
```

The "DIDN'T TOUCH" section prevents reviewers from wondering whether adjacent issues were missed or intentionally deferred.

## Hook Safety Under Husky

Installing hooks into `.git/hooks/` silently fails on any repo that uses Husky. Husky sets `core.hooksPath` (typically to `.husky/_`) and git ignores `.git/hooks/` entirely when that config is non-empty. The hook file lands on disk, is executable, is correct, and is dead. Invisible failure until someone asks why the post-merge behavior isn't running.

### Detection rule before writing any hook

```bash
hooks_path=$(git -C "$repo" config --get core.hooksPath)
```

- Empty output: write to `$(git rev-parse --git-common-dir)/hooks/<name>` as usual.
- `.husky/_` (or any path containing `husky.sh` / `h` trampoline): Husky v9 setup. Write to `.husky/<name>`; do NOT include the v8-era `. "$(dirname "$0")/_/husky.sh"` line (v9 prints a deprecation warning if you do).
- Unrecognized non-empty value: refuse to write the hook and surface the path to the user. Silent writes to the wrong location waste debug cycles later.

### Worktree-safe hook body

`.git/hooks/` lives in the common git dir and runs for every worktree of the clone. A hook installed once fires across all trees. Two rules to stay safe:

1. Resolve the invoking worktree's root inside the hook body with `git rev-parse --show-toplevel`, not a hardcoded path. Hardcoding means the last `install-hooks` invocation wins for every worktree.
2. Guard the tool invocation with an existence check on the tool's per-tree state dir. Siblings without your tool's setup must no-op, not spawn a failing background process per git op.

```sh
#!/bin/sh
root="$(git rev-parse --show-toplevel 2>/dev/null)" || exit 0
[ -d "$root/.my-tool" ] || exit 0
( cd "$root" && my-tool index ) >>"$root/.my-tool/hook.log" 2>&1 &
exit 0
```

Redirect to a log file inside the tool's state dir, not `/dev/null` — silent failures produce stale state you only notice hours later.

## Local Excludes: .git/info/exclude vs .gitignore

Tooling artifacts (local index dirs, hook helpers, per-developer scratch files) belong in `.git/info/exclude`, NOT in the tracked `.gitignore`.

- `.gitignore` is content — tracked, shared with the team, reviewed in PRs. Adding a personal tooling rule there pollutes a shared file. On foreign repos (upstream projects, third-party clones) the rule either rides into a PR by accident or sits as a dirty working tree forever.
- `.git/info/exclude` is local — untracked, lives in the common git dir, shared across every worktree of the clone. Same syntax and semantics as `.gitignore` without the leakage.

### Resolving the path correctly under worktrees

Don't hardcode `$repo/.git/info/exclude`. In a worktree, `.git` is a file (gitlink), not a directory. Use git itself:

```bash
exclude=$(git -C "$repo" rev-parse --git-path info/exclude)
```

### Idempotent append

```bash
line="/.my-tool/"
mkdir -p "$(dirname "$exclude")"
grep -qxF "$line" "$exclude" 2>/dev/null || printf '\n# my-tool\n%s\n' "$line" >> "$exclude"
```

`grep -qxF` matches the exact line with no regex surprises.

### When to break the rule

Only when the artifact is genuinely team-shared and belongs in the repo (build outputs used in CI, generated files, vendored dependencies). If in doubt, ask: "would another contributor benefit from this rule?" If no, exclude locally.

## Verify

- `git worktree list` shows the new entry
- `.worktrees` directory confirmed in `.gitignore`
- Dependencies installed in the worktree
- Baseline test suite passes in the worktree

## References

- [workflow-examples.md](./references/workflow-examples.md) - Code review and parallel development workflows
- [troubleshooting.md](./references/troubleshooting.md) - Common issues, directory structure, how it works
- [worktree-manager.sh](./scripts/worktree-manager.sh) - The manager script
