Claude Code Hooks 實戰「提交前自動跑測試」:PreToolUse 攔住 git commit,測試不過就退出碼 2,附 Windows 注意點

只寫一個完整例子:讓 Claude Code 每次要執行 git commit 之前,先自動跑項目測試,沒通過就攔下並把輸出交給它修。本文按官方 Hooks 文檔給出腳本、settings.json 配置、測試方法、排錯和 Windows 的兩處坑。

NNathaniel bigo··原創首發·AI 輔助撰寫
10 分鐘讀完
資料核對於 2026-11-05 · 依據官方文檔與公開資料整理 Pro 帳號
本文根據 Claude Code 官方文檔《Automate actions with hooks》《Hooks reference》《Best practices for Claude Code》《Tools reference》整理,資料核對於 2026-11-05。配圖為本站整理的示意圖,不是介面截圖。本站(bigolab.com)不是 Anthropic 官方網站。

適用於誰

  • 已經知道 Hooks 是什麼,想要一個能直接套用的實戰例子的人;
  • 總擔心 Claude 沒跑測試就提交了的人;
  • 配了鉤子卻發現沒生效、不知從哪查的人。

鉤子的基礎概念和事件列表,站內已有 /guides/claude-code-hooks,本文只做一個例子:提交前自動跑測試。

結論先說

  1. 用 PreToolUse 事件。 官方說它在工具調用執行之前觸發,可以阻止。Claude 要運行 git commit 的那條 Bash 命令,就是被攔的對象。
  2. 阻止的辦法是退出碼 2。 官方:腳本往 stderr 寫原因並以退出碼 2 結束,Claude Code 會取消這次調用,並把 stderr 的內容作為反饋交給 Claude,讓它調整做法。
  3. 退出碼 0 不等於批准,只是「沒有意見」,調用仍走正常的權限流程。
  4. 別的退出碼(比如 1)一般不會攔截,只是個非阻塞的錯誤提示,操作照常進行。所以腳本里測試失敗時必須明確寫 exit 2,不要讓腳本靠測試命令自己的退出碼「碰巧」失敗。
  5. 用 if 字段縮小範圍:官方的 if 用權限規則語法,只有命令匹配時才啟動鉤子進程,不用每條 Bash 命令都跑一遍。

提交前跑測試鉤子的流程

圖:本站根據 Claude Code 官方文檔:Hooks 整理的示意圖

第一步:寫腳本

在項目裏建 .claude/hooks/test-before-commit.sh。思路沿用官方「保護文件」例子的結構:從標準輸入讀 JSON,取出 tool_input.command,決定放行還是攔截。

bash
#!/bin/bash
# .claude/hooks/test-before-commit.sh
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')

# 只在命令裏確實有 git commit 時才跑測試
case "$COMMAND" in
  *"git commit"*) ;;
  *) exit 0 ;;
esac

cd "$CLAUDE_PROJECT_DIR" || exit 2

OUTPUT=$(npm test 2>&1)
STATUS=$?

if [ $STATUS -ne 0 ]; then
  echo "測試沒有通過,已阻止這次提交。請先修復失敗的測試再提交。測試輸出的最後 40 行:" >&2
  echo "$OUTPUT" | tail -n 40 >&2
  exit 2
fi

exit 0

說明:

  • 官方的 Bash 鉤子輸入裏,tool_input.command 就是 Claude 要運行的命令;用 jq 取出來是官方示例的做法。如果你的機器沒有 jq,官方排錯裏說可以安裝它,或用 Python、Node.js 解析 JSON。
  • npm test 換成你項目的測試命令。想只跑快的那部分測試,用你項目裏對應的命令。
  • 在 macOS 和 Linux 上,官方說鉤子腳本必須有可執行權限:chmod +x .claude/hooks/test-before-commit.sh。
  • 測試輸出只回傳最後 40 行,避免把大量日誌灌進上下文,這是本站的做法。

第二步:註冊鉤子

在項目的 .claude/settings.json 裏加入(提交進倉庫就是全隊共享;只想自己用,放 .claude/settings.local.json):

json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash|PowerShell",
        "hooks": [
          {
            "type": "command",
            "if": "Bash(git commit *)",
            "timeout": 300,
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/test-before-commit.sh"
          },
          {
            "type": "command",
            "if": "PowerShell(git commit *)",
            "timeout": 300,
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/test-before-commit.sh"
          }
        ]
      }
    ]
  }
}

