GitHooks设置 git-hooks-setup

这个技能用于配置 Git 钩子,以自动化代码质量检查、提交信息验证、秘密检测等,确保代码在提交和推送前符合团队标准。

DevOps 0 次安装 0 次浏览 更新于 3/4/2026

Git Hooks 设置

概览

配置 Git 钩子以强制执行代码质量标准,运行自动化检查,并防止有问题的提交被推送到共享仓库。

何时使用

  • 提交前代码质量检查
  • 提交信息验证
  • 防止提交中包含秘密
  • 提交前运行测试
  • 代码格式化执行
  • 代码风格检查配置
  • 团队范围内的标准执行

实施示例

1. Husky 安装和配置

#!/bin/bash
# setup-husky.sh

# 安装 Husky
npm install husky --save-dev

# 初始化 Husky
npx husky install

# 创建提交前钩子
npx husky add .husky/pre-commit "npm run lint"

# 创建提交信息钩子
npx husky add .husky/commit-msg 'npx --no -- commitlint --edit "$1"'

# 创建推送前钩子
npx husky add .husky/pre-push "npm run test"

# 创建合并后钩子
npx husky add .husky/post-merge "npm install"

2. 提交前钩子(Node.js)

#!/usr/bin/env node
# .husky/pre-commit

const { execSync } = require('child_process');
const fs = require('fs');

console.log('🔍 运行提交前检查...
');

try {
  // 获取暂存文件
  const stagedFiles = execSync('git diff --cached --name-only', { encoding: 'utf-8' })
    .split('
')
    .filter(file => file && (file.endsWith('.js') || file.endsWith('.ts')))
    .join(' ');

  if (!stagedFiles) {
    console.log('✅ 没有 JavaScript/TypeScript 文件需要检查');
    process.exit(0);
  }

  // 在暂存文件上运行 linter
  console.log('📝 运行 ESLint...');
  execSync(`npx eslint ${stagedFiles} --fix`, { stdio: 'inherit' });

  // 运行 Prettier
  console.log('✨ 运行 Prettier...');
  execSync(`npx prettier --write ${stagedFiles}`, { stdio: 'inherit' });

  // 暂存修正后的文件
  console.log('📦 暂存修正后的文件...');
  execSync(`git add ${stagedFiles}`);

  console.log('
✅ 提交前检查通过!');
} catch (error) {
  console.error('❌ 提交前检查失败!');
  process.exit(1);
}

3. 提交信息验证

#!/bin/bash
# .husky/commit-msg

# 验证提交信息格式
COMMIT_MSG=$(<"$1")

# 模式:type(scope): description
PATTERN="^(feat|fix|docs|style|refactor|test|chore|perf)(\([a-z\-]+\))?: .{1,50}"

if ! [[ $COMMIT_MSG =~ $PATTERN ]]; then
    echo "❌ 提交信息格式无效"
    echo "格式:type(scope): description"
    echo "类型:feat, fix, docs, style, refactor, test, chore, perf"
    echo ""
    echo "示例:"
    echo "  feat: 添加新功能"
    echo "  fix(auth): 解决登录错误"
    echo "  docs: 更新 README"
    exit 1
fi

# 检查信息长度
FIRST_LINE=$(echo "$COMMIT_MSG" | head -n1)
if [ ${#FIRST_LINE} -gt 72 ]; then
    echo "❌ 提交信息太长(最多 72 个字符)"
    exit 1
fi

echo "✅ 提交信息有效"

4. Commitlint 配置

// commitlint.config.js
module.exports = {
  extends: ['@commitlint/config-conventional'],
  rules: {
    'type-enum': [2, 'always', ['feat', 'fix', 'docs', 'style', 'refactor', 'test', 'chore']],
    'subject-case': [2, 'never', ['start-case', 'pascal-case', 'upper-case']],
    'type-empty': [2, 'never']
  }
};

5. 推送前钩子(综合)

#!/usr/bin/env bash
# .husky/pre-push
BRANCH=$(git rev-parse --abbrev-ref HEAD)

# 防止直接推送到主分支
if [[ "$BRANCH" =~ ^(main|master)$ ]]; then
  echo "❌ 直接推送到 $BRANCH 不被允许"
  exit 1
fi

npm test && npm run lint && npm run build

6. 提交前框架(Python)

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v4.4.0
    hooks:
      - id: trailing-whitespace
      - id: end-of-file-fixer
      - id: check-yaml
      - id: check-added-large-files
        args: ['--maxkb=1000']
      - id: detect-private-key
      - id: check-merge-conflict

  - repo: https://github.com/psf/black
    rev: 23.3.0
    hooks:
      - id: black
        language_version: python3.11

  - repo: https://github.com/PyCQA/flake8
    rev: 6.0.0
    hooks:
      - id: flake8
        args: ['--max-line-length=88', '--extend-ignore=E203,W503']

  - repo: https://github.com/PyCQA/isort
    rev: 5.12.0
    hooks:
      - id: isort
        args: ['--profile', 'black']

  - repo: https://github.com/Yelp/detect-secrets
    rev: v1.4.0
    hooks:
      - id: detect-secrets
        args: ['--baseline', '.secrets.baseline']

  - repo: https://github.com/commitizen-tools/commitizen
    rev: 3.5.2
    hooks:
      - id: commitizen
        stages: [commit-msg]

7. 秘密检测钩子

#!/bin/bash
# .husky/pre-commit-secrets
git diff --cached | grep -E 'password|api_key|secret|token' && exit 1
echo "✅ 未检测到秘密"

8. package.json 中的 Husky

{
  "scripts": { "prepare": "husky install" },
  "devDependencies": {
    "husky": "^8.0.0",
    "@commitlint/cli": "^17.0.0"
  },
  "lint-staged": {
    "*.{js,ts}": "eslint --fix"
  }
}

最佳实践

✅ 执行

  • 强制执行提交前代码风格检查和格式化
  • 验证提交信息格式
  • 提交前扫描秘密
  • 提交前运行测试
  • 仅在极少数情况下使用 --no-verify 跳过钩子
  • 在 README 中记录钩子需求
  • 使用一致的钩子配置
  • 使钩子快速(< 5 秒)
  • 提供有用的错误信息
  • 允许开发者绕过,并提供清晰的警告

❌ 不要

  • 使用 --no-verify 跳过检查
  • 在提交的文件中存储秘密
  • 使用不一致的实现
  • 忽略钩子错误
  • 在提交前运行完整的测试套件

资源