1. 背景概要

昨天一个同事问我如何修改已经commit的message, 因为push 到远端时发现message不符合规范, 提交规范大概如下:

  1. 必须以特定开头,比如功能开发是 "feat:", bug修复是"fix:"
  2. 开头后面跟上必要说明文字且不少于40个字符
  3. 必须以"[#工单号]"为结尾, 工单号为一个六位数.

那位同事push 失败的原因不符合规范说明长度不够, 使用 git rebase可实现修改. 和同事沟通后是他经常本地 commit几次以后再一起push 到远端才出现这种问题, 那么能不能在本地commit的时候检查是否符合规范呢?

2. 实现本地检查

本地commit的检查是使用Git hook来实现。下面是关于Git hook的简要说明:

Git hook(钩子)是一种自定义脚本,它可以在 Git 特定的事件发生时触发。这些事件包括提交(commit)、推送(push)、合并(merge)、克隆(clone)等。通过使用 Git 钩子,你可以在这些事件的不同阶段执行自定义脚本,以实现各种自动化和定制化的任务。

Git 钩子位于 Git 仓库的 .git/hooks 目录下,每个钩子都是可执行文件,可以是任何可以在你的系统上运行的脚本。这些钩子的文件名对应着触发它们的事件。例如:

  • pre-commit 钩子在执行提交前触发。
  • post-commit 钩子在提交完成后触发。
  • pre-push 钩子在执行推送前触发。
  • 等等。

你可以在这些脚本中执行各种任务,比如代码风格检查、测试运行、文档生成等。这样,你就可以确保提交到版本控制系统的代码符合你的团队或项目的标准。

要使用 Git 钩子,你只需创建对应事件的脚本文件,并确保其可执行。Git 在相应的事件发生时会自动执行这些脚本。

话不多说,来写Code!

新建一个bash脚本文件内容如下,重要的内容在注释中

#!/bin/bash

# 传入的提交消息
commit_msg=$1

# 输出调试信息
echo "Debug: commit_msg is '$commit_msg'"

# 定义正则表达式
regex="^(feat|fix): .+ \[#\d{6}\]$"

# 设置最小允许的提交消息长度
min_length=40

# 检查消息格式
if [[ $commit_msg =~ $regex ]]; then
    echo "Debug: Message format matches the pattern."
else
    echo "Debug: Message format does not match the pattern."
    echo "Error: Commit message does not match the required format." >&2
    echo "Format should be 'feat: something [#123456]' or 'fix: something [#123456]'." >&2
    exit 1
fi

# 检查消息长度
if [ ${#commit_msg} -lt $min_length ]; then
    echo "Error: Commit message is too short (min: $min_length characters)." >&2
    exit 1
fi

# 如果消息格式和长度都符合要求,允许提交
exit 0

测试一下脚本:

$ sh test_commit.sh "feat: something [#123456]"
Debug: commit_msg is 'feat: something [#123456]'
Debug: regex is '^(feat|fix): .+ \[#\d{6}\]$'
Debug: Message format does not match the pattern.
Error: Commit message does not match the required format.
Format should be 'feat: something [#123456]' or 'fix: something [#123456]'.

不对啊,这应该提示长度不对才是,为什么提示格式不对?难道正则有问题?google了一个在线测试正则的网站:

image-20231121201816201

这么看正则确实没问题,能匹配到内容。

然后又直接在bash命令行中测试:

image-20231121202254178

执行结果确实是正则不匹配,看到命令提示行才想到,我是使用 Windows 安装的 git 里面的 bash,配置如下:

image-20231121202427029

那么是不是因为Windows系统的原因?查询ChatGPT得知:

正则表达式中的 \d 在某些环境中可能不起作用,使用更通用的 [0-9] 替换 \d

尝试修改正则为:

regex="^(feat|fix): .+ \[#[0-9]{6}\]$"

再次测试结果如下:

$ sh test_commit.sh "feat: something [#123456]"
Debug: commit_msg is 'feat: something [#123456]'
Debug: regex is '^(feat|fix): .+ \[#[0-9]{6}\]$'
Debug: Message format matches the pattern.
Error: Commit message is too short (min: 40 characters).

上述说明正则检查通过, 然后修改一下从 git commit中获取message,完整的脚本内容如下:

#!/bin/bash

# 获取提交消息
commit_msg_file=$1
commit_msg=$(cat $commit_msg_file)

# 输出调试信息
# echo "Debug: commit_msg is '$commit_msg'"

# 定义正则表达式
regex="^(feat|fix): .+ \[#[0-9]{6}\]$"

# 设置最小允许的提交消息长度
min_length=40

# 检查消息格式
if [[ $commit_msg =~ $regex ]]; then
    echo "Debug: Message format matches the pattern."
else
    echo "Debug: Message format does not match the pattern."
    echo "Error: Commit message does not match the required format." >&2
    echo "Format should be 'feat: something [#123456]' or 'fix: something [#123456]'." >&2
    exit 1
fi

# 检查消息长度
if [ ${#commit_msg} -lt $min_length ]; then
    echo "Error: Commit message is too short (min: $min_length characters)." >&2
    exit 1
fi

# 如果消息格式和长度都符合要求,允许提交
exit 0

注意保存格式为 UTF-8

注意保存格式为 UTF-8

注意保存格式为 UTF-8

然后在git 仓库目录执行一下内容:

ln -s commit-check.sh .git/hooks/commit-msg

把上面的 commit-check.sh 路径为实际的文件路径, 执行后测试提交:

$ git commit -m "feat: fixxxx [#234444]"
Debug: Message format matches the pattern.
Error: Commit message is too short (min: 40 characters).

已经提示长度错误了,修改长度后再次测试:

$ git commit -m "feat: fixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx [#234444]"
Debug: Message format matches the pattern.
[feature_test 985f6c35d] feat: fixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx [#234444]
 1 file changed, 1 insertion(+)

说明已经提交成功了!

3. 使用优化

人嘛 都是比较懒, 一个项目这样添加一次也还好, 要是有比较多的仓库都要设置这样的规则怎么处理?

这不得不使用 git bash下面的 alias!

以Windows系统为例, 找到Git的安装路径:

image-20231121204052943

打开 aliases.sh 文件的alias ll='ls -l'下面添加一行:

# --show-control-chars: help showing Korean or accented characters
alias ls='ls -F --color=auto --show-control-chars'
alias ll='ls -l'
alias addCommitCheck='ln -s /d/AppData/Git/command/commit-check.sh .git/hooks/commit-msg'

然后重新打开命令行,就可以使用addCommitCheck 来设置仓库的检查规则了.

$ addCommitCheck
ln: failed to create symbolic link '.git/hooks/commit-msg': File exists

我这个提示是已经添加过commit-msg 检查脚本.

4. 总结

本文主要讲解了如何解决commit message本机检查的问题, 这样可以大大减少push的时候由于不符合规则失败的问题,但是要注意:

如果服务器检查规则更改,本地也要做对应的更新,或者让团队给出新的规则.

如果你喜欢本文请点赞或者点击在看,分享给有需要的人,关注我公众号,看更多~