如何在组织内前置校验Git Commit Message格式,阻止不合规提交?
我来给你一套完整的解决方案,完美覆盖你提到的三种提交到master/main分支的场景,全程做前置拦截,彻底避免事后校验的尴尬。
1. 本地提交与推送的前置拦截(覆盖场景1、2)
首先从源头卡住,确保开发者在本地就没法提交或推送不符合格式的内容。
a. commit-msg钩子:拦截所有本地提交
创建项目根目录下的.githooks/commit-msg文件(把钩子放到项目仓库里,方便团队共享),内容如下:
#!/bin/sh # 定义你要求的校验正则 VALIDATION_PATTERN='^\[[A-Z]{2}-[0-9]{5,7}\]\-.+' # 读取当前提交的message内容 COMMIT_CONTENT=$(cat "$1") # 校验格式 if ! echo "$COMMIT_CONTENT" | grep -qE "$VALIDATION_PATTERN"; then echo "❌ 提交信息不符合规范!" echo "要求格式示例:[PRO-123456] 修复用户中心加载缓慢问题" echo "正则规则:$VALIDATION_PATTERN" exit 1 fi
给文件加执行权限:chmod +x .githooks/commit-msg
然后让团队所有成员都能自动用上这个钩子:在项目根目录执行git config core.hooksPath .githooks,并把.githooks目录和.git/config的修改提交到仓库,新克隆项目的成员只需要执行一次这个config命令就能生效(也可以写个初始化脚本自动处理)。
b. pre-push钩子:拦截违规内容推送到远程
防止有人用--no-verify绕过commit钩子后推送,所以加个推送前的校验,检查要推送到master/main的所有提交是否合规。
创建.githooks/pre-push文件:
#!/bin/sh # 只针对master/main分支做校验 TARGET_BRANCH=$(echo "$2" | awk -F '/' '{print $NF}') if [ "$TARGET_BRANCH" != "master" ] && [ "$TARGET_BRANCH" != "main" ]; then exit 0 fi VALIDATION_PATTERN='^\[[A-Z]{2}-[0-9]{5,7}\]\-.+' # 获取要推送的所有提交的message COMMIT_LIST=$(git log --pretty=format:"%B" "$1..HEAD") # 逐个校验 while IFS= read -r MSG; do if ! echo "$MSG" | grep -qE "$VALIDATION_PATTERN"; then echo "❌ 要推送的提交中有不符合格式的信息!" echo "违规内容:$MSG" echo "要求格式示例:[PRO-123456] 修复用户中心加载缓慢问题" exit 1 fi done <<< "$COMMIT_LIST"
同样加执行权限:chmod +x .githooks/pre-push,并提交到仓库。
2. GitHub PR合并的前置校验(覆盖场景3,核心解决痛点)
这部分是关键,要让PR在合并前就完成校验,而不是合并后CI才报错。我们用GitHub原生的分支保护规则+Actions来实现:
步骤1:配置分支保护规则
- 打开GitHub仓库的「Settings」→「Branches」→「Branch protection rules」
- 新建规则,选择
master/main分支:- 勾选「Require pull request reviews before merging」(可选,但建议开启,加强代码审核)
- 勾选「Require status checks to pass before merging」
- 后面创建的Actions任务会出现在「Status checks that are required」列表里,到时选中它
- 务必勾选「Do not allow bypassing the above settings」,强制所有人遵守(包括管理员)
步骤2:创建GitHub Action工作流
在仓库的.github/workflows/commit-message-check.yml创建文件:
name: 提交信息格式校验 on: pull_request: branches: [master, main] types: [opened, synchronize, reopened] jobs: lint-commit-messages: runs-on: ubuntu-latest steps: - name: 拉取代码 uses: actions/checkout@v4 with: fetch-depth: 0 # 必须拉取完整历史,才能检查PR里的所有提交 - name: 校验所有提交信息 run: | VALIDATION_PATTERN='^\[[A-Z]{2}-[0-9]{5,7}\]\-.+' # 获取PR中所有新增提交的message PR_COMMITS=$(git log --pretty=format:"%B" "${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }}") # 逐个检查 while IFS= read -r COMMIT_MSG; do if ! echo "$COMMIT_MSG" | grep -qE "$VALIDATION_PATTERN"; then echo "::error::提交信息不符合规范!" echo "::error::违规内容:$COMMIT_MSG" echo "::error::要求格式示例:[PRO-123456] 修复用户中心加载缓慢问题" exit 1 fi done <<< "$PR_COMMITS"
这个工作流会在PR打开、新增提交(同步)、重新打开时自动触发,只有所有提交信息都合规,PR才能被合并,完全实现前置拦截。
3. 额外小贴士:处理历史违规提交
如果仓库已经有不符合格式的历史提交,可以用git filter-repo批量修改(谨慎操作,会重写历史,需要团队统一执行):
git filter-repo --message-callback ' import re # 这里根据实际需求替换,比如给无格式的提交加上默认前缀 pattern = re.compile(r"^.*$") new_message = re.sub(r"^", "[FIX-000000]-", message) return new_message '
这样三个场景就全部覆盖了:
- 场景1:本地master提交后推送 →
commit-msg+pre-push双重拦截 - 场景2:本地分支提交后合并到master再推送 →
commit-msg拦截分支提交,pre-push拦截推送 - 场景3:PR合并 → GitHub Action前置校验,不通过无法合并
内容的提问来源于stack exchange,提问作者JAR.JAR.beans




