원클릭으로
worktree
Git worktree management: create, list, remove isolated working copies with env/config symlinks.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Git worktree management: create, list, remove isolated working copies with env/config symlinks.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Strict review and QA workflows: shared reviewer ethos, scope boundaries, code-review classification, finding JSON schema, and QA-label review lifecycle. Load this skill when reviewing a diff, classifying findings, returning a verdict, or handling a QA-label-triggered review.
GitHub API CLI for PR operations: threads, comments, reviews, CI logs, merging, and cross-PR analysis.
PRIMARY AGENT ONLY — single work-item orchestration for Linear or GitHub issues: prepare, delegate implementation, review, submit, merge, and handoff.
TPM-orchestrated planning, audit, roadmap, and research-driven decomposition. Owns the user-facing wrappers (cycle-plan, audit-issues, roadmap-*, research-*) and the underlying TPM execution workflows.
Cross-model second opinion: review, challenge, audit, and consult via an external AI CLI (Claude ↔ Codex).
Architecture Decision Record (ADR) and architectural decision document management: templates, creation, search, supersession tracking, and INDEX maintenance.
| name | worktree |
| description | Git worktree management: create, list, remove isolated working copies with env/config symlinks. |
| license | MIT |
| user-invocable | true |
| argument-hint | create <ID> [--base <branch>] [--from <ref>] [--pr <N>] [--reuse|--restack] | restack continue|skip|abort <ID|path> | list | remove <ID|path> |
| metadata | {"author":"vanillagreen","source":"vstack","repository":"https://github.com/vanillagreencom/vstack","bugs":"https://github.com/vanillagreencom/vstack/issues","version":"1.0.0"} |
Portable git worktree manager. Layout defaults to project/main (repo) + project/trees/{id} (worktrees); projects can override the worktree parent directory.
Resolves project root via git rev-parse, detects default branch automatically, and reads project-specific config from .env, vstack.settings.toml, then .env.local (.env.local wins).
.agents/skills/worktree/scripts/worktree <command> [options]
| Command | Description |
|---|---|
create | Claim a new issue worktree. Refuses implicit reuse when a worktree, branch, or PR already exists. |
restack | Guardedly continue, skip, or abort a tool-created paused restack. |
list | List all worktrees |
remove | Remove worktree, clean symlinks, prune branches |
cleanup | Remove worktrees whose branches are merged |
path | Print worktree path for issue ID |
exists | Check if worktree exists for issue ID |
check | Pre-create git state check (JSON: uncommitted, unpushed) |
push | Push worktree branch with auto-rebase |
codex-setup | Apply env/config setup to a Codex Desktop app-created worktree |
codex-branch | Normalize a Codex Desktop app-created branch to an issue branch |
codex-cleanup | Non-destructive Codex Desktop cleanup hook; app owns deletion |
push ISSUE_ID normally resolves through the configured worktree registry. When run from a checkout whose current branch already matches the normalized issue branch, it pushes that active checkout instead. This supports Codex Desktop app-created worktrees that are valid git worktrees but are not registered under WORKTREE_BASE_DIR.
push and origin fetches use the GitHub skill's git-https-auth behavior when
available: GitHub SSH remotes stay unchanged by default, but if gh auth is
valid the git command gets temporary HTTPS rewrite and gh auth git-credential
config. This lets Codex/GitHub-authenticated sessions push without a working
SSH key. Set VSTACK_GITHUB_GIT_HTTPS_FALLBACK=never to force the normal SSH
path.
When push performs its auto-rebase, the following push uses a scoped
--force-with-lease pinned to the target branch OID known before the rebase.
create --reuse and the supported create --restack conflict-recovery flow
persist the same narrowly scoped authorization in the worktree: it records the
exact observed remote OID and the exact successfully restacked local head.
push accepts that rewritten head or later commits built on it, still pins the
force-with-lease to the recorded remote OID, and consumes the authorization
after success. A different local rewrite, remote movement while conflict
resolution is pending, or a moved remote at push time fails closed. Plain
pushes are still used with --no-rebase.
remove deletes the worktree before deleting the local branch. Branch deletion uses safe git branch -d; if that fails after worktree removal, the script exits non-zero with a diagnostic naming the remaining branch and manual git branch -D recovery command.
When a configured symlink path is already tracked in the worktree branch, the script marks that path assume-unchanged before replacing it so git status stays clean.
Bare create <ID> is a new-work claim, not a discovery command. Every new-branch mode, including --from, checks the normalized issue branch, an explicit requested branch, and BOT_NAME/<issue> across worktrees, local/remote refs, and open PRs. Existing ownership exits 75 and leaves local branches unchanged. Origin remote-head or GitHub PR discovery failure exits 1 before worktree config, branch, or target-path mutation; never interpret an outage as absence. Unreachable secondary remotes are skipped with a warning — they cannot receive other sessions' pushes, so only origin is required for the claim gate; reachable secondary remotes still count as ownership signals. A repository-local normalized-issue claim lock holds the final repeated discovery through git worktree add, so concurrent claims cannot both mutate. Inspect or monitor owned work instead of spawning a second implementer. Run issue creates as separate commands and check each result; do not batch them in a shell loop whose final successful command can hide an earlier active-work exit.
An existing owner may opt in with create <ID> --reuse, which refreshes setup after rebasing onto origin/<default>. Reuse/restack requires the target's exact canonical path to be registered to this repository's common Git directory; incomplete directories are preserved and exit 75. Use --restack only to pause that intentional rebase in a conflict state. To inspect existing remote work whose issue worktree is absent, use create <ID> --pr <N> or --base <branch> explicitly.
Let Codex Desktop own app-created worktree creation and deletion. Configure project setup/cleanup hooks to run:
"$CODEX_SOURCE_TREE_PATH/.agents/skills/worktree/scripts/worktree" codex-setup "$CODEX_WORKTREE_PATH"
"$CODEX_SOURCE_TREE_PATH/.agents/skills/worktree/scripts/worktree" codex-cleanup "$CODEX_WORKTREE_PATH"
For issue workflows, run codex-branch ISSUE_ID "$CODEX_WORKTREE_PATH" before orchestration if the harness did not already normalize the branch.
create flags| Flag | Effect |
|---|---|
--base BRANCH | Checkout an existing remote branch into the worktree |
--from REF | Create a new branch (named after ID) starting from REF after the normal ownership claim gate |
--pr NUMBER | Look up the branch from a GitHub PR number (implies --base) |
--reuse | Explicitly reuse an existing issue worktree and rebase it onto origin/<default> |
--restack | When reusing an existing worktree and its rebase onto origin/<default> conflicts, stop in the conflict state for resolution instead of aborting |
Bare create never rebases an existing worktree. After the owning session opts in with --reuse, the branch rebases onto origin/<default>. If that rebase conflicts, the run aborts the rebase and exits 1 — the worktree is left clean on its pre-rebase state, so there is no conflict left to resolve in place. The error lists the conflicting files (captured before the abort) and the two supported recovery paths:
create <ID> --restack. The rebase re-runs and pauses in the conflict state. Resolve the listed files, stage each with git -C <path> add <file>, then run worktree restack continue <ID>; repeat if it stops again. If the current commit is already represented by the new base and should be omitted, use worktree restack skip <ID>. Use worktree restack abort <ID> to restore the pre-restack branch.remove <ID> then create <ID> recreates the worktree fresh from origin/<default>, losing the local commits that conflicted.The guarded actions accept only a registered worktree whose worktree-local restack authorization, tool-created state token, and Git sequencer metadata agree on the exact remote, branch, observed remote OID, original head, and target base. continue and skip re-check the remote before and after replay, finalize the exact rewritten-head lease when complete, and fail closed on missing, stale, or unrelated state. abort requires the same matching local state, restores the recorded original head, and clears only the pending authorization; remote movement does not make that restorative action unsafe. Published paused states created by the pre-token tool remain recoverable when all legacy authorization and sequencer fields match exactly. With no conflict, --restack completes the same intentional rebase as --reuse.
Some execution policies reject top-level git rebase porcelain outright — Codex approval_policy = never rejects it with approval required by policy, but AskForApproval is set to Never, and no approval can ever arrive. That rejection names the command, not the goal: do not retry the same porcelain, do not delegate it to a sub-agent, and never substitute a raw --force push.
First choice — the supported tool path. Every guarded restack command is a single simple helper invocation with no top-level rebase porcelain: create <ID> --reuse performs the rebase onto origin/<default> inside the tool and records the exact lease worktree push needs, create <ID> --restack pauses a conflicting rebase for resolution, and worktree restack continue|skip|abort <ID> controls the paused state. Use this path whenever the checkout is a registered issue worktree.
Cherry-pick replay — only when the tool path is unavailable or also rejected. The replay produces the same rebased history from single simple commands: it detaches at the new base, replays the branch's unique commits in order, moves the branch ref only after the whole replay succeeds, and publishes with the same pinned-lease model the tool uses. Run each fenced command below as exactly one command per tool call; take derived values from a previous command's printed output, never from $(...) substitution.
Clean-worktree check — the output must be empty; never replay over uncommitted changes:
git -C <path> status --porcelain
Fetch the current remote state:
git -C <path> fetch origin
Record the observed remote head — use the printed OID as <remote-oid> in steps 4 and 10. If the ref does not exist the branch is unpublished: skip step 4, and finish with worktree push <ID> --set-upstream instead of step 10.
git -C <path> rev-parse refs/remotes/origin/<branch>
Ancestry check (the tool's own lease rule) — exit status must be 0. Nonzero means the remote holds commits this checkout has never observed: stop and reconcile; replaying would overwrite them.
git -C <path> merge-base --is-ancestor <remote-oid> <branch>
Also stop if there is nothing to restack: git -C <path> merge-base --is-ancestor origin/<default> <branch> exiting 0 means the branch already contains the new base.
List the commits to replay, oldest first, and record the list:
git -C <path> log --oneline --reverse origin/<default>..<branch>
Detach at the new base. Detaching is worktree-safe: it never checks out <default> as a branch, so it cannot collide with the main checkout.
git -C <path> checkout --detach origin/<default>
Replay the unique commits in order (same range as step 5; git applies it oldest first):
git -C <path> cherry-pick origin/<default>..<branch>
If the range contains a merge commit the replay stops without picking it; run the abort control below and use the supported tool path or manual reconciliation instead.
Conflict controls — the policy-shaped equivalents of restack continue|skip|abort. On a conflict stop, edit the conflicting files with harness file-edit tools (never shell redirection), stage each one, then continue:
git -C <path> add <file>
git -C <path> -c core.editor=true cherry-pick --continue
-c core.editor=true keeps git from opening an interactive editor; it is a git flag, not an env-assignment prefix, so the command stays a single simple command. If the stopped pick is already represented by the new base (git reports the pick is now empty), skip it:
git -C <path> cherry-pick --skip
To back out entirely — the branch ref has not moved yet, so aborting restores everything; reattach afterward with git -C <path> checkout <branch>:
git -C <path> cherry-pick --abort
Verify the replayed tip and move the branch. First confirm the new base is contained — exit status must be 0:
git -C <path> merge-base --is-ancestor origin/<default> HEAD
Then move the branch ref to the replayed tip (the first ref mutation of the whole procedure) and reattach the worktree to it:
git -C <path> branch -f <branch> HEAD
git -C <path> checkout <branch>
Publish with the pinned lease — the exact <remote-oid> recorded in step 3, so the push fails closed if the remote moved. worktree push refuses manual rewrites by design (its rewritten-push authorization is recorded only by the tool's own supported restack), so this one command is the documented completion; never use raw --force, and never an unpinned --force-with-lease (a background fetch can move the tracking ref and defeat it):
git -C <path> push origin <branch> --force-with-lease=refs/heads/<branch>:<remote-oid>
Restore worktree setup — the replay can replace configured symlinks with tracked content, exactly like a manual rebase:
.agents/skills/worktree/scripts/worktree fix-links <ID>
gitgh for new-work PR ownership discoveryflock for repository-local per-issue claim serializationSet non-sensitive defaults in committed vstack.settings.toml under [env]. Existing .env and .env.local variables still work, and .env.local wins for secrets or personal overrides.
| Variable | Effect |
|---|---|
WORKTREE_BASE_DIR | Parent directory for created worktrees. Relative paths resolve from the main checkout; absolute paths are used as-is. Default: ../trees |
WORKTREE_SYMLINKS | Space-separated paths symlinked from main checkout into each worktree; include .env.local only if worktrees should share local secrets/overrides |
WORKTREE_RELATIVE_SYMLINKS | Space-separated path=target symlinks created inside each worktree, with relative targets resolving from the link location |
WORKTREE_COPIES | Space-separated files copied from main checkout into each worktree |
WORKTREE_MKDIRS | Space-separated directories created inside each worktree with mkdir -p; use for gitignored scratch dirs such as tmp |
Example: share local env plus generated Claude assets, but keep .claude/CLAUDE.md pointed at each worktree's own AGENTS.md:
[env]
WORKTREE_BASE_DIR = "../trees"
WORKTREE_SYMLINKS = ".env.local .claude/agents .claude/hooks .claude/skills"
WORKTREE_RELATIVE_SYMLINKS = ".claude/CLAUDE.md=../AGENTS.md"
WORKTREE_MKDIRS = "tmp"