本文目录导读:

常用 Git 钩子与检查时机
| 钩子类型 | 触发时机 | 适用场景 |
|---|---|---|
pre-commit |
执行 git commit 之前 |
检查代码格式、禁止提交调试代码、运行静态分析 |
commit-msg |
用户输入提交信息后 | 检查提交信息格式(如是否包含 issue 编号) |
pre-push |
执行 git push 之前 |
运行单元测试、集成测试、安全扫描、覆盖率检查 |
pre-receive / update |
服务端接收推送时 | 强制分支保护规则、合规性检查 |
常见的可靠性门禁检查项
1 代码风格与静态分析
#!/bin/sh
# pre-commit 示例:运行 linter 和格式化检查
npm run lint
if [ $? -ne 0 ]; then
echo "❌ Linting failed. Please fix issues before commit."
exit 1
fi
# 检查是否有调试代码(如 console.log 在非开发环境)
if git diff --cached | grep -E "console\.log|debugger" > /dev/null; then
echo "❌ Found debugger/console.log in staged changes. Remove them first."
exit 1
fi
2 单元测试与覆盖率
#!/bin/sh
# pre-push 示例:运行单元测试并检查覆盖率
npm test -- --coverage
# 提取覆盖率数据(假设 Jest 输出到 coverage/lcov-report/index.html)
COVERAGE=$(node -e "const cov = require('./coverage/coverage-summary.json'); console.log(cov.total.lines.pct);")
# 设置最低覆盖率门限(80%)
THRESHOLD=80
if (( $(echo "$COVERAGE < $THRESHOLD" | bc -l) )); then
echo "❌ Code coverage is ${COVERAGE}%, which is below the ${THRESHOLD}% threshold."
exit 1
fi
3 安全漏洞扫描
#!/bin/sh
# pre-push 示例:运行 npm audit 或安全插件
npm audit --audit-level=high
if [ $? -ne 0 ]; then
echo "❌ Security audit failed. Fix vulnerabilities before pushing."
exit 1
fi
4 构建验证
#!/bin/sh
# pre-push 示例:确保代码可以编译或构建成功
npm run build
if [ $? -ne 0 ]; then
echo "❌ Build failed. Fix compilation errors before pushing."
exit 1
fi
管理多个钩子与工具链(推荐)
使用 Husky + lint-staged 是目前最流行的方式:
安装
npm install husky lint-staged --save-dev npx husky init
配置 package.json
{
"lint-staged": {
"*.{js,ts,tsx}": ["eslint --fix", "prettier --write"],
"*.md": ["prettier --write"]
}
}
配置钩子 .husky/pre-commit
#!/bin/sh npx lint-staged npx tsc --noEmit # TypeScript 类型检查
配置钩子 .husky/pre-push
#!/bin/sh npm run test:coverage npm run audit npm run build
服务端强制门禁(服务端钩子)
如果团队需要不可绕过的门禁,可以在远程 Git 仓库(如 GitLab/GitHub Self-hosted)配置:
服务端 pre-receive 钩子(Git 原生)
#!/bin/bash
# 强制:每次 push 都必须包含测试通过记录(如 CI pipeline 传递的 token)
while read oldrev newrev refname; do
# 检查是否在分支保护范围内
if [ "$refname" = "refs/heads/main" ]; then
# 实际生产环境:调用外部 CI 系统 API 确认构建状态
echo "❌ Direct push to main is blocked. Use merge request + CI pipeline."
exit 1
fi
done
更推荐的做法:结合 CI/CD 系统
- GitLab CI / GitHub Actions:在 Pipeline 中定义可靠性门禁,仅当通过后才允许合并 PR。
- Branch Protection Rules:设置“需要状态检查通过”才能合并。
绕过风险与最佳实践
| 风险 | 解决方案 |
|---|---|
用户可以 git commit --no-verify 跳过钩子 |
服务端钩子(pre-receive)不可绕过 |
| 钩子运行耗时过长影响开发体验 | 使用 lint-staged 仅检查暂存区文件 |
| 依赖安装失败导致钩子无效 | CI 中再次执行相同检查作为双重保障 |
| 不同开发环境差异导致误判 | 使用 Docker 容器化环境运行检查 |
完整示例脚本(pre-push)
#!/bin/bash
# .husky/pre-push - 综合可靠性门禁
echo "🔍 Running reliability gate checks..."
# 1. 运行单元测试并生成覆盖率报告
npm test -- --coverage --silent
TEST_EXIT=$?
if [ $TEST_EXIT -ne 0 ]; then
echo "❌ Unit tests failed. Fix before pushing."
exit 1
fi
# 2. 检查代码覆盖率(从 coverage-summary.json 解析)
COVERAGE=$(node -e "
try {
const c = require('./coverage/coverage-summary.json');
const lines = c.total.lines.pct;
const branches = c.total.branches.pct;
const minLines = process.argv[1] || 85;
console.log(JSON.stringify({ lines, branches }));
} catch(e) {
console.log('{}');
}
" 2>/dev/null)
LINES=$(echo "$COVERAGE" | node -e "const d = JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')); console.log(d.lines || 0);" 2>/dev/null)
THRESHOLD=85
if (( $(echo "$LINES < $THRESHOLD" | bc -l 2>/dev/null) )); then
echo "❌ Line coverage ${LINES}% < ${THRESHOLD}% threshold."
exit 1
fi
# 3. 安全扫描(仅检查 high 以上级别)
npm audit --audit-level=high 2>&1 | tail -1 | grep -q "found 0 vulnerabilities"
if [ $? -ne 0 ]; then
echo "❌ High/critical vulnerabilities found. Fix before push."
exit 1
fi
# 4. 生产构建验证
npm run build 2>/dev/null
if [ $? -ne 0 ]; then
echo "❌ Build failed."
exit 1
fi
echo "✅ All reliability checks passed. Push allowed."
exit 0
可靠性门禁检查核心思路
命令行:git commit --no-verify? → 本地钩子很容易绕过
CI/CD:merge request pipeline → 最可靠的门禁位置
服务端钩子:pre-receive → 不可绕过,但管理成本高
最佳组合:本地钩子 + CI 门禁 → 既快又安全
关键点:本地钩子防止低质量代码流出,CI 门禁作为最终防线,服务端保护规则封死绕过路径。