Claude Code hooks替代pre-commit边界
以「8 个 hooks 替代 pre-commit」经验帖为个案,对照官方事件名讲清能拦什么、不能替什么、和 git 怎么分工。

有人把「提交前要记的那串清单」搬进 Claude Code hooks,标题就写成替代 pre-commit。Claude Code hooks 替代 pre-commit 这件事,更贴近现实的说法是:hooks 管 agent 动作环,git hook 管仓库提交闸,两边叠用才完整。
经验帖在替什么,又在夸张什么
Jerry PM 在 2026-08-05 的 Medium 文《8 Claude Code Hooks That Replaced My Pre-Commit Checks》开篇很具体:曾经靠脑子记「跑 linter、别直推 main、别把 API key 写进配置、重跑失败测试」,每周仍会漏一项;后来改成 hooks 自动开火——改文件就格式化、会话里推不了 main、长任务结束响一声。这是个人工作流个案,官方从未声明 hooks 等于 pre-commit 框架。
读这类帖子时,把「替代」理解成「我不再依赖记忆去做同一批检查」即可。真正可复用的是机制:确定性脚本挂在生命周期事件上,模型没法用「我忘了」跳过。帖子里的八条具体 shell,若你打不开会员全文,不必硬抄;按官方事件自己拼最小集更稳。公开导语已经点出三类收益:格式化跟手、危险 git 被挡、完成时有声响提醒。
官方事件名:先对齐文档再抄配置
Hooks 参考把 hooks 定义成在生命周期固定点执行的 shell、HTTP 或 prompt。和「提交时」无关的事件也很多,常见包括:
- 会话级:
SessionStart、SessionEnd - 回合级:
UserPromptSubmit、Stop、StopFailure - 工具环:
PreToolUse、PostToolUse、PostToolUseFailure - 提醒:
Notification(如permission_prompt、idle_prompt) - 压缩:
PreCompact、PostCompact - 团队相关:
TeammateIdle、TaskCreated、TaskCompleted
配置写在 ~/.claude/settings.json(本机全局)或项目 .claude/settings.json(可进仓库)。改完用 /hooks 只读浏览确认已加载;菜单不能编辑,要改 JSON。事件名拼错或 matcher 不对时,表现就是「写了不触发」,排查见 hooks 不触发六步排查。
退出码语义必须按文档:多数事件里 exit 2 才是阻断;exit 0 成功;其它非零常常是非阻断错误,动作仍会继续。想拦住危险命令却写成 exit 1,等于没拦。这是抄经验帖时最容易带歪的一点。
hooks 能拦什么:动作发生前与发生后
能卸掉「提交前那份记忆清单」的,主要是这几类。
PreToolUse(可阻断):工具真正执行前开火。官方示例用它挡破坏性 Bash、挡对 .env / package-lock.json / .git/ 的 Edit|Write。脚本从 stdin 读 JSON,匹配到危险路径就 echo … >&2; exit 2,Claude 会收到原因并改道。把「禁止 git push 到 main」「禁止 --no-verify」做成 Bash matcher,也是同一模式。
PostToolUse(已发生,偏修正):Edit|Write 成功后跑 Prettier / 项目 formatter,等于「每次改完都格式化」,不用等 commit。官方 hooks-guide 给了 jq 取 file_path 再 prettier --write 的片段。
Stop 与 Notification(节奏与提醒):Stop 可在 Claude 声称结束时再跑测试;exit 2 会阻止结束、逼它继续修。Notification 在等许可或 idle 时弹桌面通知,对应 Jerry 文里「响一声让我抬头」。这和 pre-commit 完全不是一类闸,但确实卸掉「盯着终端」的负担。
SessionStart(compact 后补上下文):压缩后用 matcher: "compact" 往上下文打关键约定,避免「格式化规则只写在对话里、一压就丢」。
这些能力覆盖的是 agent 会话内的动作。Cursor 云端 agent 另有一套对话向 hooks,事件名不同,别混配;对照见 云端 agent hooks 怎么配。
不能替代什么:仓库闸与多人基线
hooks 替不了下面几件事。
非 Claude Code 的提交路径:同事用 IDE、GUI、另一台没装项目 settings 的机器直接 git commit,你的 Claude hooks 根本不在场。仓库质量基线仍要靠 .git/hooks、pre-commit 框架或 CI。
已落地的历史债与全量扫描:PostToolUse 通常只碰当前改的文件。全仓库 secret 扫描、license 检查、全量 typecheck,仍适合 commit/push/CI 闸。你在会话里「全绿」,不代表仓库门禁会对别人同样绿灯。
可被绕过的本地策略:懂行的人可以改 settings、关 hook、或不用 Claude Code。需要硬策略时,要叠权限层与服务端闸,别只信本地 hook;相关讨论见 Claude Code / Cursor 策略执行。
判断型审查:「这次重构是否破坏领域边界」靠 prompt/agent hook 只能辅助,不能当成确定性门禁。官方也区分:确定性用 command hook,要判断再用 prompt/agent hook,且生产策略优先 command。
所以标题里的「替代」,若理解成「删掉仓库 pre-commit、只留 Claude hooks」,会在第一条人工提交上穿帮。经验帖解决的是作者本人的遗忘,不是团队仓库的单一真相源。
和 git pre-commit 怎么分工
一张对照就够:
| 闸口 | 何时开火 | 典型职责 |
|---|---|---|
| Claude PreToolUse / PostToolUse | agent 调工具前后 | 挡危险命令、护敏感文件、改完即格式化、会话内反馈 |
| Claude Stop | 声称完成时 | 跑相关测试,失败则不许收工 |
| git pre-commit / pre-commit 框架 | git commit 时 | 全员统一的 lint、secret、commit-msg |
| CI | push / PR | 慢测、全量检查、不可绕过的门禁 |
实用叠法:把 pre-commit 里快、且只针对改动文件的检查,接到 PostToolUse 或拦截 git commit 的 PreToolUse 上,让 Claude 在会话里自修;完整 pre-commit run 与 CI 仍保留。两边都会跑时,Claude 侧先失败、git 侧再兜底,比只留一层稳。
若 Claude 试图 git commit --no-verify,应再加一条 PreToolUse 直接 exit 2,否则你刚接好的 git hook 会被绕开。这是 hooks 与 pre-commit 互补的关键接缝。有人把「拦 --no-verify」也算进那 8 条习惯里;即便原文细节不可见,这一条也应该自己补上。
最小可复制配置
项目级先放两段,对应「格式化」和「护文件」,事件名对照官方文档:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path' | xargs -I{} npx prettier --write {}"
}
]
}
],
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/protect-files.sh"
}
]
}
]
}
}
protect-files.sh 按 hooks-guide:读 stdin 里的 tool_input.file_path,命中 .env 等模式则 stderr 说明原因并 exit 2,脚本需 chmod +x。装完在 CLI 跑 /hooks,确认 PreToolUse / PostToolUse 计数非零,再让 Claude 改一行 JS 看 Prettier 是否动盘。若计数为 0,先查 JSON 是否嵌在同一个 hooks 对象下,别开了第二个顶级键把前面的配置盖掉。
再往上加「拦 push main」「Stop 跑测试」「Notification 响铃」时,一次加一条,避免五个 Bash matcher 对每次 shell 全开导致迟滞。慢检查放 git pre-push 或 CI,别塞进每个 PreToolUse。2026-08-05 对照的是 hooks 参考页与 hooks-guide 当时结构;版本升迁后事件表可能变长,装完后在本机跑一次 /hooks 核对列表即可。