本文目录导读:

针对Git钩子脚本检查“培训计划”,这个需求通常需要结合具体场景来理解,因为“培训计划”并不是Git原生的概念(如代码、分支、提交信息),我推测你可能是在以下几种场景之一工作:
- 场景A(最可能): 你的团队或企业内部有培训考核流程,要求开发者在提交代码前,必须确认自己已完成某项安全培训或技能培训(
git commit前弹窗提醒“你完成《代码规范》培训了吗?”)。 - 场景B: 你的仓库中有一个专门的目录或文件叫
training_plan/培训计划,你想检查这个文件是否被修改、格式是否正确,或者是否在每次提交时都包含它。 - 场景C: 你想在提交信息(commit message)中强制包含培训相关的ID或说明。
下面我会针对最常见的场景A(行为检查)和场景B(文件内容检查)提供具体的钩子脚本示例。
核心工具:Git Hooks
钩子脚本位于项目根目录下的 .git/hooks/ 文件夹中,你需要创建一个可执行脚本(如 pre-commit)。
注意: .git/hooks/ 下的文件不会被提交到仓库,如果你想团队共享,需要将脚本放到项目目录(如 hooks/),然后通过 git config core.hooksPath hooks/ 进行配置。
场景A:提交前强制确认培训完成情况
这是最常见的企业级需求,使用 pre-commit 钩子,阻止未完成培训的开发者提交代码。
原理: 脚本读取一个本地文件、环境变量或调用内部API,检查用户是否标记为“已培训”。
示例 1:检查本地标记文件(简单版)
在用户完成培训后,本地生成一个隐藏文件 ~/.training_completed。
文件:.git/hooks/pre-commit(需赋予 chmod +x 权限)
#!/bin/bash
# 检查培训标记文件是否存在
TRAINING_FILE="$HOME/.training_completed"
if [ ! -f "$TRAINING_FILE" ]; then
echo "❌ 错误:您尚未完成《2025年度信息安全培训》!"
echo "请前往内部培训平台完成培训,完成后系统将自动生成标记。"
echo "(或联系管理员解决)"
exit 1 # 非零退出码阻止提交
fi
# 可选:检查文件内容是否包含当前季度
CURRENT_QUARTER=$(date +%Y-Q%q)
if ! grep -q "$CURRENT_QUARTER" "$TRAINING_FILE"; then
echo "❌ 错误:您的培训记录($(cat $TRAINING_FILE))不在当前周期($CURRENT_QUARTER)。"
echo "请重新完成季度培训。"
exit 1
fi
# 检查通过
exit 0
示例 2:调用内部API验证(生产级)
假设你们有一个内部系统 https://train.corp.com/check?user=<username> 返回 {"passed": true}。
#!/bin/bash
# 获取当前Git用户
USER_EMAIL=$(git config user.email)
USER_NAME=$(git config user.name)
# 调用内部API(超时2秒,静默失败时允许提交)
RESULT=$(curl -s --connect-timeout 2 --max-time 3 \
"https://train.corp.com/api/check?email=$USER_EMAIL" 2>/dev/null)
# 检查API是否返回成功
if echo "$RESULT" | grep -q '"passed": true'; then
exit 0
elif echo "$RESULT" | grep -q '"passed": false'; then
echo "❌ 提交被拒绝:用户 $USER_NAME 尚未通过【高效代码审查】培训。"
echo "请访问 https://train.corp.com 完成培训。"
exit 1
else
# API不可用时,记录日志但允许提交,避免阻塞开发
echo "⚠️ 警告:无法连接培训系统,跳过培训检查。(建议尽快修复)" >&2
exit 0
fi
场景B:检查“培训计划”文件内容或变更
假设仓库里有一个 docs/training_plan.md 文件,你想确保它总是被更新。
示例 3:检查文件是否被修改(pre-commit)
检查当前变更中是否包含了 training_plan.md,如果没有则警告。
#!/bin/bash
# 检查暂存区(staged)中是否包含培训计划文件
if ! git diff --cached --name-only | grep -q "training_plan.md"; then
echo "⚠️ 警告:您的提交未包含 'docs/training_plan.md' 的更新。"
echo "如果这次提交改变了培训计划,请务必包含该文件。"
# 这里不 exit 1,只发出警告,如果必须强制,则改为 exit 1
# exit 1
fi
exit 0
示例 4:检查文件格式是否正确(pre-commit)
假设培训计划是一个JSON文件 training/plan.json,必须包含 version 和 participants 字段。
#!/bin/bash
STAGED_PLAN=$(git diff --cached --name-only | grep "training/plan.json")
if [ -n "$STAGED_PLAN" ]; then
# 获取暂存区中的文件内容
CONTENT=$(git show :training/plan.json)
# 使用python或jq检查JSON格式和字段
echo "$CONTENT" | python3 -c "
import sys, json
try:
data = json.load(sys.stdin)
assert 'version' in data, '缺少version字段'
assert 'participants' in data, '缺少participants字段'
assert isinstance(data['participants'], list), 'participants必须是数组'
print('培训计划格式检查通过')
except Exception as e:
print(f'❌ 培训计划格式错误: {e}')
sys.exit(1)
" 2>&1 || exit 1 # 如果python检查失败,则退出
fi
exit 0
场景C:检查提交信息包含培训ID
要求每次提交必须包含 TRAINING-123 这样的培训任务ID。
文件:.git/hooks/commit-msg
#!/bin/bash
# commit-msg 钩子接收一个参数:提交信息文件路径
COMMIT_MSG_FILE=$1
COMMIT_MSG=$(cat "$COMMIT_MSG_FILE")
# 检查是否包含培训ID模式(TRAINING-数字 或 TRN-数字)
if ! echo "$COMMIT_MSG" | grep -qE '(TRAINING|TRN)-[0-9]+'; then
echo "❌ 提交信息错误:必须包含培训任务ID(如 TRAINING-12345)。"
echo "示例:git commit -m \"fix: 修复登录bug (TRAINING-12345)\""
exit 1
fi
exit 0
最佳实践与注意事项
- 不要完全阻塞开发:如果培训系统API不可用,建议允许提交(如示例2所示),避免开发流程完全中断。
- 使用
commit-msg而不是pre-commit:如果检查依赖于完整的提交信息,使用commit-msg钩子更合适。 - 团队共享钩子:将钩子脚本放到项目目录(如
scripts/hooks/)并通过git config core.hooksPath scripts/hooks/共享,但需要确保所有开发者都配置了该路径。 - 禁用钩子:永远记住
git commit --no-verify可以跳过钩子检查,这是合法的逃生舱口,不要恼火。 - 避免复杂逻辑:钩子脚本最好轻量、快速,过于复杂的逻辑(如数据库查询)应放在CI/CD阶段。
- 如果你需要阻止未培训的人提交 → 使用
pre-commit钩子,结合API检查(示例1/2)。 - 如果你需要检查培训计划文件的内容 → 使用
pre-commit钩子,解析文件(示例3/4)。 - 如果你需要提交信息包含培训编号 → 使用
commit-msg钩子(示例5)。
请根据你的实际场景选择,如果需要更具体的代码(比如如何从LDAP获取用户组),请补充描述你的“培训计划”具体指什么。