對照官方文檔:

  • matcher 區分大小寫,按工具名匹配;Bash|PowerShell 是官方在講 PowerShell 工具時給的寫法,因為 Windows 上 Claude 可能走 PowerShell 工具而不是 Bash 工具,只匹配 Bash 是不夠的。
  • 官方說,要匹配多個工具名,可以分成幾個處理器,各帶自己的 if,所以這裏寫了兩條。
  • timeout 單位是秒;官方說命令類鉤子預設是 10 分鐘。測試跑得久就按需調大,太小會被取消。官方說多數事件裏超時的鉤子不產生任何決定,也就是說超時不會攔截,提交會照常進行,所以別把超時設得比測試耗時還短。
  • "$CLAUDE_PROJECT_DIR"/.claude/hooks/... 是官方「保護文件」例子裏引用腳本的寫法。

第三步:不靠 Claude,自己先測腳本

官方排錯裏給了辦法:用管道把一段示例 JSON 餵給腳本,再看退出碼。

bash
# 不是提交命令:應當直接放行,退出碼 0
echo '{"tool_name":"Bash","tool_input":{"command":"git status"}}' | .claude/hooks/test-before-commit.sh; echo $?

# 是提交命令:測試通過返回 0,不通過返回 2
echo '{"tool_name":"Bash","tool_input":{"command":"git commit -m test"}}' | .claude/hooks/test-before-commit.sh; echo $?

故意把一個測試改壞,再跑第二條,應該看到失敗輸出和退出碼 2;改回來後應該是 0。

第四步:在 Claude Code 裏驗證

  1. 輸入 /hooks,確認 PreToolUse 下有這個鉤子。官方說如果剛改了設定文件、幾秒後還沒出現,重啟會話。
  2. 故意讓測試失敗,然後說:「請提交當前改動,提交資訊寫 test」。
  3. 按 Ctrl+O 打開會話記錄,看鉤子的結果。官方說被阻止時通常會看到隨阻止一起給出的資訊。
  4. 再讓它修好測試後重新提交,這次應當放行。

提示詞 1:讓 Claude 幫你寫鉤子

text
請為這個項目寫一個 Claude Code 鉤子:每次 Claude 要執行 git commit 前,先運行【npm test】;測試失敗就阻止提交,並把輸出的最後 40 行作為原因反饋給 Claude。
要求:1)用 PreToolUse,只針對 git commit 命令;2)腳本放 .claude/hooks/,註冊到 .claude/settings.json;3)測試失敗必須明確 exit 2;4)寫完後用管道喂 JSON 的方法測試放行和攔截兩種情況,把結果給我。
寫完用 /hooks 讓我確認。

提示詞 2:被攔截之後

text
剛才提交被鉤子攔下了,請讀鉤子給出的測試輸出,找出失敗原因並修復。
修好後重新運行測試,通過了再提交。不要為了讓測試通過而刪除測試或修改它的預期結果,除非先告訴我原因。

提示詞 3:讓 Claude 審查鉤子的漏洞

text
請審查 .claude/hooks/test-before-commit.sh 和 .claude/settings.json 裏的鉤子配置,列出它攔不住或會誤攔的情況,例如:
1)git commit --amend、git commit -a、先 git add 再 && git commit 的組合命令;
2)git -C 某目錄 commit 這類帶參數的寫法;
3)測試命令不存在、測試超時、jq 沒安裝時腳本會怎樣(是放行還是攔截);
4)在 Windows 上由 PowerShell 工具發起的提交能否被攔住。
對每一項說明現狀和建議的改法,先只報告,不要修改文件。

鉤子沒生效時的排查

圖:本站根據官方文檔整理的示意圖

排錯對照(官方「Limitations and troubleshooting」)

  • 鉤子沒有觸發:/hooks 裏是否在 PreToolUse 下;matcher 是否完全匹配工具名(區分大小寫);事件類型對不對,PreToolUse 在執行前、PostToolUse 在執行後,而後者無法撤銷已發生的動作。
  • 看到 PreToolUse hook error:腳本意外返回了非零退出碼。用上面的管道辦法手動測試,看是不是 jq 沒裝、路徑找不到,或腳本沒有可執行權限。
  • 想看細節:官方說用 claude --debug 啟動,或會話中運行 /debug 打開日誌。

