"又有人把调试代码提交上来了""提交信息乱写一气""CI 在合并前才发现格式错误"——根源都是质量检查全靠自觉。Git Hooks 能在 commit、push 等动作发生的瞬间自动执行脚本,把"事后补救"变成"事前拦截"。
1. 什么是 Git Hooks
Git Hooks 是 Git 在特定事件发生时自动执行的脚本,放在 .git/hooks/ 目录。自带的 *.sample 示例,去掉后缀并加执行权限即可启用。
ls .git/hooks/
# pre-commit.sample commit-msg.sample pre-push.sample ...
# 启用钩子:去掉 .sample 后缀并加执行权限
mv .git/hooks/pre-commit.sample .git/hooks/pre-commit
chmod +x .git/hooks/pre-commit
2. 客户端钩子与执行时机
| 钩子 | 触发时机 | 典型用途 |
|---|---|---|
| pre-commit | commit 前 | 格式化、lint、检查调试代码 |
| commit-msg | 提交信息输入后 | 校验提交信息格式 |
| pre-push | push 前 | 跑测试、检查大文件 |
钩子退出码为 0 表示通过,非 0 则中断操作,如 pre-commit 返回 1,commit 即被拒绝。
3. 实战:pre-commit 检查调试代码
写一个钩子,阻止包含 console.log 或 debugger 的 JS 文件被提交:
#!/bin/sh
# .git/hooks/pre-commit
files=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.(js|ts)$')
for f in $files; do
if git show :"$f" | grep -nE 'console\.log|debugger'; then
echo "错误: $f 包含调试代码,禁止提交!"
exit 1
fi
done
exit 0
脚本遍历暂存区里的 JS/TS 文件,发现调试代码就拒绝提交。注意钩子必须可执行:chmod +x .git/hooks/pre-commit。
4. 实战:commit-msg 校验提交规范
团队约定提交格式 type(scope): subject(如 feat(login): 增加验证码),用钩子强制:
#!/bin/sh
# .git/hooks/commit-msg
msg=$(cat "$1")
if ! echo "$msg" | grep -qE '^(feat|fix|docs|refactor|chore|test)\([a-z-]+\): .+'; then
echo "提交信息不符合规范: type(scope): subject"
echo "示例: feat(login): 增加验证码登录"
exit 1
fi
$1 是提交信息文件路径。从此不规范提交在本地就被拦下,CI 和评审都轻松很多。
5. 实战:pre-push 跑测试
#!/bin/sh
# .git/hooks/pre-push
echo "=== 推送前运行测试 ==="
npm test
if [ $? -ne 0 ]; then
echo "测试失败,已阻止推送!"
exit 1
fi
测试比较耗时,建议只跑核心用例;超过 30 秒的钩子,同事会想办法绕过它。
6. 团队如何共享钩子
.git/hooks/ 不随仓库提交,新成员 clone 后没有钩子。常见做法:把脚本放到 scripts/hooks/ 提交进仓库,用安装脚本软链过去:
# scripts/install-hooks.sh
#!/bin/sh
for hook in pre-commit commit-msg pre-push; do
ln -sf ../../scripts/hooks/$hook .git/hooks/$hook
done
echo "钩子安装完成"
进阶可用 Husky(Node)或 pre-commit 框架(Python),自动安装钩子、按文件类型分流,接入成本更低。
💡 学习建议:从"最痛的点"入手——比如团队最近总有人提交调试代码,就先写一个 pre-commit 钩子;跑通后加上提交信息校验,再考虑 pre-push 测试。一次只加一道闸,别想着第一天就搭起完整的质量流水线。