Files
ISEP/hooks/not-my-branch-guard.sh
T
Leo c2638668e3 ISEP 0.1.0:環境設定收成一個 plugin,本機與雲端共用一份
leo 2026-08-20:「同一個 plugin 你用,薄殼也用,保證兩邊同步」
              「我要你幫雲端做薄殼,永遠都有問題,你要做的就是這組設定
                你自己可以 dogfooding」

搬進來:41 支 hook(51 條註冊)/7 支 command/2 支 skill/23 支腳本。
不搬 .env、wiki、docs——那些是知識不是環境。

51 條 hook 路徑全部從 $CLAUDE_PROJECT_DIR/.claude/hooks/ 改成 ${CLAUDE_PLUGIN_ROOT}/hooks/,
零漏網。那正是薄殼一直壞掉的根:雲端 cwd 不是真身,寫死路徑就斷。

尚未驗證:Claude Code 能不能從私有 Gitea repo 裝 marketplace(要憑證)。
下一步就是在本機實際裝一次,通了才動雲端 bootstrap.sh。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 11:41:46 +08:00

82 lines
3.8 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/sh
# not-my-branch-guard.sh — PreToolUseBash):**不准 commit 到別人正在施工的分支。**
#
# 🔴 為什麼是硬擋(2026-08-16,總管一小時內犯兩次):
# 第一次:把 branch-hold 的落帳 commit 打在 `feat/gitea-arm-per-issue` 上(agent 的分支)
# 第二次:把 `ticket decide` 的 commit 打在**同一條**分支上
# ——而且第一次之後,總管在回覆裡寫了「這正是共用工作區那條教訓咬到我自己」。
# **寫下教訓沒有讓他不再犯。** 一小時後同一個錯又來一次。
#
# 為什麼會犯:總管的 shell 與 agent 共用同一個工作區,**分支是誰上一次切的就是誰的**。
# `git commit` 不會問「你確定要打在這條上嗎」,它只是照做。
# 而 `git push gitea main` 在那種狀態下會回 **`Everything up-to-date`**
# ——**假成功**,因為本機 `main` 確實沒動過。真訊號是「本機 HEAD 與遠端對不上」。
#
# 判準:**當前分支出現在 `.claude/branch-holds.md` 裡** ⇒ 那是有人(agent)正在上面施工的
# 分支,或刻意保留的分支。兩種都不該由總管順手 commit 進去。
#
# 刻意不擋的:
# · 在 `main` 上 commit(那是總管的地盤,另有 main-and-prod-push-guard 管推送)
# · 不在 branch-holds 名單上的分支(總管自己開的工作分支)
# · 非 commit 的 git 動作(statuslogdiffcheckout…)
#
# 真的要在那條分支上 commit(例如接手一條被放棄的分支):
# 把它從 `branch-holds.md` 移除(那本來就是「它不再是別人的」的正確表示法),
# 或 `NOT_MY_BRANCH_OK=1 git commit ...`(留痕,commit 說明寫理由)。
set -eu
[ "${NOT_MY_BRANCH_OK:-}" = "1" ] && exit 0
PAYLOAD=$(cat 2>/dev/null || echo '{}')
CMD=$(printf '%s' "$PAYLOAD" | python3 -c '
import sys, json
try: d = json.load(sys.stdin)
except Exception: sys.exit(0)
print((d.get("tool_input") or {}).get("command") or "")
' 2>/dev/null || true)
# 只看 commit(含 -m-F--amend
case "$CMD" in
*"git commit"*) ;;
*) exit 0 ;;
esac
PROJ="${CLAUDE_PROJECT_DIR:-$(pwd)}"
HOLDS="$PROJ/.claude/branch-holds.md"
[ -f "$HOLDS" ] || exit 0
BR=$(git -C "$PROJ" rev-parse --abbrev-ref HEAD 2>/dev/null || echo "")
[ -n "$BR" ] || exit 0
case "$BR" in main|master|HEAD) exit 0 ;; esac
# 分支名有沒有出現在 branch-holds 的條目裡(格式:- `分支名`(repo):理由)
grep -q "^- \`${BR}\`" "$HOLDS" 2>/dev/null || exit 0
REASON=$(grep -A1 "^- \`${BR}\`" "$HOLDS" | head -2 | tr '\n' ' ' | cut -c1-160)
cat >&2 <<EOF
🚫 這條分支不是你的——它列在 branch-holds 上(別人正在施工,或刻意保留)
當前分支:$BR
它的條目:${REASON}
🔴 **2026-08-16 總管一小時內在同一條分支上犯了兩次**,而且第一次之後
還在回覆裡寫了「這正是共用工作區那條教訓咬到我自己」——**寫下教訓沒有讓他不再犯。**
【為什麼這個錯特別難發現】
打錯分支之後跑 \`git push gitea main\` 會回 **\`Everything up-to-date\`**——
**那是假成功**,因為本機 \`main\` 確實沒動過。
真訊號是「**本機 HEAD 與遠端對不上**」,而那句話不會自己跳出來。
【現在怎麼做(擇一)】
① **切回 main 再 commit**(絕大多數情況的正解):
git checkout main && <你的 git commit ...>
② **已經打錯了要救**
git checkout main && git cherry-pick <那顆 sha>
git branch -f $BR gitea/$BR # 把別人的分支還原成遠端狀態
③ **你真的要接手這條分支**:先把它從 \`.claude/branch-holds.md\` 移除
(那本來就是「它不再是別人的」的正確表示法),再 commit
④ 真有例外:\`NOT_MY_BRANCH_OK=1 git commit ...\`,並在 commit 說明寫理由
EOF
exit 2