本文目录导读:

- 基于提交信息中的负责人字段检查(推荐)
- 基于文件路径与角色映射检查
- 集成外部权限系统(企业级)
- 结合 CODEOWNERS 文件(GitHub/GitLab 原生方案)
- 最佳实践建议
- 注意事项
- 完整示例:服务端
pre-receive检查脚本
Git 钩子脚本(如 pre-commit、pre-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 | 代码审查指派 |
注意事项
- 客户端钩子可绕过:
pre-commit等本地钩子可以通过--no-verify跳过,关键权限检查必须在服务端pre-receive或update钩子中完成。 - 性能影响:不要在
pre-receive中调用慢速外部 API 或读取大量文件,建议使用缓存或异步处理。 - 跨平台兼容:脚本应避免依赖 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 钩子可以有效地将代码变更与职责分工关联起来,实现自动化合规检查。