Skip to content

Commit e55fdae

Browse files
huangyiireneclaude
andauthored
fix(hooks): print the --no-track worktree recipe in both guards' remediation text (#7000)
`.claude/hooks/guard-main-checkout.sh` and `.claude/hooks/guard-main-checkout-bash.sh` each end their block message with the worktree recipe to run instead, and both created the branch with a plain `-b`. PR #6976 hardened the prescribed form in `CLAUDE.md` and `AGENTS.md`; the hooks' copy was left behind — and it is the higher-leverage copy, delivered at the exact moment an agent is about to act, so it is the one most likely to be run verbatim. The hazard is the one #6976 established: plain `-b` writes the new branch's upstream keys (`branch.NAME.remote`, `branch.NAME.merge`) into the one `.git/config` that every linked worktree of a repo shares. That write can fail after the branch is created, leaving a branch with no worktree — a half state the error text does not name. Read as "the worktree exists", the agent starts editing the shared primary checkout, which is the one thing these two guards exist to prevent. Additive, not a recipe rewrite: this repo's hooks already emitted the fetch-hardened base (`git fetch origin main && … origin/main`, landed for ui#6208), so the missing flag was the only surviving divergence from the prescribed form. One word added per file, net ±0 lines in both. Claude-Session: https://claude.ai/code/session_01EnE7G31tqbxN1rqpQmzurT Co-authored-by: Claude <noreply@anthropic.com>
1 parent ce7b7ec commit e55fdae

3 files changed

Lines changed: 44 additions & 2 deletions

File tree

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
---
2+
---
3+
4+
PreToolUse-hook prose only: no published package's `src/` changed, so nothing ships.
5+
6+
**Both worktree guards now print `--no-track` in the recipe they emit when they block.**
7+
`.claude/hooks/guard-main-checkout.sh` and `.claude/hooks/guard-main-checkout-bash.sh` each
8+
end their block message with the worktree recipe to run instead, and both created the branch
9+
with a plain `-b`. PR #6976 hardened the prescribed form in `CLAUDE.md` and `AGENTS.md`; the
10+
hooks' copy was left behind, and it is the higher-leverage one — it is delivered at the exact
11+
moment an agent is about to act, so it is the copy most likely to be run verbatim.
12+
13+
The hazard is the one #6976 established: plain `-b` writes the new branch's upstream keys
14+
(`branch.NAME.remote`, `branch.NAME.merge`) into the one `.git/config` that every linked
15+
worktree of a repo shares. That write can fail *after* the branch is created, leaving a branch
16+
with no worktree — a half state the error text does not name. Read as "the worktree exists",
17+
the agent starts editing the shared primary checkout, which is the one thing these two guards
18+
exist to prevent. Measured on git 2.43.0 in #6976: `--no-track` removes the config write and
19+
still bases the worktree on `origin/main`, and `git push -u origin BRANCH` sets the upstream
20+
one command later.
21+
22+
Additive, not a recipe rewrite: this repo's hooks already emitted the fetch-hardened base
23+
(`git fetch origin main && … origin/main`, landed for ui#6208), so the only surviving
24+
divergence from the prescribed form was the missing flag. One word added per file, net ±0
25+
lines in both.
26+
27+
Deliberately unchanged, each for its own reason:
28+
29+
- `.changeset/6208-worktree-recipe-fetch-base.md` quotes the pre-#6208 recipe as the record of
30+
a past change. Editing a historical changeset would rewrite that record (adjudicated in
31+
PR #6976).
32+
- The two `-cmp` comparison-tree lines in `CLAUDE.md` / `AGENTS.md` create no branch and take
33+
an explicit ref from the caller, so there are no upstream keys to write and the flag does not
34+
apply — the same reading #6208 recorded for them.
35+
- `.claude/hooks/guard-tree-enum.selftest.sh`'s allow-case is a command payload fed to a
36+
different guard to assert that ordinary commands pass through it. It is test input, not text
37+
any agent is told to run.
38+
39+
Verified by re-running all three self-test matrices this repo ships (`guard-main-checkout-bash`
40+
121, `guard-shared-stash` 41, `guard-tree-enum` 36 — 0 failed each, unchanged from before the
41+
edit, because no case pins the remediation string), and by invoking both hooks directly and
42+
reading the text they emit.

‎.claude/hooks/guard-main-checkout-bash.sh‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -541,7 +541,7 @@ only, so the identical edit expressed as a shell command used to slip through in
541541
its HEAD switched and its tree reset under you, clobbering uncommitted work. A feature
542542
branch on the shared checkout is NOT enough; you need a dedicated worktree:
543543
544-
git fetch origin main && git worktree add ../${name}-<task> -b <branch> origin/main
544+
git fetch origin main && git worktree add --no-track ../${name}-<task> -b <branch> origin/main
545545
cd ../${name}-<task> && pnpm install # then re-run the command there
546546
547547
Always fine, no flag needed:

‎.claude/hooks/guard-main-checkout.sh‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ This repo is edited by multiple agents at once — the shared checkout gets its
5454
switched and tree reset under you, silently clobbering uncommitted work. A feature
5555
branch on the shared checkout is NOT enough; you must be in a dedicated worktree:
5656
57-
git fetch origin main && git worktree add ../${name}-<task> -b <branch> origin/main
57+
git fetch origin main && git worktree add --no-track ../${name}-<task> -b <branch> origin/main
5858
cd ../${name}-<task> && pnpm install # then re-run your edits there
5959
6060
This guard checks the edited file's OWN repo, so sibling repos are covered too.

0 commit comments

Comments
 (0)