本文目录导读:

- 常见的日志策略检查项
- 示例脚本:检查 Conventional Commits 格式
- 更详细的脚本:检查多种规则
- 针对不同需求的其他检查示例
- 全局安装 hook(多个仓库共享)
- 使用 shell 脚本的注意事项
- 结合 CI 的额外建议
Git 钩子脚本通常通过 commit-msg 钩子来检查日志(提交信息)策略,这个钩子在用户输入提交信息之后、提交完成之前被触发。
以下是一个完整的检查日志策略的 commit-msg 钩子脚本示例,并说明了常见的检查项及部署方法。
常见的日志策略检查项
- 非空检查:提交信息不能为空。
- 格式检查:是否符合特定格式,
type(scope): subject(Conventional Commits)。 - 长度限制:第一行(标题)不能超过 50/72 个字符;正文每行不超过 72 个字符。
- 关键词屏蔽:禁止包含敏感词或临时标记(如
WIP、test、fixme)。 - 分支/issue 关联:提交信息是否包含 Issue 编号或 Jira 编号。
- 签名检查:是否包含
Signed-off-by或Co-authored-by行。
示例脚本:检查 Conventional Commits 格式
将以下脚本保存为 .git/hooks/commit-msg 并赋予可执行权限。
#!/bin/sh
#
# Git commit-msg hook: 检查提交信息是否符合 Conventional Commits 格式
# 规则:
# <type>[optional scope]: <description>
# [optional body]
# [optional footer(s)]
#
# 启用严格模式(可选)
# set -e
commit_msg_file="$1"
commit_msg=$(cat "$commit_msg_file")
# 定义正则匹配模式(Conventional Commits)
pattern="^(feat|fix|docs|style|refactor|perf|test|chore|ci|build|revert)(\(.+\))?!?: .{1,}$"
# 检查是否匹配格式
if ! echo "$commit_msg" | grep -qE "$pattern"; then
echo "ERROR: 提交信息不符合 Conventional Commits 格式"
echo "格式: <type>(<scope>): <subject>"
echo "允许的 type: feat|fix|docs|style|refactor|perf|test|chore|ci|build|revert"
echo "示例: feat(auth): 添加登录功能"
exit 1
fi
# 检查第一行长度(通常建议不超过 72)
first_line=$(echo "$commit_msg" | head -n1)
if [ ${#first_line} -gt 72 ]; then
echo "ERROR: 第一行(标题)长度 ${#first_line},不允许超过 72 个字符"
exit 1
fi
# 检查空提交信息
if [ -z "$commit_msg" ]; then
echo "ERROR: 提交信息不能为空"
exit 1
fi
# ✅ 所有检查通过
exit 0
更详细的脚本:检查多种规则
#!/bin/bash
commit_msg_file="$1"
commit_msg=$(cat "$commit_msg_file")
exit_code=0
echo "[commit-msg hook] 检查提交信息策略..."
# 1. 非空检查
if [ -z "$commit_msg" ]; then
echo "❌ 提交信息不能为空"
exit_code=1
fi
长度(超过50给出警告,超过72拒绝)
first_line=$(echo "$commit_msg" | head -n1)
if [ ${#first_line} -gt 72 ]; then
echo "❌ 标题超过 72 个字符 (当前: ${#first_line})"
exit_code=1
elif [ ${#first_line} -gt 50 ]; then
echo "⚠️ 标题超过 50 个字符 (建议不超过50)"
fi
# 3. 格式:必须包含冒号和空格
if ! echo "$first_line" | grep -qE ":\s"; then
echo "❌ 标题格式错误:必须包含 ': ' (冒号+空格)"
exit_code=1
fi
# 4. 不允许包含 WIP 或 FIXME
if echo "$commit_msg" | grep -qi "\bWIP\b"; then
echo "❌ 提交信息包含 'WIP',禁止提交"
exit_code=1
fi
# 5. 如果分支是 feature/xxx,要求提交信息包含 issue 编号
branch_name=$(git rev-parse --abbrev-ref HEAD 2>/dev/null)
if echo "$branch_name" | grep -qE "^feature/"; then
if ! echo "$commit_msg" | grep -qE "#[0-9]+"; then
echo "❌ 当前分支为 feature 分支,提交信息必须包含 Issue 编号(如 #123)"
exit_code=1
fi
fi
# 6. 检查是否包含 Signed-off-by (用于 DCO 认证)
# if ! echo "$commit_msg" | grep -q "Signed-off-by:"; then
# echo "❌ 缺少 Signed-off-by 行 (请使用 git commit -s)"
# exit_code=1
# fi
# 汇总结果
if [ $exit_code -ne 0 ]; then
echo ""
echo "🔴 提交信息策略检查未通过,请修改后重新提交。"
echo "提示: 可使用 'git commit --amend' 修改提交信息。"
fi
exit $exit_code
针对不同需求的其他检查示例
1 检查 Jira 编号(如项目 ID 开头)
# 要求提交信息必须包含 JIRA-XXX 的编号
if ! echo "$commit_msg" | grep -qE "[A-Z]+-[0-9]+"; then
echo "ERROR: 提交信息必须包含 Jira 编号 (如 PROJECT-123)"
exit 1
fi
2 禁止使用中文(部分团队要求纯英文)
if echo "$commit_msg" | grep -qP "[\x{4e00}-\x{9fa5}]"; then
echo "ERROR: 提交信息不能包含中文字符,请使用英文"
exit 1
fi
3 检查空行/分行(多行提交信息需要空行分隔标题和正文)
lines=$(echo "$commit_msg" | wc -l)
if [ "$lines" -gt 1 ]; then
# 如果有正文,必须在标题后留一个空行
second_line=$(echo "$commit_msg" | sed -n '2p')
if [ -n "$second_line" ]; then
echo "ERROR: 标题和正文之间必须有一个空行"
exit 1
fi
fi
全局安装 hook(多个仓库共享)
如果希望所有仓库都使用相同的提交信息检查逻辑,可以使用 全局 Git 钩子。
# 1. 创建全局钩子目录 git config --global core.hooksPath ~/.git-hooks # 2. 将脚本放入该目录 mkdir -p ~/.git-hooks cp commit-msg ~/.git-hooks/ chmod +x ~/.git-hooks/commit-msg
然后所有使用该 Git 版本的新仓库都会自动应用此钩子。
使用 shell 脚本的注意事项
- 可移植性:使用
#!/bin/sh而非#!/bin/bash能提高 macOS 等系统的兼容性(某些系统默认/bin/sh不是 bash)。 - 变量引用:尽量用双引号包裹变量(如
"$commit_msg"),防止特殊字符导致错误。 - 错误处理:所有检查失败时
exit 1,Git 会拒绝本次提交。 - 调试:可以临时添加
echo "DEBUG: $commit_msg" >&2输出到 stderr 以便调试。
结合 CI 的额外建议
Hook 仅作用于开发者本地环境,为了保险起见,建议在 CI(如 Jenkins、GitHub Actions)中也加入相似的提交信息校验:
# GitHub Actions 示例:check commit message
- name: Check commit message format
run: |
commit_msg=$(git log --format=%B -n1 ${{ github.sha }})
echo "Commit message: $commit_msg"
echo "$commit_msg" | grep -qE "^(feat|fix|docs): .+$" || exit 1
| 钩子名 | 触发时机 | 常用检查项 |
|---|---|---|
commit-msg |
提交信息输入后 | 格式、长度、非空、关键词 |
prepare-commit-msg |
提交信息编辑前 | 自动插入模板、分支名、issue号 |
最常用且推荐的做法是使用 commit-msg 钩子 编写 Shell 脚本,配合正则表达式检查提交信息的格式和内容策略。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播