git-hooks的使用——以Git新建分支名称检查为例

360 阅读4分钟

一、引言

在使用 Git 进行版本控制的项目中,规范的分支命名有助于提高项目的可维护性和可读性。Git - hooks 提供了一种在 Git 操作的特定阶段执行自定义脚本的机制,我们可以利用它来实现新建分支名称的检查,确保团队遵循一致的命名规则。

(二)可用的钩子类型

  • 客户端钩子(Client - side Hooks) :在本地仓库执行 Git 操作时触发,比如开发人员在自己的机器上进行提交或推送操作时。常见的客户端钩子包括 pre - commitprepare - commit - msgcommit - msg 和 pre - push 等。
  • 服务器端钩子(Server - side Hooks) :在 Git 服务器接收到客户端的推送等操作请求时执行。例如,pre - receiveupdate 和 post - receive 等,服务器端钩子可用于对整个团队的 Git 操作进行集中管理和控制。

三、新建分支名称检查的需求分析

(一)命名规范的重要性

规范的分支名称可以清晰地传达分支的用途,比如 feat/ 开头表示新功能开发分支,fix/ 开头表示修复问题分支,merge/ 用于合并相关的操作。这样在查看分支列表或者进行代码审查时,团队成员能够快速理解每个分支的角色。

(二)检查内容

我们希望检查新建分支名称是否符合以下规则:

  • 分支名称有合适的前缀(如 feat/fix/merge/)。
  • 分支名称中除前缀外的部分(假设存在 /)只包含小写字母、数字、小数点和下划线,不包含大写字母。

四、使用客户端钩子实现新建分支名称检查

(一)选择合适的客户端钩子 ——pre-push

pre-push 钩子在将本地分支推送到远程仓库之前执行,非常适合用于检查分支名称。因为在推送之前确保分支名称合规,可以避免不符合规范的分支进入远程仓库。

(二)编写 pre-push 钩子脚本

以下是一个简单的 bash 脚本实现的 pre-push 分支名称检查逻辑:

#!/bin/bash
export LC_ALL="C"
# 获取当前时间戳,格式为:年-月-日 时:分:秒
timestamp=$(date +"%Y-%m-%d %H:%M:%S")

# 获取当前本地分支名称
local_branch=$(git symbolic-ref --short HEAD)
echo "$timestamp [INFO] > Current branch name:$local_branch" >&2

# 定义合法的分支名称前缀数组
valid_prefixes=("feat/" "fix/" "merge/")

# 检查前缀是否合法
valid_prefix=false
for prefix in "${valid_prefixes[@]}"; do
    if [[ $local_branch == $prefix* ]]; then
        valid_prefix=true
        break
    fi
done
echo "$timestamp [INFO] > Is prefix valid?:$valid_prefix" >&2

# 获取分支名称中第一个/后面的部分(如果存在)
branch_body=${local_branch#*/}
echo "$timestamp [INFO] > Branch name body:$branch_body" >&2

# 定义合法的主体部分的模式(只允许小写英文、小数点、下划线或数字的组合,且不包含大写字母)
valid_branch_body_pattern='^[a-z0-9_.]*$'
echo "$timestamp [INFO] > Branch name body pattern:$valid_branch_body_pattern" >&2

# 检查分支主体部分是否合法
if [[ $branch_body =~ ^[a-z0-9_.]+$ ]]; then
    valid_branch_body=true
else
    valid_branch_body=false
fi

echo "$timestamp [INFO] > Is branch name valid?:$valid_branch_body" >&2
# 判断分支名称整体是否合法
if [ $valid_prefix == false ]; then
    echo "$timestamp [ERROR] > Tips:Branch name should start with 'feat/', 'fix/' or 'merge/'." >&2
    exit 1
elif [ $valid_branch_body == false ]; then
    echo "$timestamp [ERROR] > Tips:After the first '/', the branch name should only consist of lowercase English characters, digits, dots and underscores without any uppercase letters." >&2
    exit 1
else
    echo "$timestamp [INFO] > Branch name is valid. Proceeding with push." >&2
    exit 0
fi

(三)使脚本生效

  • 将上述脚本保存为 .git/hooks/pre - push 文件(确保脚本有可执行权限,可以使用 chmod +x.git/hooks/pre-push)。
  • 之后每次执行 git push 操作时,pre-push 钩子就会自动检查当前分支名称是否符合规范。
  • linux上运行时 export LC_ALL="C" 是可以省略的,但在windows中,由于git bash 对locate的不同有不一样的表现导致可能正则表达式的大小写验证不符合预期

五、使用服务器端钩子实现新建分支名称检查(可选)

(一)服务器端钩子的优势

对于多人协作的项目,服务器端钩子可以提供更统一的控制。即使某个开发人员忘记在本地配置客户端钩子或者绕过了本地检查,服务器端钩子依然可以阻止不符合规范的分支进入远程仓库。

(二)编写服务器端钩子脚本(以 pre-receive 为例)

以下是一个使用 pre-receive 钩子实现分支名称检查的脚本示例:

#!/bin/bash

while read oldrev newrev refname; do
    branch=$(basename $refname)
    valid_prefixes=("feat/" "fix/" "merge/")
    valid_prefix=false
    for prefix in "${valid_prefixes[@]}"; do
        if [[ $branch == $prefix* ]]; then
            valid_prefix=true
            break
        fi
    done
    branch_body=${branch#*/}
    valid_branch_body_pattern='^(?![A-Z])[a - z0 - 9_.]*$'
    if [[ $branch_body =~ $valid_branch_body_pattern ]]; then
        valid_branch_body=true
    else
        valid_branch_body=false
    fi
    if [ $valid_prefix == false ] || [ $valid_branch_body == false ]; then
        echo "Branch name $branch does not follow the naming convention."
        exit 1
    else
        echo "Branch name is valid."
    fi
done

(三)配置服务器端钩子

  • 将脚本保存到 Git 服务器上的相应钩子目录(具体位置因 Git 服务器配置而异,例如在基于 Gitlab 或 Gitea 等搭建的服务器上,有特定的设置位置和方法)。
  • 设置脚本权限为可执行(chmod +x pre-receive)。

六、总结

通过使用 Git - hooks,无论是客户端还是服务器端的钩子,我们都可以有效地实现对新建分支名称的检查。这有助于维护项目中分支命名的规范性,提高整个开发团队的协作效率和代码管理质量。同时,开发团队可以根据自己的实际需求进一步扩展和完善钩子脚本,以适应更多的分支命名规则和检查逻辑。