本文目录导读:

Git 钩子脚本可以从多个维度检查代码性能问题,以下是针对不同场景的完整实现方案:
基础性能检查脚本结构
pre-commit 钩子示例(检查提交前代码)
#!/bin/bash
# .git/hooks/pre-commit
echo "🔍 开始性能检查..."
# 设置严格模式
set -e
# 定义性能违规函数
performance_violations=0
check_performance() {
local file="$1"
# 根据不同文件类型检查
case "$file" in
*.py)
check_python_performance "$file"
;;
*.js|*.ts)
check_javascript_performance "$file"
;;
*.java)
check_java_performance "$file"
;;
*.sql)
check_sql_performance "$file"
;;
esac
}
特定语言性能检查函数
Python 性能检查
check_python_performance() {
local file="$1"
# 检查循环中不必要的计算
if grep -n "for.*in range\|while.*:" "$file" | grep -q "len("; then
echo "⚠️ $file: 循环中可能重复计算 len(),建议缓存"
((performance_violations++))
fi
# 检查重复的数据库查询
if grep -n "\.query\|\.filter\|\.get(" "$file" | grep -q "for\|while"; then
echo "⚠️ $file: 循环中存在数据库查询,考虑批量操作"
((performance_violations++))
fi
# 检查大量字符串拼接
if grep -n "+=.*str\|+=.*'" "$file" | head -5 | grep -q "for\|while"; then
echo "⚠️ $file: 循环中使用字符串拼接,建议使用 join()"
((performance_violations++))
fi
# 检查未使用的导入
local unused_imports=$(grep "^import\|^from" "$file" | while read line; do
local module=$(echo "$line" | awk '{print $2}')
if ! grep -q "$module" <(grep -v "^import\|^from" "$file"); then
echo "$module"
fi
done)
if [ -n "$unused_imports" ]; then
echo "⚠️ $file: 可能未使用的导入: $unused_imports"
((performance_violations++))
fi
}
JavaScript/TypeScript 性能检查
check_javascript_performance() {
local file="$1"
# 检查不必要的 DOM 操作
if grep -n "\.innerHTML\s*=" "$file" | grep -q "for\|while\|forEach"; then
echo "⚠️ $file: 循环中频繁操作 innerHTML,建议使用 DocumentFragment"
((performance_violations++))
fi
# 检查闭包中的大对象
if grep -n "return function\|=> {" "$file" | head -10 | while read line; do
if echo "$line" | grep -q "large\|big\|heavy"; then
echo "⚠️ $file: 闭包中可能包含大对象,注意内存泄漏"
((performance_violations++))
fi
done
# 检查防抖/节流使用
if grep -n "\.addEventListener\|onclick\|onscroll\|onresize" "$file" | grep -v "debounce\|throttle"; then
echo "⚠️ $file: 高频事件未使用防抖/节流"
((performance_violations++))
fi
# 检查 import 大小(需要 webpack 配置)
if command -v node &> /dev/null; then
node -e "
const fs = require('fs');
const content = fs.readFileSync('$file', 'utf8');
const imports = content.match(/import\s+.*from\s+['\"]([^'\"]+)['\"]/g);
if (imports) {
imports.forEach(imp => {
if (imp.includes('lodash') || imp.includes('moment')) {
console.log('⚠️ 考虑使用 lodash 按需引入或 moment 替代方案');
}
});
}
"
fi
}
Java 性能检查
check_java_performance() {
local file="$1"
# 检查 StringBuilder 使用
if grep -n "String\s\+\w\+\s*=" "$file" | grep -q "for\|while"; then
echo "⚠️ $file: 循环中使用字符串拼接,建议使用 StringBuilder"
((performance_violations++))
fi
# 检查大对象序列化
if grep -n "implements Serializable\|@Serial" "$file" | grep -q "List\|Map\|Set"; then
echo "⚠️ $file: 大集合类实现 Serializable,注意性能影响"
((performance_violations++))
fi
# 检查线程安全
if grep -n "synchronized\|Lock\|Atomic" "$file" | grep -q "get\|set\|add\|remove"; then
# 这里的逻辑可能需要调整
true
fi
# 检查深拷贝
if grep -n "clone()\|new.*(.*old\|deepCopy\|deepClone" "$file"; then
echo "⚠️ $file: 使用深拷贝,注意性能开销"
((performance_violations++))
fi
}
SQL 性能检查
check_sql_performance() {
local file="$1"
# 检查 SELECT *
if grep -n "SELECT\s+\*" "$file"; then
echo "⚠️ $file: 使用 SELECT *,建议明确指定列"
((performance_violations++))
fi
# 检查缺少索引的 JOIN
if grep -n "JOIN\|LEFT JOIN\|RIGHT JOIN" "$file" | grep -v "INDEX\|index"; then
echo "⚠️ $file: JOIN 操作可能缺少索引"
((performance_violations++))
fi
# 检查 LIKE 前导通配符
if grep -n "LIKE\s+'%" "$file"; then
echo "⚠️ $file: LIKE 前导通配符将导致全表扫描"
((performance_violations++))
fi
# 检查 OR 条件(可能导致索引失效)
if grep -n "OR" "$file"; then
echo "⚠️ $file: 使用 OR 条件可能导致索引失效"
((performance_violations++))
fi
}
通用性能检查
大文件检查
check_file_size() {
local file="$1"
local max_size=500000 # 500KB
if [ -f "$file" ]; then
local size=$(stat -f%z "$file" 2>/dev/null || stat -c%s "$file" 2>/dev/null)
if [ "$size" -gt "$max_size" ]; then
echo "⚠️ 文件过大 ($(echo "scale=2; $size/1024/1024" | bc) MB): $file"
((performance_violations++))
fi
fi
}
依赖检查(package.json)
check_dependencies() {
if [ -f "package.json" ]; then
local heavy_packages=("lodash" "moment" "jquery" "bootstrap")
for package in "${heavy_packages[@]}"; do
if grep -q "\"$package\"" "package.json"; then
echo "⚠️ package.json 包含重依赖: $package"
((performance_violations++))
fi
done
fi
}
完整的 pre-commit 钩子
#!/bin/bash
# .git/hooks/pre-commit
echo "🔍 开始性能检查..."
performance_violations=0
# 获取暂存的文件
staged_files=$(git diff --cached --name-only --diff-filter=ACM)
if [ -z "$staged_files" ]; then
echo "✅ 没有需要检查的文件"
exit 0
fi
echo "检查以下文件:"
echo "$staged_files"
echo ""
# 逐个检查文件
for file in $staged_files; do
# 跳过非代码文件
[[ "$file" =~ \.(md|txt|json|yml|yaml)$ ]] && continue
echo "检查: $file"
# 文件大小检查
check_file_size "$file"
# 语言特定检查
check_performance "$file"
echo ""
done
# 依赖检查
check_dependencies
# 输出结果
if [ "$performance_violations" -gt 0 ]; then
echo "❌ 发现 $performance_violations 个潜在性能问题"
echo "请修复后重新提交,或使用 git commit --no-verify 跳过检查"
exit 1
else
echo "✅ 性能检查通过"
exit 0
fi
性能检查工具集成
集成 ESLint 性能规则
# .eslintrc.json 配置
{
"rules": {
"no-unused-vars": "error",
"no-console": "warn",
"no-await-in-loop": "warn",
"require-atomic-updates": "warn"
}
}
集成 Python Pylint 性能检查
# .pylintrc 配置
[MESSAGES CONTROL]
enable=performance
disable=C,R,W
# 在钩子中调用
if [ "$file" == *.py ]; then
pylint --load-plugins=pylint.extensions.bad_builtin "$file" 2>/dev/null || true
fi
性能检查报告生成
generate_performance_report() {
local report_file="performance_report_$(date +%Y%m%d_%H%M%S).md"
cat > "$report_file" << EOF
# 性能检查报告
生成时间: $(date)
提交者: $(git config user.name)
分支: $(git branch --show-current)
## 发现的问题
EOF
# 追加检查结果
for violation in "${violations[@]}"; do
echo "- $violation" >> "$report_file"
done
echo "报告已生成: $report_file"
}
使用建议
- 性能阈值设置:根据项目实际需求调整阈值
- 忽略列表:创建
.performanceignore文件跳过特定检查 - 增量检查:只检查新修改的代码,避免全量检查
- 并行执行:对于大型项目,考虑并行执行检查
- 持续优化:定期更新检查规则,适应项目演变
将这个脚本保存为 .git/hooks/pre-commit 并赋予执行权限:
chmod +x .git/hooks/pre-commit
这种方式的性能检查可以有效预防常见的性能问题,但建议配合专业的性能分析工具使用,以获得更全面的性能保障。