Worktree Handoff
Mission
Reproduce the current source worktree state onto a local target branch. If the user does not name a target branch, choose the default target from the current worktree context.
The source worktree must look the same before and after the handoff. The handoff only changes the destination branch/worktree.
When To Use
- User wants current worktree changes moved onto another local branch.
- Untracked files must come along with tracked edits.
- The repo uses multiple worktrees and the target branch may already have one.
Non-Negotiables
- Default target branch:
- If the user named a target branch, use it.
- If no target is named and the current source is a linked worktree, use the current source branch as the canonical destination branch.
- If no target is named and the source is detached, first check
git worktree list --porcelain for same-HEAD branch worktrees before falling back to develop.
- Never use
develop as the detached fallback until same-HEAD branch worktrees have been checked.
- Source worktree state is invariant. Do not clear it, clean it, switch it, reset it, restore it, or stash/pop/apply from it as part of the handoff.
- Do not update the destination branch with
pull, merge, rebase, or reset as part of the handoff. Apply onto the destination's current local state.
- Do not use destructive git commands.
- Prefer the target branch's existing worktree if one already exists.
- Existing local changes on the target branch are allowed. Minor dirtiness such as lockfile churn is not a blocker; apply on top and let Git report whether a real conflict exists.
- After applying, always inspect for conflicts and report them before resolving anything.
- If a temporary target worktree is created, report its path and leave it in place unless the user asks for cleanup.
- A clean source worktree after handoff is not a success signal. If the source became clean, something went wrong unless the user explicitly asked for cleanup.
Fast Non-Mutating Workflow
1) Preflight
git status --short --branch
git worktree list --porcelain
- Capture the source status first; it must match again after the handoff.
git status --short --branch replaces separate branch and status checks.
- If
HEAD is detached, use the short commit SHA as the source ref in the report.
- When resolving an implicit target, state which rule selected it before applying anything.
- If there are no source changes, stop and say there is nothing to hand off.
2) Resolve the default target branch
Only do this if the user did not specify a target branch.
- Parse
git worktree list --porcelain; entries are separated by worktree <path> lines and may include HEAD <sha> and branch refs/heads/<name>.
- If the source is not detached, the source path differs from the first/main worktree path, and
git status --short --branch shows a local branch, default the target to that source branch name. Report: "Source is a linked worktree on <branch>, so defaulting target to <branch>."
- If the source is detached, get the source
HEAD SHA and find other worktree entries with the same HEAD <sha> and a branch refs/heads/<name> line.
- If exactly one same-HEAD branch worktree exists, default the target to that branch. Report: "Source is detached at , but main/root worktree at the same HEAD is on
<branch>, so defaulting target to <branch>." If the matching branch worktree is not the main/root worktree, name its path instead of "main/root worktree".
- If multiple same-HEAD branch worktrees exist, stop and ask which branch to use. List the candidate branch names and worktree paths.
- If no same-HEAD branch worktree exists, default the target to
develop. Report: "Source is detached at and no same-HEAD branch worktree exists, so defaulting target to develop."
- Do not default a detached source to
develop before completing the same-HEAD branch worktree check.
Example Codex linked-worktree case:
worktree /repo
HEAD abc1234
branch refs/heads/feature/foo
worktree /repo/.codex/worktrees/task
HEAD abc1234
detached
If the source path is /repo/.codex/worktrees/task and no target was specified, default to feature/foo, not develop, because the main/root worktree is on feature/foo at the same HEAD.
3) Resolve the target worktree
- If
git worktree list --porcelain already shows branch refs/heads/<target-branch> in a worktree other than the source worktree, use that worktree path.
- Otherwise, create a sibling temporary worktree for the target branch instead of forcing a branch switch in the current worktree.
- If Git refuses because the target branch is already checked out by the source worktree, create the temporary destination with
--force; never use the source worktree itself as the destination.
git worktree add "../<repo>-handoff-<target-branch>" "<target-branch>"
# only when Git says the branch is already checked out by the source worktree:
git worktree add --force "../<repo>-handoff-<target-branch>" "<target-branch>"
- If the target branch does not exist locally, stop and ask whether it should be created from
origin/<target-branch> or another base.
4) Build a non-mutating snapshot from the source worktree
tmpdir=$(mktemp -d)
base=$(git rev-parse HEAD)
alt_index="$tmpdir/handoff.index"
cp "$(git rev-parse --git-path index)" "$alt_index"
GIT_INDEX_FILE="$alt_index" git add -A
snapshot_tree=$(GIT_INDEX_FILE="$alt_index" git write-tree)
snapshot_commit=$(printf 'worktree-handoff snapshot\n' | git commit-tree "$snapshot_tree" -p "$base")
- This captures tracked, staged, unstaged, and untracked paths without touching the real source index or worktree.
snapshot_commit is temporary and does not update any branch ref.
- This handoff preserves the source worktree contents, not the exact staged/unstaged split. The destination will typically receive the snapshot as staged changes.
5) Check the target before applying
git -C "<target-worktree>" status --short
- Existing tracked changes and non-colliding untracked files are fine, including small unrelated dirtiness such as
bun.lock updates. Do not stop just because the destination is dirty.
- If the target already has colliding untracked paths, report the collision instead of forcing the handoff.
6) Apply the handoff onto the target branch
git -C "<target-worktree>" cherry-pick -n "$snapshot_commit"
- This applies the source snapshot only in the target worktree. The source worktree must remain untouched.
- Stop on conflicts and report them. Do not resolve them silently.
- Do not run
git stash push, git stash pop, or git stash apply in the source worktree.
7) Verify the result
git status --short --branch
git -C "<target-worktree>" diff --name-only --diff-filter=U
git -C "<target-worktree>" status --short
- Confirm the source status matches the preflight snapshot. If it differs, report an unexpected source mutation immediately.
- The target should now contain the handed-off snapshot.
Reporting Rules
- If the apply succeeds cleanly, report:
- source ref/worktree
- target branch/worktree
- whether the target already had local changes
- whether the source status matched before/after exactly
- whether a temporary target worktree was created
- that the destination received a staged snapshot of the source state
- If there are conflicts, stop after applying and report:
- conflicted files
- whether the target branch already had overlapping edits
- that the source worktree remained unchanged
- the most likely resolution approach
Even if a conflict looks trivial, do not silently resolve it. Ask how to proceed after summarizing the conflict.
Never describe success as "the source worktree is now clean again". If the user wants the source cleaned after verification, that is a separate explicit follow-up step.
1---2name: worktree-handoff3description: Safely hand off the current source worktree state, including untracked files, onto a local target branch without modifying the source worktree, using an alternate-index snapshot and target-side cherry-pick.4---56# Worktree Handoff78## Mission910Reproduce the current source worktree state onto a local target branch. If the user does not name a target branch, choose the default target from the current worktree context.1112The source worktree must look the same before and after the handoff. The handoff only changes the destination branch/worktree.1314## When To Use1516- User wants current worktree changes moved onto another local branch.17- Untracked files must come along with tracked edits.18- The repo uses multiple worktrees and the target branch may already have one.1920## Non-Negotiables2122- Default target branch:23 - If the user named a target branch, use it.24 - If no target is named and the current source is a linked worktree, use the current source branch as the canonical destination branch.25 - If no target is named and the source is detached, first check `git worktree list --porcelain` for same-HEAD branch worktrees before falling back to `develop`.26 - Never use `develop` as the detached fallback until same-HEAD branch worktrees have been checked.27- Source worktree state is invariant. Do not clear it, clean it, switch it, reset it, restore it, or stash/pop/apply from it as part of the handoff.28- Do not update the destination branch with `pull`, `merge`, `rebase`, or `reset` as part of the handoff. Apply onto the destination's current local state.29- Do not use destructive git commands.30- Prefer the target branch's existing worktree if one already exists.31- Existing local changes on the target branch are allowed. Minor dirtiness such as lockfile churn is not a blocker; apply on top and let Git report whether a real conflict exists.32- After applying, always inspect for conflicts and report them before resolving anything.33- If a temporary target worktree is created, report its path and leave it in place unless the user asks for cleanup.34- A clean source worktree after handoff is not a success signal. If the source became clean, something went wrong unless the user explicitly asked for cleanup.3536## Fast Non-Mutating Workflow3738### 1) Preflight3940```bash41git status --short --branch42git worktree list --porcelain43```4445- Capture the source status first; it must match again after the handoff.46- `git status --short --branch` replaces separate branch and status checks.47- If `HEAD` is detached, use the short commit SHA as the source ref in the report.48- When resolving an implicit target, state which rule selected it before applying anything.49- If there are no source changes, stop and say there is nothing to hand off.5051### 2) Resolve the default target branch5253Only do this if the user did not specify a target branch.5455- Parse `git worktree list --porcelain`; entries are separated by `worktree <path>` lines and may include `HEAD <sha>` and `branch refs/heads/<name>`.56- If the source is not detached, the source path differs from the first/main worktree path, and `git status --short --branch` shows a local branch, default the target to that source branch name. Report: "Source is a linked worktree on `<branch>`, so defaulting target to `<branch>`."57- If the source is detached, get the source `HEAD` SHA and find other worktree entries with the same `HEAD <sha>` and a `branch refs/heads/<name>` line.58- If exactly one same-HEAD branch worktree exists, default the target to that branch. Report: "Source is detached at <sha>, but main/root worktree at the same HEAD is on `<branch>`, so defaulting target to `<branch>`." If the matching branch worktree is not the main/root worktree, name its path instead of "main/root worktree".59- If multiple same-HEAD branch worktrees exist, stop and ask which branch to use. List the candidate branch names and worktree paths.60- If no same-HEAD branch worktree exists, default the target to `develop`. Report: "Source is detached at <sha> and no same-HEAD branch worktree exists, so defaulting target to `develop`."61- Do not default a detached source to `develop` before completing the same-HEAD branch worktree check.6263Example Codex linked-worktree case:6465```text66worktree /repo67HEAD abc123468branch refs/heads/feature/foo6970worktree /repo/.codex/worktrees/task71HEAD abc123472detached73```7475If the source path is `/repo/.codex/worktrees/task` and no target was specified, default to `feature/foo`, not `develop`, because the main/root worktree is on `feature/foo` at the same HEAD.7677### 3) Resolve the target worktree7879- If `git worktree list --porcelain` already shows `branch refs/heads/<target-branch>` in a worktree other than the source worktree, use that worktree path.80- Otherwise, create a sibling temporary worktree for the target branch instead of forcing a branch switch in the current worktree.81- If Git refuses because the target branch is already checked out by the source worktree, create the temporary destination with `--force`; never use the source worktree itself as the destination.8283```bash84git worktree add "../<repo>-handoff-<target-branch>" "<target-branch>"85# only when Git says the branch is already checked out by the source worktree:86git worktree add --force "../<repo>-handoff-<target-branch>" "<target-branch>"87```8889- If the target branch does not exist locally, stop and ask whether it should be created from `origin/<target-branch>` or another base.9091### 4) Build a non-mutating snapshot from the source worktree9293```bash94tmpdir=$(mktemp -d)95base=$(git rev-parse HEAD)96alt_index="$tmpdir/handoff.index"97cp "$(git rev-parse --git-path index)" "$alt_index"98GIT_INDEX_FILE="$alt_index" git add -A99snapshot_tree=$(GIT_INDEX_FILE="$alt_index" git write-tree)100snapshot_commit=$(printf 'worktree-handoff snapshot\n' | git commit-tree "$snapshot_tree" -p "$base")101```102103- This captures tracked, staged, unstaged, and untracked paths without touching the real source index or worktree.104- `snapshot_commit` is temporary and does not update any branch ref.105- This handoff preserves the source worktree contents, not the exact staged/unstaged split. The destination will typically receive the snapshot as staged changes.106107### 5) Check the target before applying108109```bash110git -C "<target-worktree>" status --short111```112113- Existing tracked changes and non-colliding untracked files are fine, including small unrelated dirtiness such as `bun.lock` updates. Do not stop just because the destination is dirty.114- If the target already has colliding untracked paths, report the collision instead of forcing the handoff.115116### 6) Apply the handoff onto the target branch117118```bash119git -C "<target-worktree>" cherry-pick -n "$snapshot_commit"120```121122- This applies the source snapshot only in the target worktree. The source worktree must remain untouched.123- Stop on conflicts and report them. Do not resolve them silently.124- Do not run `git stash push`, `git stash pop`, or `git stash apply` in the source worktree.125126### 7) Verify the result127128```bash129git status --short --branch130git -C "<target-worktree>" diff --name-only --diff-filter=U131git -C "<target-worktree>" status --short132```133134- Confirm the source status matches the preflight snapshot. If it differs, report an unexpected source mutation immediately.135- The target should now contain the handed-off snapshot.136137## Reporting Rules138139- If the apply succeeds cleanly, report:140 - source ref/worktree141 - target branch/worktree142 - whether the target already had local changes143 - whether the source status matched before/after exactly144 - whether a temporary target worktree was created145 - that the destination received a staged snapshot of the source state146- If there are conflicts, stop after applying and report:147 - conflicted files148 - whether the target branch already had overlapping edits149 - that the source worktree remained unchanged150 - the most likely resolution approach151152Even if a conflict looks trivial, do not silently resolve it. Ask how to proceed after summarizing the conflict.153154Never describe success as "the source worktree is now clean again". If the user wants the source cleaned after verification, that is a separate explicit follow-up step.