Windows 的兩處坑

  • 需要有 Bash 來運行這個腳本。官方說,Windows 上沒有 Git Bash 時,shell 形式的鉤子預設用 PowerShell 運行,Bash 寫的腳本可能失敗;安裝 Git for Windows,或用 CLAUDE_CODE_GIT_BASH_PATH 指向 Git Bash,然後開新會話。另外官方還提醒:Windows 沒有 Git Bash 時,PreToolUse 的鉤子失敗或超時可能直接阻止工具調用,錯誤訊息裏會寫着 blocking because Git Bash wasn't found。
  • 路徑帶反斜槓。官方說,Windows 上文件工具傳給鉤子的路徑是反斜槓,用正斜槓寫的比較永遠匹配不上,鉤子會「什麼也沒攔」。本例只看命令文本,不受影響;如果你改寫成按路徑攔截,務必先把反斜槓換成正斜槓。

更多 Windows 上的使用細節見 /guides/claude-code-windows-pitfalls-paths-git-bash-powershell。

另一種思路:Stop 鉤子

官方最佳實踐裏有一個相近的例子:Stop 鉤子在 Claude 想結束回覆時運行檢查,退出碼 2 會讓它回去繼續幹活,官方示例寫的是 pnpm tsc --noEmit 1>&2 || exit 2。把測試命令放進去,就是「每次回覆結束前測試必須通過」。注意官方說:連續阻止八次、中間沒有工具調用時,Claude Code 會放行;腳本里應讀取輸入裏的 stop_hook_active 字段,已在續跑時提前退出。兩種方式可以按需選:想在「提交」這個節點把關用本文的方法,想要「每一輪結束都驗證」用 Stop。

它攔不住什麼

PreToolUse 鉤子只管 Claude 發起的命令。你自己在終端裏手敲的 git commit、別的編輯器裏的提交,都不經過它。想對所有提交生效,要用 Git 自帶的 pre-commit 鉤子,那是 Git 的機制,不屬於 Claude Code。另外官方明確說 if 過濾是盡力而為的,要硬性禁止某類命令,應該用權限規則,見 /guides/claude-code-permission-modes。

訂閱和額度

鉤子本身不佔額度,但每次被攔截後 Claude 會讀測試輸出並重試,測試輸出越長越占上下文,所以只回傳末尾幾十行。訂閱選擇見 /chongzhi/claude-code,價格和額度以官方頁面當前顯示為準。

相關教學

參考資料

  • Claude Code 文檔:Automate actions with hooks — https://code.claude.com/docs/en/hooks-guide
  • Claude Code 文檔:Hooks reference — https://code.claude.com/docs/en/hooks
  • Claude Code 文檔:Best practices for Claude Code — https://code.claude.com/docs/en/best-practices
  • Claude Code 文檔:Tools reference — https://code.claude.com/docs/en/tools-reference

Nathaniel 的更多內容

  1. 01

    Claude Code 在 Windows 上的常見坑:Git Bash 還是 PowerShell、路徑反斜槓、假報錯、WSL 怎麼選

    Windows 上用 Claude Code,裝好之後最容易踩的是:用哪個 shell、路徑寫法不一致、grep 沒匹配就報錯、鉤子沒生效、WSL 和原生怎麼選。本文逐條按官方文檔整理原因和處理辦法,附三段提示詞和一張對照表。

    Claude0
  2. 02

    Claude Code 自定義斜槓命令與 Skill 實戰:從零寫一個「生成更新日誌」的 /release-notes,含傳參、預執行命令和調試

    概念看過了,還是不知道從哪下手?本文按 Claude Code 官方「Extend Claude with skills」寫一個完整可用的例子:用 /release-notes 根據 git 記錄生成更新日誌,覆蓋目錄、frontmatter、傳參、預執行命令、預授權和調試。

    Claude0
  3. 03

    Claude Code 部署網站:先寫 Dockerfile 和 compose 在本機跑通,再按清單上雲伺服器,別讓它直接改線上

    想讓 Claude Code 幫你把網站部署到雲伺服器。本文只寫通用做法,按 Docker 官方文檔講:讓它寫 Dockerfile、.dockerignore 和 compose,在本機跑通,端口和數據卷怎麼設,再給出上線清單,並說明為什麼不要讓它直接動線上機器。

    Claude0
  4. 04

    Claude Code 寫爬蟲與數據清洗:先查 robots.txt 和網站條款,控制頻率,原始數據留一份再清洗

    想讓 Claude Code 寫爬蟲抓數據再清洗。本文先講合規:robots.txt 不是授權也不是安全措施、網站條款要自己讀;再講怎麼用 Python 標準庫檢查規則、小樣本先試、儲存原始數據,以及用 pandas 清洗,附四段提示詞。

    Claude0
  5. 05

    Claude Code 寫 Chrome 擴展:按 Manifest V3 起步,加載未打包的擴展,改了哪些文件要重新加載

    想讓 Claude Code 幫你寫一個 Chrome 擴展。本文按 Chrome 官方擴展文檔講:manifest.json 的最小寫法、在 chrome://extensions 加載未打包的擴展、哪些改動要刷新、怎麼看控制檯和報錯,再給四段提示詞,以及權限要盡量少。

    Claude0
  6. 06

    Claude Code 寫安卓 App:Android Studio 建項目、讓它用 gradlew 編譯安裝,報錯和日誌怎麼餵給它

    想讓 Claude Code 幫你寫安卓 App。官方文檔沒有專門的安卓教學,本文把 Claude Code 官方工作流和安卓官方命令行文檔拼在一起:Android Studio 建項目、gradlew 編譯安裝、模擬器和真機、測試與日誌,附四段提示詞。

    Claude0

