别再乱写 Commit 了!利用 Git commit-msg 钩子与正则实现自动化规范校验
在团队协作中,混乱的 Git 提交信息(Commit Message)是后期维护的灾难。你是否见过满屏的 update、fix 甚至是 ...?这不仅让 git log 失去了追踪意义,更导致自动化生成 Changelog 变得不可能。
目前业界公认的最佳实践是 Conventional Commits(约定式提交)。本文将深入探讨如何利用 Git 自带的 commit-msg 钩子,配合正则表达式,在代码提交的第一道关口实现强制规范校验。
1. 什么是 Conventional Commits?
约定式提交规范提供了一个轻量级的提交历史结构。其核心格式如下:
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
- feat: 新功能
- fix: 修补错误
- docs: 文档改变
- style: 代码格式改变(不影响代码运行的变动)
- refactor: 重构(既不是新增功能,也不是修改 bug 的代码变动)
- perf: 性能优化
- test: 增加测试
- chore: 构建过程或辅助工具的变动
2. Git 钩子机制:commit-msg
Git Hooks 是 Git 在特定事件发生时触发的脚本。其中 commit-msg 钩子在用户输入提交信息并保存后触发。
- 触发时机:在编辑器关闭、提交信息存入临时文件之后。
- 输入参数:该钩子接收一个参数,即保存提交信息的临时文件路径。
- 拦截机制:如果脚本以非零状态码退出(
exit 1),Git 将放弃此次提交。
3. 构建核心正则表达式
要校验提交信息,我们需要一个能够覆盖规范且严谨的正则。
推荐使用的正则:
/^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\(.+\))?!?: .+/
解析:
^: 匹配行首。(feat|fix|...): 必须以这些指定的 type 开头。(\(.+\))?: 可选的作用域(scope),包裹在圆括号内。!?: 可选的惊叹号,表示包含破坏性变更(Breaking Change)。:: 必须包含冒号加空格。.+: 后面必须跟上具体的描述信息。
4. 编写 commit-msg 钩子脚本
在你的项目根目录下,找到 .git/hooks/commit-msg.sample,将其重命名为 commit-msg(去掉后缀),并写入以下代码:
#!/bin/sh
# 获取提交信息文件的路径
COMMIT_MSG_FILE=$1
# 读取提交信息的第一行
COMMIT_MSG=$(head -n 1 "$COMMIT_MSG_FILE")
# 定义正则规范
REGEXP="^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\(.+\))?!?: .+"
# 检查是否匹配正则
if ! echo "$COMMIT_MSG" | grep -Eq "$REGEXP"; then
echo " "
echo "Error: 不符合规范的提交格式!"
echo " "
echo "正确格式: <type>(scope?): <description>"
echo "例如: feat(auth): 增加用户登录功能"
echo " fix: 修复内存泄漏问题"
echo " "
echo "常见 type 包括: feat, fix, docs, style, refactor, perf, test, chore, revert"
echo "请修改后重新提交。"
exit 1
fi
关键步骤:必须赋予脚本可执行权限:
chmod +x .git/hooks/commit-msg
5. 进阶:如何让全团队共享钩子?
.git 文件夹下的内容不会被提交到远程仓库。为了让团队成员都强制执行此规范,有几种常见方案:
方案 A:使用 Husky (推荐用于 Node.js 项目)
Husky 是前端领域最流行的工具,它可以将钩子配置存储在 package.json 中,并在 npm install 时自动安装到本地 .git/hooks。
npx husky-init && npm install
npx husky add .husky/commit-msg 'npx --no -- commitlint --edit "$1"'
方案 B:配置 git config core.hooksPath
你可以创建一个自定义的目录(如 .githooks),将脚本放入其中并提交。然后让团队成员执行:
git config core.hooksPath .githooks
6. 为什么不直接使用 commitlint?
市面上确实有成熟的工具如 @commitlint/cli。如果你追求开箱即用,它们是首选。但深入理解 commit-msg 钩子和正则的意义在于:
- 轻量化:无需安装成百上千的 node_modules,仅靠几行 Shell 脚本即可实现。
- 高度自定义:你可以根据公司内部标准,自定义特定的 type(比如公司内部的单号格式
PROJ-123: fix something)。 - 多语言通用:无论你的项目是 Go、Python 还是 C++,Shell 脚本钩子是通用的。
总结
自动化规范校验是 DevOps 的第一步。通过简单的 commit-msg 钩子,我们可以确保 Git 历史记录的整洁与可读。这不仅方便了开发者自己回溯代码,更为后续的自动化发布、版本号自动演进(Semantic Versioning)打下了坚实的基础。
现在,去给你的项目加上这个“紧箍咒”吧!