本文目录导读:

Git 钩子脚本(特别是 pre-commit 和 commit-msg 钩子)非常适合用于自动化变更管理检查,以下是几种常见的检查策略及对应的钩子脚本实现示例。
变更范围与文件类型检查
禁止提交特定文件类型
#!/bin/bash
# .git/hooks/pre-commit
# 禁止提交 .log、.tmp 文件
for file in $(git diff --cached --name-only); do
if [[ "$file" =~ \.(log|tmp|bak|swp)$ ]]; then
echo "错误:禁止提交临时文件:$file"
exit 1
fi
done
检查文件大小限制
#!/bin/bash
# .git/hooks/pre-commit
MAX_SIZE=$((10 * 1024 * 1024)) # 10MB
git diff --cached --name-only -z | xargs -0 stat --format='%s %n' | while read size file; do
if [ "$size" -gt "$MAX_SIZE" ]; then
echo "错误:文件过大 (>10MB):$file"
exit 1
fi
done
代码质量与规范检查
ESLint 检查(JavaScript/TypeScript)
#!/bin/bash
# .git/hooks/pre-commit
# 获取暂存区中修改的 JS/TS 文件
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.(js|ts|tsx|jsx)$')
if [ -n "$STAGED_FILES" ]; then
echo "运行 ESLint 检查..."
npx eslint $STAGED_FILES
if [ $? -ne 0 ]; then
echo "ESLint 检查失败,请修正后重新提交"
exit 1
fi
fi
Python 代码规范检查
#!/bin/bash
# .git/hooks/pre-commit
STAGED_PY=$(git diff --cached --name-only --diff-filter=ACM | grep '\.py$')
if [ -n "$STAGED_PY" ]; then
echo "运行 Flake8 检查..."
flake8 $STAGED_PY
if [ $? -ne 0 ]; then
echo "Python 代码规范检查失败"
exit 1
fi
fi
提交信息规范检查
提交信息格式验证
#!/bin/bash
# .git/hooks/commit-msg
COMMIT_MSG_FILE=$1
COMMIT_MSG=$(cat "$COMMIT_MSG_FILE")
# 检查提交信息格式: [类型]: 描述
# 类型: feat|fix|docs|style|refactor|test|chore
if ! echo "$COMMIT_MSG" | grep -qE '^(feat|fix|docs|style|refactor|test|chore)(\(.+\))?: .{1,50}$'; then
echo "错误:提交信息格式不正确"
echo "正确格式: [类型]: 描述"
echo "示例: feat: 添加用户登录功能"
echo "类型: feat|fix|docs|style|refactor|test|chore"
exit 1
fi
变更日志检查
检查变更文件是否更新了 CHANGELOG
#!/bin/bash
# .git/hooks/pre-commit
# 检查是否有除 CHANGELOG 外的文件被修改
STAGED_FILES=$(git diff --cached --name-only)
HAS_CHANGES=$(echo "$STAGED_FILES" | grep -v "CHANGELOG.md" | wc -l)
HAS_CHANGELOG=$(echo "$STAGED_FILES" | grep "CHANGELOG.md" | wc -l)
if [ "$HAS_CHANGES" -gt 0 ] && [ "$HAS_CHANGELOG" -eq 0 ]; then
echo "警告:您修改了代码但未更新 CHANGELOG.md"
echo "是否继续提交?(y/n)"
read -r response
if [ "$response" != "y" ]; then
exit 1
fi
fi
分支命名规范检查
#!/bin/bash
# .git/hooks/pre-commit
BRANCH_NAME=$(git rev-parse --abbrev-ref HEAD)
# 允许的分支命名模式
# feature/xxx, bugfix/xxx, hotfix/xxx, release/xxx
if [[ "$BRANCH_NAME" =~ ^(feature|bugfix|hotfix|release)/[a-z0-9_-]+$ ]]; then
# 根据分支类型添加额外的检查
case "$BRANCH_NAME" in
feature/*)
# 功能分支检查
;;
bugfix/*)
# 修复分支检查:确保有关联的 Issue 编号
if [[ ! "$BRANCH_NAME" =~ -[0-9]+$ ]]; then
echo "错误:bugfix 分支应包含 Issue 编号"
echo "示例: bugfix/fix-login-123"
exit 1
fi
;;
esac
else
echo "警告:当前分支名称 '$BRANCH_NAME' 不符合命名规范"
echo "推荐格式: feature/xxx, bugfix/xxx, hotfix/xxx"
fi
综合示例:完整变更管理检查脚本
#!/bin/bash
# .git/hooks/pre-commit
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
ERRORS=0
WARNINGS=0
echo "=== 变更管理检查开始 ==="
# 1. 获取所有变更文件
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM)
echo "变更文件数量: $(echo "$STAGED_FILES" | wc -l)"
# 2. 检查禁止提交的文件类型
echo -e "\n[检查1] 文件类型检查..."
for file in $STAGED_FILES; do
if [[ "$file" =~ \.(log|tmp|bak|swp|DS_Store)$ ]]; then
echo -e "${RED}错误:禁止提交临时文件:$file${NC}"
((ERRORS++))
fi
done
# 3. 检查文件大小
echo -e "\n[检查2] 文件大小检查..."
MAX_SIZE=$((5 * 1024 * 1024))
while IFS= read -r file; do
if [ -f "$file" ]; then
size=$(stat -f%z "$file" 2>/dev/null || stat -c%s "$file" 2>/dev/null)
if [ "$size" -gt "$MAX_SIZE" ]; then
echo -e "${RED}错误:文件过大 (>5MB):$file (大小: $((size/1024/1024))MB)${NC}"
((ERRORS++))
fi
fi
done <<< "$STAGED_FILES"
# 4. 检查敏感信息
echo -e "\n[检查3] 敏感信息检查..."
for file in $STAGED_FILES; do
if [ -f "$file" ] && [[ ! "$file" =~ \.(png|jpg|jpeg|gif|ico)$ ]]; then
# 检查常见的敏感信息模式
if grep -qP '(password|api_key|secret|token|credential|private_key)' "$file" 2>/dev/null; then
echo -e "${YELLOW}警告:文件可能包含敏感信息:$file${NC}"
((WARNINGS++))
fi
fi
done
# 5. 检查是否有 TODO/FIXME 注释
echo -e "\n[检查4] TODO/FIXME 检查..."
for file in $STAGED_FILES; do
if [ -f "$file" ] && [[ "$file" =~ \.(py|js|ts|java|go|rb|php)$ ]]; then
if grep -qP '(TODO|FIXME|HACK|XXX)' "$file" 2>/dev/null; then
echo -e "${YELLOW}警告:文件包含 TODO/FIXME 标记:$file${NC}"
((WARNINGS++))
fi
fi
done
# 6. 检查分支命名
echo -e "\n[检查5] 分支命名检查..."
BRANCH_NAME=$(git rev-parse --abbrev-ref HEAD)
if [[ "$BRANCH_NAME" == "main" || "$BRANCH_NAME" == "master" ]]; then
echo -e "${RED}错误:禁止直接在主分支上提交${NC}"
((ERRORS++))
fi
# 汇总结果
echo -e "\n=== 检查完成 ==="
echo -e "${RED}错误: $ERRORS${NC}"
echo -e "${YELLOW}警告: $WARNINGS${NC}"
if [ $ERRORS -gt 0 ]; then
echo -e "${RED}由于存在错误,提交被终止${NC}"
exit 1
fi
echo -e "${GREEN}所有检查通过,允许提交${NC}"
exit 0
钩子脚本部署建议
-
赋予执行权限:
chmod +x .git/hooks/pre-commit chmod +x .git/hooks/commit-msg
-
团队共享配置:将钩子脚本放在项目仓库中
mkdir -p .githooks cp .git/hooks/* .githooks/
-
全局配置:设置全局钩子路径
git config --global core.hooksPath /path/to/global/hooks
-
使用 Husky(Node.js 项目):
// package.json { "husky": { "hooks": { "pre-commit": "npm run test && npm run lint", "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" } } }
最佳实践建议
-
渐进式执行:先以警告形式运行,待团队适应后再改为强制检查
-
提供跳过机制:
git commit --no-verify # 跳过钩子检查
-
性能优化:避免在钩子中执行耗时操作(如完整测试套件)
-
错误信息清晰:提供明确的错误信息和修复建议
-
版本控制:将钩子脚本纳入版本管理,确保团队一致
通过合理配置 Git 钩子,可以有效实施变更管理策略,提高代码质量和团队协作效率。