Git钩子脚本如何检查职责分工

wen 实用脚本 1

本文目录导读:

Git钩子脚本如何检查职责分工

  1. 基于提交信息中的负责人字段检查(推荐)
  2. 基于文件路径与角色映射检查
  3. 集成外部权限系统(企业级)
  4. 结合 CODEOWNERS 文件(GitHub/GitLab 原生方案)
  5. 最佳实践建议
  6. 注意事项
  7. 完整示例:服务端 pre-receive 检查脚本

Git 钩子脚本(如 pre-commitpre-receive)可以通过解析 Git 提交信息、文件变更列表以及结合外部数据源(如配置文件、API)来检查职责分工,以下是几种常见的实现思路和示例:

基于提交信息中的负责人字段检查(推荐)

通过在 commit message 中强制要求标注 Reviewer:Module:Owner: 标签,钩子脚本解析这些内容并匹配负责人。

示例:commit-msg 钩子

#!/bin/sh
# 检查提交信息是否包含指定模块的负责人
commit_msg=$(cat "$1")
# 假设有一个存储职责映射的配置文件
# 格式:模块名称:负责人
cat > .OWNERS <<EOF
frontend:alice
backend:bob
database:charlie
EOF
# 提取模块信息(假设 commit message 包含 "Module: frontend")
module=$(echo "$commit_msg" | grep -i "Module:" | sed 's/Module:[[:space:]]*//i')
if [ -z "$module" ]; then
    echo "Error: Commit message must include 'Module: <name>' tag."
    exit 1
fi
# 查找负责人
owner=$(grep -i "$module" .OWNERS | cut -d: -f2)
echo "Module '$module' owner is '$owner'"
# 可选:检查当前用户是否是该模块负责人
if [ "$(git config user.name)" != "$owner" ]; then
    echo "Warning: You are not the designated owner for module '$module'"
fi

基于文件路径与角色映射检查

对于不同目录或文件类型,指定不同的审批人或责任人。

示例:pre-commit 钩子(检查修改的文件是否由正确角色提交)

#!/bin/sh
# 获取本次提交修改的文件列表
changed_files=$(git diff --cached --name-only)
# 定义路径到负责人的映射(可存储在外部文件)
declare -A PATH_OWNERS=(
    ["src/web/"]="前端团队"
    ["src/api/"]="后端团队"
    ["database/"]="DBA"
)
for file in $changed_files; do
    for path in "${!PATH_OWNERS[@]}"; do
        if [[ "$file" == $path* ]]; then
            echo "File '$file' belongs to '${PATH_OWNERS[$path]}'"
            # 可以在这里发送 Slack 通知或记录审计日志
        fi
    done
done
# 创建修改记录(日志)
logging_file=".git/commit-audit.log"
echo "User: $(git config user.name)" >> $logging_file
echo "Files: $changed_files" >> $logging_file
echo "Timestamp: $(date)" >> $logging_file

集成外部权限系统(企业级)

通过调用 API 或读取 LDAP 数据来验证当前用户是否被授权修改特定文件。

示例:pre-receive 钩子(服务端检查)

#!/bin/sh
# 从标准输入读取推入的引用信息
while read oldrev newrev refname; do
    # 获取推入的所有新提交
    commits=$(git rev-list $oldrev..$newrev)
    for commit in $commits; do
        # 获取该提交修改的文件
        files=$(git diff-tree --no-commit-id -r --name-only $commit)
        for file in $files; do
            # 调用内部 API 检查权限
            response=$(curl -s "https://org.internal/api/check-permission?user=$(git log -1 --format=%ae $commit)&file=$file")
            if [ "$response" != "allowed" ]; then
                echo "Error: User $(git log -1 --format=%ae $commit) not allowed to modify $file"
                exit 1
            fi
        done
    done
done

结合 CODEOWNERS 文件(GitHub/GitLab 原生方案)

虽然 Git 本身不支持自动解析,但可以在钩子中读取标准 CODEOWNERS 文件进行检查。

示例:pre-commit 钩子解析 CODEOWNERS

#!/bin/sh
# 读取 CODEOWNERS 文件(通常在根目录或 .github/)
codeowners_file="./.github/CODEOWNERS"
if [ ! -f "$codeowners_file" ]; then
    exit 0  # 无需检查
fi
changed_files=$(git diff --cached --name-only)
for file in $changed_files; do
    # 简单模式匹配(实际应支持 glob 模式)
    owner=$(grep "$file" "$codeowners_file" | head -1 | cut -d' ' -f2-)
    if [ -n "$owner" ] && [ "$owner" != "*" ]; then
        echo "File '$file' requires approval from: $owner"
        # 可以添加更严格的校验逻辑
    fi
done

最佳实践建议

场景 推荐钩子类型
个人开发环境 commit-msg 确保 commit message 包含模块标签
团队 CI/CD pre-receive 服务端强制检查文件权限
大型开源项目 集成 GitHub 原生 CODEOWNERS 代码审查指派

注意事项

  1. 客户端钩子可绕过pre-commit 等本地钩子可以通过 --no-verify 跳过,关键权限检查必须在服务端 pre-receiveupdate 钩子中完成。
  2. 性能影响:不要在 pre-receive 中调用慢速外部 API 或读取大量文件,建议使用缓存或异步处理。
  3. 跨平台兼容:脚本应避免依赖 Linux 特有命令(如 sed -i),或使用 Git for Windows 兼容的方式。

完整示例:服务端 pre-receive 检查脚本

#!/bin/bash
# 服务端强制职责分工检查
owner_database=".git-allowed-owners"  # 格式: 文件路径模式:用户/团队
while read oldrev newrev refname; do
    # 跳过删除和分支删除
    if [ "$newrev" = "0000000000000000000000000000000000000000" ]; then
        continue
    fi
    # 获取所有新提交的父提交(避免重复检查)
    git rev-list $oldrev..$newrev | while read commit; do
        author=$(git log -1 --format="%ae" $commit)
        files=$(git diff-tree --no-commit-id -r --name-only $commit)
        while IFS= read -r file; do
            # 查询该文件的责任人
            owner=""
            while IFS= read -r pattern; do
                if [[ "$file" == $pattern ]]; then
                    owner=$(echo "$pattern" | cut -d: -f2)
                    break
                fi
            done < "$owner_database"
            if [ -n "$owner" ] && [ "$author" != "$owner" ]; then
                echo "ERROR: File '$file' can only be modified by $owner (commit by $author)"
                exit 1
            fi
        done <<< "$files"
    done || exit 1
done

通过以上方法,Git 钩子可以有效地将代码变更与职责分工关联起来,实现自动化合规检查。

抱歉,评论功能暂时关闭!