commit-msg钩子最可靠,它在commit生成后、写入本地仓库前触发,通过读取$1参数指定的临时消息文件并exit非0可拒绝提交;需手动判断分支、处理windows换行符,并用正则校验首行格式。

commit-msg钩子怎么拦截不合规的提交信息
直接用 commit-msg 钩子最可靠,它在 commit 生成后、写入本地仓库前触发,能读取刚生成的提交信息文件并决定是否拒绝提交。别用 pre-commit,它看不到 commit message,只管代码改动。
常见错误是把校验逻辑写在 pre-commit 里,结果永远校验不到 message 格式;或者用 prepare-commit-msg,它只能修改 message,不能拒绝提交。
- 钩子脚本路径:
.git/hooks/commit-msg(需可执行权限chmod +x) - 输入参数:
$1是临时 message 文件路径,用cat "$1"读内容 - 拒绝提交:脚本 exit 非 0(如
exit 1),Git 会中止 commit 并打印你 echo 的提示 - 注意 Windows 换行符(CRLF)可能干扰正则匹配,建议先
tr -d '\r'
如何只对 main 和 release/* 分支生效
钩子本身没分支概念,必须手动判断当前 HEAD 所在分支——但 commit-msg 运行时还没创建 commit 对象,git branch --show-current 可能为空。稳妥做法是查当前检出的 ref:
GitHub 仓库备份技能 - 将 OpenClaw 工作空间自动或手动备份至 GitHub 私有仓库。支持自动定时备份和手动交互式配置,引导完成 Token 配置、仓库创建、首次备份及定时任务设置。用途:(1) 首次设置 (2) 日常备份。
- 用
git symbolic-ref --short HEAD 2>/dev/null获取当前分支名(比git rev-parse --abbrev-ref HEAD更准) - 如果返回空,说明在 detached HEAD 状态,通常允许提交(或按需拒绝)
- 匹配分支:用
case或[[ $branch =~ ^(main|release/.*$) ]]判断,注意release/.*要加shopt -s extglob或改用[[ $branch == "main" || $branch == release/* ]] - 别依赖
git rev-parse --abbrev-ref origin/HEAD,那是远程默认分支,不是本地当前分支
提交信息格式校验的实用正则写法
别一上来就写复杂规则,先覆盖高频场景:type(scope): subject 结构,且 type 限定为 feat、fix、chore 等。容易踩坑的是 shell 正则和换行处理。
- 提取首行:
head -n1 "$1" | tr -d '\r'(避免 CRLF 导致匹配失败) - 推荐基础校验:
^((feat|fix|docs|style|refactor|test|chore|revert)(\([^)]*\))?:\s+.+)$ - 注意 shell 中
[^)]*不能跨行,所以只校验第一行;多行 body 不强制(除非业务强要求) - 如果用
grep -qE,记得加-i忽略大小写,否则Feat会被拒 - 不要用
sed替换后再匹配——替换可能破坏原始格式,直接 match 原始字符串更安全
钩子分发和团队同步的实际难点
Git Hooks 不随 clone 自动同步,这是最大落地障碍。没人手动 chmod +x 或复制脚本,规则就形同虚设。
- 别把钩子硬塞进项目根目录再教人 ln -s,90% 的人会漏掉这步
- 推荐方案:用
husky(v8+)或simple-git-hooks,它们通过 package.json 配置自动安装钩子,并支持跨平台 - 如果坚持原生钩子,至少提供一键安装脚本:
npm pkg set scripts.prepare="cp hooks/commit-msg .git/hooks/",配合preinstall或prepare生命周期 - 提醒:CI 环境(如 GitHub Actions)不运行本地钩子,必须另配 commitlint 或 pre-commit 框架做二次校验
真正难的不是写正则,而是让每个开发者机器上的 .git/hooks/commit-msg 实时生效且不被 IDE 覆盖。每次重装 Git、升级 VS Code 或拉新分支,都可能清空钩子。










