本文目录导读:

- 核心思路
- 场景一:检查演练计划文件是否存在
- 场景二:检查演练计划文件内容格式(如状态、日期)
- 场景三:检查演练计划是否被意外修改(加锁机制)
- 场景四:检查演练计划文件中的日期是否合理
- 场景五:结合外部脚本或命令进行复杂验证
- 如何部署这些脚本
- 常见问题与技巧
- 推荐的工具:pre-commit 框架
Git 钩子脚本可以通过检查特定文件内容、文件是否存在、分支命名规范或调用自定义逻辑等方式,来验证“演练计划”是否满足要求。
由于“演练计划”在 Git 仓库中体现为具体的文件(如 .md、.json、.yaml 或特定目录下的文件),以下是几种常见的检查实现方式。
核心思路
在 pre-commit(提交前)或 pre-push(推送前)钩子中,使用 git diff、git ls-tree 或 grep 等命令,对演练计划相关文件进行内容或结构校验。
检查演练计划文件是否存在
需求:每次提交必须包含一个名为 drill-plan.md 的文件,否则禁止提交。
脚本示例(.git/hooks/pre-commit):
#!/bin/sh
# 获取本次提交即将变更的文件列表(暂存区)
staged_files=$(git diff --cached --name-only)
# 检查是否包含演练计划文件
if echo "$staged_files" | grep -q "drill-plan.md"; then
exit 0
else
echo "错误:本次提交未包含 drill-plan.md 文件!"
echo "请确保演练计划已暂存。"
exit 1
fi
改进版本(支持特定目录):
#!/bin/sh
required_dir="plans/drill/"
staged_files=$(git diff --cached --name-only)
has_plan=false
for file in $staged_files; do
if echo "$file" | grep -q "^${required_dir}"; then
has_plan=true
break
fi
done
if [ "$has_plan" = false ]; then
echo "错误:暂存区中不存在 ${required_dir} 目录下的演练计划文件。"
exit 1
fi
检查演练计划文件内容格式(如状态、日期)
需求:演练计划文件(如 drill-plan.yaml)必须包含 status: approved 字段。
脚本示例(.git/hooks/pre-commit):
#!/bin/sh
staged_files=$(git diff --cached --name-only)
for file in $staged_files; do
# 仅检查以 .yaml 结尾的文件
case "$file" in
*drill-plan*.yaml|*drill-plan*.yml)
# 从暂存区获取文件内容(而非工作目录)
content=$(git show :"$file")
# 检查是否包含 approved 状态
if ! echo "$content" | grep -q "status: approved"; then
echo "错误:文件 $file 中的状态不是 'approved'。"
exit 1
fi
;;
esac
done
注意事项:
git show :"$file"获取暂存区中的文件内容,这是关键——如果用户修改了工作目录但未暂存,这里检查的是暂存区的内容。- 使用
case通配符匹配文件名,避免硬编码路径。
检查演练计划是否被意外修改(加锁机制)
需求:如果演练计划已被标记为“最终版”,则禁止任何人修改(除非特定用户或分支)。
脚本示例(.git/hooks/pre-commit):
#!/bin/sh
# 定义只读文件或目录
protected_files=("plans/final_drill_plan.md")
for file in "${protected_files[@]}"; do
if git diff --cached --name-only | grep -q "$file"; then
echo "错误:$file 是受保护的演练计划文件,禁止修改!"
echo "如需修改,请联系管理员。"
exit 1
fi
done
检查演练计划文件中的日期是否合理
需求:演练计划中的日期 date: 不能早于当前时间(不能使用过去的日期)。
脚本示例(.git/hooks/pre-commit):
#!/bin/sh
staged_files=$(git diff --cached --name-only)
for file in $staged_files; do
case "$file" in
*drill_plan*
# 提取暂存区文件中的日期行
plan_date=$(git show :"$file" | grep -E "^date:" | awk '{print $2}')
if [ -z "$plan_date" ]; then
echo "警告:文件 $file 中未找到 date 字段,跳过日期检查。"
continue
fi
current_date=$(date +%Y-%m-%d)
# 比较日期(假设格式为 YYYY-MM-DD)
if [ "$plan_date" \< "$current_date" ]; then
echo "错误:$file 中的日期 $plan_date 早于当前日期 $current_date。"
exit 1
fi
;;
esac
done
结合外部脚本或命令进行复杂验证
需求:使用独立的验证脚本(如 validate_plan.py)对演练计划进行结构化检查(JSON Schema、完整性等)。
脚本示例(.git/hooks/pre-commit):
#!/bin/sh
# 获取本次变更的演练计划文件列表
plan_files=$(git diff --cached --name-only | grep -E "plans/drill/.*\.(json|yaml|yml)$")
if [ -z "$plan_files" ]; then
exit 0 # 没有演练计划文件变更,直接通过
fi
# 针对每个文件执行外部验证脚本
for file in $plan_files; do
# 将暂存区文件内容传递给验证脚本
git show :"$file" | validate_plan.py "$file"
if [ $? -ne 0 ]; then
echo "错误:演练计划验证失败:$file"
exit 1
fi
done
如何部署这些脚本
-
创建钩子文件:
# 进入你的 Git 仓库 cd /path/to/your/repo cat > .git/hooks/pre-commit << 'EOF' # 将上述脚本内容粘贴到这里 EOF chmod +x .git/hooks/pre-commit
-
将钩子纳入版本管理(可选):
- 创建一个
scripts/git-hooks/目录,存放钩子脚本。 - 通过
git config core.hooksPath scripts/git-hooks让团队共享钩子。 - 或者使用
pre-commit框架管理(推荐)。
- 创建一个
-
测试脚本:
# 故意不包含演练计划进行提交尝试 echo "test" > other.txt git add other.txt git commit -m "test" # 应该被拒绝
常见问题与技巧
- 跨越暂存区:确保检查的是
git diff --cached(暂存区内容),而不是工作目录的git diff,钩子运行时,用户已经执行了git add,但尚未提交。 - 处理跨平台路径:在 Windows 环境中使用
git bash或确保脚本兼容sh(不要依赖 bash 特有语法)。 - 性能考虑:如果演练计划文件很多,避免在钩子中加载整个文件内容(使用
git show按需读取)。 - 跳过钩子:用户可以通过
git commit --no-verify跳过钩子,因此钩子不应作为唯一的权限控制手段,更多是辅助提醒。
推荐的工具:pre-commit 框架
如果你需要更复杂的、可共享的钩子管理,建议使用 pre-commit 框架,你可以编写一个自定义钩子(如 validate-drill-plan),然后在 .pre-commit-config.yaml 中引用:
repos:
- repo: local
hooks:
- id: check-drill-plan
name: 检查演练计划文件
entry: validate_plan.py
language: script
files: 'drill-plan\.(md|yaml|json)$'
这种方式让钩子的安装、更新和共享变得更简单。