同產品的其他教學

  1. 01

    Claude Code 用數據庫 MCP 查數據、出報表:只讀帳號、先看口徑再看數字,結果別一次拉太多行

    想用自然語言讓 Claude Code 查數據庫、出統計報表,而不是寫後端接口。本文按官方 MCP 頁面和 DBHub 說明講:怎麼連 PostgreSQL、MySQL、SQLite、輸出太大怎麼辦、怎麼讓它先說明口徑、怎麼核對數字,附三段提示詞。

    Claude0
  2. 02

    Claude Code 配 Figma MCP 還原設計稿:插件或一條命令安裝,複製圖層連結,小塊小塊地讓它出代碼

    想讓 Claude Code 照 Figma 設計稿寫前端代碼。本文按 Figma 官方開發者文檔講:遠程伺服器地址、插件和手動兩種安裝、怎麼複製圖層連結、為什麼要選小塊、座位類型與調用次數限制,並給三段還原設計稿的提示詞。

    Claude0
  3. 03

    Claude Code 管理 GitHub issue:用 gh 命令還是 GitHub MCP,怎麼裝、怎麼限權、怎麼讓它分揀和回覆 issue

    讓 Claude Code 讀 issue、分揀標籤、起草回覆、關聯 PR,有兩條路:裝好 gh 命令行直接用,或連 GitHub 官方 MCP 伺服器。本文按兩邊官方文檔講安裝命令、令牌權限、只讀模式,並給出三段分揀提示詞和限權設定。

    Claude0
  4. 04

    Claude Code 配 Playwright MCP 做瀏覽器測試:一條命令安裝,讓它打開頁面、點按鈕、讀控制檯,再把流程寫成測試

    想讓 Claude Code 自己打開瀏覽器測試你的網頁。本文按微軟 Playwright MCP 官方倉庫和 Claude Code 官方 MCP 文檔講:安裝命令、怎麼確認連上、有頭無頭與隔離參數、一次測試的提示詞,以及它不是安全邊界這件事。

    Claude0
  5. 05

    Claude Code 寫文檔、README 和代碼註釋:先讓它讀代碼再動筆,指定風格,寫完逐條核對命令能不能跑

    想讓 Claude Code 給項目補 README、接口文檔和註釋,又怕它編造不存在的命令和參數。本文按官方「Handle documentation」工作流講:先找沒有文檔的代碼、指定風格、寫完核對,附四段可複製提示詞和驗證辦法。

    Claude0
  6. 06

    用 Claude Code 整理電腦文件、批量重命名、處理表格:先出清單再執行,副本操作和權限設定

    Claude Code 不只能寫代碼,官方說它能在任何文件夾裏搜尋、編輯和整理內容。本文講非程式員怎麼用它整理下載文件夾、批量重命名、處理表格:先出整理清單、用副本操作、權限怎麼設,附四段提示詞和撤銷辦法。

    Claude0

0 條評論

登入 後參與評論

還沒有評論,來搶沙發~