# Using Git Worktrees

> Use when creating an isolated Git workspace, running the default branch locally, or closing development work that used a worktree.

- Skill: `jorgemenadev/using-git-worktrees` (Agent Skill, multi-file: 7 files)
- Install (CLI): `npx skillmds@latest add jorgemenadev/using-git-worktrees`
- Raw SKILL.md: https://api.skillmd.com/api/skills/jorgemenadev/using-git-worktrees/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: jorgemenadev (https://skillmd.com/u/jorgemenadev)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/jorgemenadev/using-git-worktrees

---


# Using Git Worktrees

## Contract

Research and review share an existing checkout and install nothing. Tracked implementation gets one source-only branch at sibling `<repo-name>-worktrees/<branch-slug>`. A no-edit local run reuses detached `<repo-name>-worktrees/local-main`. Hydration requires a 2–4 GiB storage budget and a resolved workspace storage policy: the desired target is informational, a warning or freeze may block non-incident hydration, and the hard hydration floor is the absolute stop. Every runtime owns its ports and local state, then stops and dehydrates when the task finishes. Only explicitly synthetic Convex state is disposable.

Announce: “I’m using the using-git-worktrees skill to prepare the task workspace and lifecycle.”

## Fast path: repos with the local-runtime contract

When the repository exposes `setup:worktree` in its root `package.json` (the Andes repository
contract), do not walk sections 1–5 by hand. Run one command and stop:

```bash
<skill-dir>/scripts/worktree-dev.sh up <slug> [--surface <s>]... [--mode human|smoke]
```

It performs the whole contract — sibling worktree off `origin/main`, storage preflight (defaults:
floor 10 GiB, freeze no; override with `WORKTREE_FREE_FLOOR_GIB` / `WORKTREE_HYDRATION_FREEZE`),
ignored-env copy, `bun install --frozen-lockfile`, `setup:worktree`, then a detached `qa:local`
(fallback: `dev:<surface>` / `dev`) — and prints the `QA_LOCAL_READY` / URL lines. Ports are derived
deterministically from the worktree path, so parallel worktrees never collide. Close with
`worktree-dev.sh down <slug> [--remove]`: it reaps every process whose cwd is the worktree, refuses
removal over uncommitted or unpushed work, and dehydrates before retiring. Manual sections 1–5
remain for repos without the contract and for non-standard bases or blocked states.

## 1. Inspect

Run this preamble and branch only on its tokens:

```bash
repo_root=$(git rev-parse --show-toplevel)
git_dir=$(cd "$(git rev-parse --git-dir)" && pwd -P)
git_common=$(cd "$(git rev-parse --git-common-dir)" && pwd -P)
superproject=$(git rev-parse --show-superproject-working-tree 2>/dev/null || true)
printf 'REPO_ROOT: %s\nIS_LINKED: %s\nIS_SUBMODULE: %s\nBRANCH: %s\n' \
  "$repo_root" "$([ "$git_dir" != "$git_common" ] && echo yes || echo no)" \
  "$([ -n "$superproject" ] && echo yes || echo no)" "$(git branch --show-current)"
```

Read the root instructions and package scripts. Choose exactly one mode:

- `READ_ONLY`: research/review with no tracked edit or live runtime. Stay in the existing checkout, install nothing, report `SOURCE_ONLY`, and stop this skill.
- `FEATURE`: tracked implementation. Use the explicit base or current `origin/main`.
- `LAUNCH_MAIN`: no-edit local QA/preview. Reuse the one `local-main` worktree.

Treating review as implementation or creating a second local runtime is `WORKSPACE_SPRAWL`. For mutating modes, resolve and verify `base_ref` now: use the explicit base, otherwise `git symbolic-ref --quiet --short refs/remotes/origin/HEAD`.

Branch on the inspection tokens before creating anything:

