我来详细介绍Git钩子脚本如何检查改进计划,这是一个很好的实践,可以在代码提交前自动验证和改进代码质量。

基本检查框架
预提交钩子(pre-commit)
#!/bin/bash
# .git/hooks/pre-commit
echo "🔍 开始改进计划检查..."
# 收集变更文件
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM)
if [ -z "$STAGED_FILES" ]; then
echo "✅ 没有需要检查的文件"
exit 0
fi
# 初始化结果变量
ERRORS=0
WARNINGS=0
代码质量检查
语法和风格检查
# 语法检查函数
check_syntax() {
local file=$1
local ext="${file##*.}"
case $ext in
py)
python -m py_compile "$file" 2>/dev/null || {
echo "❌ Python语法错误: $file"
return 1
}
;;
js|jsx)
node -c "$file" 2>/dev/null || {
echo "❌ JavaScript语法错误: $file"
return 1
}
;;
ts|tsx)
npx tsc --noEmit "$file" 2>/dev/null || {
echo "❌ TypeScript语法错误: $file"
return 1
}
;;
sh)
bash -n "$file" 2>/dev/null || {
echo "❌ Shell语法错误: $file"
return 1
}
;;
esac
return 0
}
代码复杂度检查
# 检查函数复杂度
check_complexity() {
local file=$1
local max_lines=100
local max_nesting=3
# 检查文件行数
local lines=$(wc -l < "$file")
if [ $lines -gt $max_lines ]; then
echo "⚠️ 文件过长 ($lines行): $file"
WARNINGS=$((WARNINGS + 1))
fi
# 检查嵌套深度(示例:Python)
if [[ "$file" == *.py ]]; then
local max_depth=$(python3 -c "
import ast
with open('$file') as f:
tree = ast.parse(f.read())
def get_depth(node, current=0):
depths = [current]
for child in ast.iter_child_nodes(node):
if isinstance(child, (ast.If, ast.For, ast.While, ast.FunctionDef)):
depths.extend(get_depth(child, current + 1))
return depths
depths = get_depth(tree)
print(max(depths) if depths else 0)
" 2>/dev/null)
if [ "$max_depth" -gt "$max_nesting" ]; then
echo "⚠️ 嵌套过深 (深度$max_depth): $file"
WARNINGS=$((WARNINGS + 1))
fi
fi
}
安全检查
# 硬编码密码检查
check_secrets() {
local file=$1
# 检查常见的敏感信息模式
patterns=(
"password\s*=\s*['\"][^'\"]+['\"]"
"api_key\s*=\s*['\"][^'\"]+['\"]"
"secret\s*=\s*['\"][^'\"]+['\"]"
"token\s*=\s*['\"][^'\"]+['\"]"
"-----BEGIN (RSA|OPENSSH) PRIVATE KEY-----"
)
for pattern in "${patterns[@]}"; do
if grep -qE "$pattern" "$file" 2>/dev/null; then
echo "❌ 发现可能的敏感信息: $file"
ERRORS=$((ERRORS + 1))
return 1
fi
done
return 0
}
测试覆盖检查
# 检查测试文件
check_test_coverage() {
local file=$1
local filename=$(basename "$file")
local dir=$(dirname "$file")
# 跳过测试文件本身
if [[ "$filename" == test_* ]] || [[ "$filename" == *_test.* ]]; then
return 0
fi
# 查找对应的测试文件
local test_file="${dir}/test_${filename}"
if [[ ! -f "$test_file" ]]; then
test_file="${dir}/tests/test_${filename}"
fi
if [[ ! -f "$test_file" ]]; then
echo "⚠️ 缺少测试文件: $file"
WARNINGS=$((WARNINGS + 1))
fi
}
文档和注释检查
# 检查文档字符串
check_docs() {
local file=$1
if [[ "$file" == *.py ]]; then
python3 -c "
import ast
with open('$file') as f:
content = f.read()
tree = ast.parse(content)
# 检查函数和类的文档
for node in ast.walk(tree):
if isinstance(node, (ast.FunctionDef, ast.ClassDef)):
if not ast.get_docstring(node):
print(f'缺少文档: {node.name} at line {node.lineno}')
" 2>/dev/null | while read -r msg; do
echo "⚠️ $msg (in $file)"
WARNINGS=$((WARNINGS + 1))
done
fi
}
依赖检查
# 检查依赖更新
check_dependencies() {
local file=$1
# Python requirements.txt
if [[ "$file" == "requirements.txt" ]]; then
while IFS= read -r package; do
if [[ "$package" == *">="* ]] || [[ "$package" == *"=="* ]]; then
echo "⚠️ 考虑使用精确版本: $package"
WARNINGS=$((WARNINGS + 1))
fi
done < "$file"
fi
# Node.js package.json
if [[ "$file" == "package.json" ]]; then
if grep -q '"version": "\^' "$file" 2>/dev/null; then
echo "⚠️ 存在^版本依赖,建议锁定版本"
WARNINGS=$((WARNINGS + 1))
fi
fi
}
主检查流程
# 主执行函数
main() {
echo "=== 改进计划检查报告 ==="
echo "检查时间: $(date)"
echo "检查文件数: $(echo "$STAGED_FILES" | wc -l)"
echo ""
for file in $STAGED_FILES; do
echo "--- 检查: $file ---"
# 只检查代码文件
case "$file" in
*.py|*.js|*.ts|*.sh|*.go|*.java|*.rb|*.php)
check_syntax "$file" || ERRORS=$((ERRORS + 1))
check_complexity "$file"
check_secrets "$file" || ERRORS=$((ERRORS + 1))
check_test_coverage "$file"
check_docs "$file"
;;
requirements.txt|package.json|Gemfile)
check_dependencies "$file"
;;
esac
done
# 生成报告
echo ""
echo "=== 检查结果 ==="
echo "❌ 错误: $ERRORS"
echo "⚠️ 警告: $WARNINGS"
echo ""
# 改进建议
if [ $ERRORS -gt 0 ] || [ $WARNINGS -gt 0 ]; then
echo "💡 改进建议:"
[ $ERRORS -gt 0 ] && echo "- 请修复所有错误后再提交"
[ $WARNINGS -gt 0 ] && echo "- 建议处理警告以提升代码质量"
echo "- 考虑使用 'git commit --no-verify' 跳过检查(不推荐)"
else
echo "✅ 代码质量良好,可以提交!"
fi
# 根据错误数量决定是否阻止提交
[ $ERRORS -gt 0 ] && exit 1
exit 0
}
main
进阶功能
集成静态分析工具
# 集成多种检查工具
run_static_analysis() {
local file=$1
case "${file##*.}" in
py)
# Pylint
pylint --rcfile=.pylintrc "$file" 2>/dev/null || true
# Flake8
flake8 --max-line-length=100 "$file" 2>/dev/null || true
;;
js|ts)
# ESLint
npx eslint "$file" 2>/dev/null || true
;;
go)
# Golangci-lint
golangci-lint run "$file" 2>/dev/null || true
;;
esac
}
性能检查
# 检查性能问题
check_performance() {
local file=$1
if [[ "$file" == *.py ]]; then
# 检查常见性能模式
if grep -q "for.*in.*range(len" "$file" 2>/dev/null; then
echo "⚠️ 建议使用enumerate代替range(len()): $file"
fi
if grep -q "^import \*" "$file" 2>/dev/null; then
echo "⚠️ 避免使用通配符导入: $file"
fi
fi
if [[ "$file" == *.js ]]; then
if grep -q "== " "$file" 2>/dev/null; then
echo "ℹ️ 建议使用===代替==: $file"
fi
fi
}
安装和使用
- 安装钩子脚本:
#!/bin/bash # setup-hooks.sh
HOOKS_DIR=".git/hooks" mkdir -p "$HOOKS_DIR"
cat > "$HOOKS_DIR/pre-commit" << 'EOF'
这里是上面的完整pre-commit脚本内容
EOF
chmod +x "$HOOKS_DIR/pre-commit" echo "✅ Git钩子安装完成"
2. **跳过检查**(紧急情况):
```bash
git commit --no-verify -m "紧急修复"
这个检查系统可以根据项目需求进行定制,比如添加特定的业务规则检查、集成更多工具,或者根据团队规范调整警告级别,关键是要在保护代码质量和不影响开发效率之间找到平衡。