兩支閘改看「指令要動的那個 repo」,不看 hook 自己的環境/cwd(inkstone/ISEP#109 → comment 6629)
① line-needs-own-worktree.sh:出路 `WORKTREE_OK=1 git -C … checkout …` 改認指令字串裡的字面前綴
(舊版讀 hook 自己的環境變數,PreToolUse hook 跟指令不是同一個行程,那行永遠走不通)。
判準是位置不是字:前綴必須掛在會移動 HEAD 的那條 git 指令上。
lib/checkout_target_dir.py 加 `--escape NAME=1`;push_target_dir._classify 在 strip_env 時
把前綴留在 verb 事件裡(find_push_target 行為不變,主線閘 10+19 條照綠)。
② github-contact-guard.sh:remote 名在「這條指令實際會推的那個 repo」裡解(沿用 lib/push_target_dir.py
解 cd 鏈/-C/子殼),解不出來才退回 cwd。判準仍是 remote URL 主機,不是「有 -C 就放行」。
測試:A24 59→69(E 群把閘印的那一行原樣餵回去;舊閘 3 條紅)、
A39 14→26(payload 帶 cwd、cwd≠目標 repo;舊閘 7 條紅=4 誤攔+3 漏擋)。
盤點表:61 支/85 條,改判準不加閘,當場數的。
版本:待總管定版。
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0178ef1fGw3XeZtpN7LaZrm4
This commit is contained in:
@@ -91,21 +91,31 @@ def _classify(tokens, verbs=("push",), strip_env=False):
|
||||
stays deliberately loose here (the verb may sit anywhere after `git`) --
|
||||
callers re-walk the returned token list to confirm command position, so
|
||||
a false positive at this layer costs nothing."""
|
||||
body = tokens
|
||||
if strip_env:
|
||||
# `FOO=1 git checkout …` -- an env prefix doesn't change which command
|
||||
# runs. Opt-in so find_push_target's behaviour stays byte-identical;
|
||||
# checkout_target_dir.py turns it on (its predecessor stripped these,
|
||||
# and dropping that would have been a silent regression -- caught by
|
||||
# the worktree gate's own case ㉒).
|
||||
#
|
||||
# 2026-09-07 (inkstone/ISEP#109 -> comment 6587): the prefix is skipped
|
||||
# for *classifying* the statement, but the "verb" event hands back the
|
||||
# full token list, prefix included. The worktree gate's escape hatch is
|
||||
# exactly that prefix (`WORKTREE_OK=1 git checkout …`), and a PreToolUse
|
||||
# hook can only see it in the command string -- it never reaches the
|
||||
# hook's own environment. Dropping it here made the printed way out
|
||||
# unwalkable. Callers that don't care simply skip leading NAME=value
|
||||
# tokens themselves (checkout_target_dir._moves_head does).
|
||||
i = 0
|
||||
while i < len(tokens) and _ENV_ASSIGN.match(tokens[i]):
|
||||
i += 1
|
||||
tokens = tokens[i:]
|
||||
if not tokens:
|
||||
body = tokens[i:]
|
||||
if not body:
|
||||
return ("other", None)
|
||||
if tokens[0] == "cd" and len(tokens) > 1:
|
||||
return ("cd", tokens[1])
|
||||
if tokens[0] == "git" and any(v in tokens[1:] for v in verbs):
|
||||
if body[0] == "cd" and len(body) > 1:
|
||||
return ("cd", body[1])
|
||||
if body[0] == "git" and any(v in body[1:] for v in verbs):
|
||||
return ("verb", tokens)
|
||||
return ("other", None)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user