- `IS_SUBMODULE: yes`: `READ_ONLY` may continue; mutating modes stop with `SUBMODULE_WORKTREE_BLOCKED` and restart from a standalone checkout or the superproject owner.
- `IS_LINKED: yes`, `FEATURE`: reuse only when the current branch is the requested branch (or this task explicitly owns it) and `base_ref` is an ancestor of `HEAD`; otherwise stop with `WORKSPACE_CONTEXT_BLOCKED`.
- `IS_LINKED: yes`, `LAUNCH_MAIN`: require basename `local-main`, clean status, and zero commits beyond `base_ref`; stop its owned runtime, detach at `base_ref`, then continue. Any failure is `WORKSPACE_CONTEXT_BLOCKED`.
- Only a non-linked, non-submodule primary checkout continues to source preparation.

## 2. Prepare source

For `FEATURE` or `LAUNCH_MAIN` from the primary checkout:

```bash
git fetch origin
git rev-parse --verify "$base_ref^{commit}"
worktree_root="$(dirname "$repo_root")/$(basename "$repo_root")-worktrees"
mkdir -p "$worktree_root"
```

Create `FEATURE` with `git worktree add "$worktree_root/$slug" -b "$branch" "$base_ref"`. Create absent `LAUNCH_MAIN` with `git worktree add --detach "$worktree_root/local-main" "$base_ref"`. Reuse `local-main` only when registered to this repository, clean, and carrying zero commits beyond `$base_ref`; stop its owned runtime, then detach it at current `$base_ref`.

The new tree remains source-only. Preserve a dirty primary checkout: never stash, clean, reset, rebase, or copy tracked files from it.

## 3. Decide hydration

Skip hydration when source inspection or editing is sufficient; source-only editing never runs the preflight. When dependencies or a runtime are required, resolve the workspace storage policy before hydrating. It defines three distinct roles:

- the desired/ideal target is informational only;
- the warning band or a new-hydration freeze may block starting non-incident hydration;
- the hard hydration floor is the absolute projected-free stop.

Read the active workspace storage policy, extract each value by name, and never substitute a desired target, acceptable band, or warning threshold for the hard floor. Then run:

```bash
WORKTREE_FREE_FLOOR_GIB=<hard-floor> WORKTREE_HYDRATION_FREEZE=<freeze> \
  <skill-dir>/scripts/storage-preflight.sh <worktree> 4
```

Use 4 GiB unless contemporaneous repository-specific dependency-plus-build peak evidence supports 2 or 3. Continue only on `HYDRATE_ALLOWED: yes`. Every `no` is `STORAGE_PREFLIGHT_BLOCKED` with a named reason: `hydration-frozen` blocks non-incident hydration and yields only to explicit incident authorization; `projected-free-below-floor` stops all hydration; a missing or malformed hard floor or freeze policy fails closed. Reuse an already-hydrated safe workspace or report the blocker. Hydrating anyway is the failure these gates prevent.

For Bun or Convex, read [BUN_CONVEX.md](BUN_CONVEX.md) in full. Otherwise use repository-declared setup. Do not add test files unless requested; use existing checks and live smoke.

## 4. Prove readiness

Verify branch/path, ignored environment presence without values, unchanged lockfile, unique owned listeners, requested URLs, non-production targets, worktree-local state, and clean tracked status. On failure, report `BLOCKED` with the exact command and error.

## 5. Close the lifecycle

When runtime work ends, read [LIFECYCLE.md](LIFECYCLE.md) in full. Stop owned processes, classify Convex state, dehydrate regenerable artifacts, and review retirement eligibility. Leaving an abandoned runtime hydrated is `LIFECYCLE_LEAK`.

## Report

```text
SOURCE_ONLY | READY | BLOCKED | RETIRED
Mode: READ_ONLY | FEATURE | LAUNCH_MAIN
Worktree: <existing checkout or absolute worktree>
Storage: free <GiB>; budget <GiB>; target <GiB> (informational); warning <GiB> (freeze gate); floor <GiB> (hard); freeze <yes/no>; hydration <yes/no/not-needed>
Runtime: <stopped or URLs plus owned ports>
State: Convex <none/synthetic/durable/unknown>; artifacts <preserved/removed>
Retirement: <not-applicable/retained/eligible/removed>
Validation: <commands and result>
```

