git-hooks-setup

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Git Hooks Setup

Git Hooks 配置指南

Overview

概述

Configure Git hooks to enforce code quality standards, run automated checks, and prevent problematic commits from being pushed to shared repositories.
配置Git hooks以强制执行代码质量标准、运行自动化检查,并防止有问题的提交被推送到共享仓库。

When to Use

适用场景

  • Pre-commit code quality checks
  • Commit message validation
  • Preventing secrets in commits
  • Running tests before push
  • Code formatting enforcement
  • Linting configuration
  • Team-wide standards enforcement
  • 提交前代码质量检查
  • 提交信息验证
  • 防止提交中包含敏感信息
  • 推送前运行测试
  • 代码格式化强制执行
  • 代码扫描(Linting)配置
  • 团队统一标准强制执行

Implementation Examples

配置示例

1. Husky Installation and Configuration

1. Husky的安装与配置

bash
#!/bin/bash
bash
#!/bin/bash

setup-husky.sh

setup-husky.sh

Install Husky

Install Husky

npm install husky --save-dev
npm install husky --save-dev

Initialize Husky

Initialize Husky

npx husky install
npx husky install

Create pre-commit hook

Create pre-commit hook

npx husky add .husky/pre-commit "npm run lint"
npx husky add .husky/pre-commit "npm run lint"

Create commit-msg hook

Create commit-msg hook

npx husky add .husky/commit-msg 'npx --no -- commitlint --edit "$1"'
npx husky add .husky/commit-msg 'npx --no -- commitlint --edit "$1"'

Create pre-push hook

Create pre-push hook

npx husky add .husky/pre-push "npm run test"
npx husky add .husky/pre-push "npm run test"

Create post-merge hook

Create post-merge hook

npx husky add .husky/post-merge "npm install"
undefined
npx husky add .husky/post-merge "npm install"
undefined

2. Pre-commit Hook (Node.js)

2. Node.js环境下的Pre-commit钩子

bash
#!/usr/bin/env node
bash
#!/usr/bin/env node

.husky/pre-commit

.husky/pre-commit

const { execSync } = require('child_process'); const fs = require('fs');
console.log('🔍 Running pre-commit checks...\n');
try { // Get staged files const stagedFiles = execSync('git diff --cached --name-only', { encoding: 'utf-8' }) .split('\n') .filter(file => file && (file.endsWith('.js') || file.endsWith('.ts'))) .join(' ');
if (!stagedFiles) { console.log('✅ No JavaScript/TypeScript files to check'); process.exit(0); }
// Run linter on staged files console.log('📝 Running ESLint...'); execSync(
npx eslint ${stagedFiles} --fix
, { stdio: 'inherit' });
// Run Prettier console.log('✨ Running Prettier...'); execSync(
npx prettier --write ${stagedFiles}
, { stdio: 'inherit' });
// Stage the fixed files console.log('📦 Staging fixed files...'); execSync(
git add ${stagedFiles}
);
console.log('\n✅ Pre-commit checks passed!'); } catch (error) { console.error('❌ Pre-commit checks failed!'); process.exit(1); }
undefined
const { execSync } = require('child_process'); const fs = require('fs');
console.log('🔍 正在运行提交前检查...\n');
try { // Get staged files const stagedFiles = execSync('git diff --cached --name-only', { encoding: 'utf-8' }) .split('\n') .filter(file => file && (file.endsWith('.js') || file.endsWith('.ts'))) .join(' ');
if (!stagedFiles) { console.log('✅ 没有需要检查的JavaScript/TypeScript文件'); process.exit(0); }
// Run linter on staged files console.log('📝 运行ESLint检查...'); execSync(
npx eslint ${stagedFiles} --fix
, { stdio: 'inherit' });
// Run Prettier console.log('✨ 运行Prettier格式化...'); execSync(
npx prettier --write ${stagedFiles}
, { stdio: 'inherit' });
// Stage the fixed files console.log('📦 暂存修复后的文件...'); execSync(
git add ${stagedFiles}
);
console.log('\n✅ 提交前检查通过!'); } catch (error) { console.error('❌ 提交前检查失败!'); process.exit(1); }
undefined

3. Commit Message Validation

3. 提交信息验证

bash
#!/bin/bash
bash
#!/bin/bash

.husky/commit-msg

.husky/commit-msg

Validate commit message format

Validate commit message format

COMMIT_MSG=$(<"$1")
COMMIT_MSG=$(<"$1")

Pattern: type(scope): description

Pattern: type(scope): description

PATTERN="^(feat|fix|docs|style|refactor|test|chore|perf)(([a-z-]+))?: .{1,50}"
if ! [[ $COMMIT_MSG =~ $PATTERN ]]; then echo "❌ Invalid commit message format" echo "Format: type(scope): description" echo "Types: feat, fix, docs, style, refactor, test, chore, perf" echo "" echo "Examples:" echo " feat: add new feature" echo " fix(auth): resolve login bug" echo " docs: update README" exit 1 fi
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: add new feature" echo " fix(auth): resolve login bug" echo " docs: update README" exit 1 fi

Check message length

Check message length

FIRST_LINE=$(echo "$COMMIT_MSG" | head -n1) if [ ${#FIRST_LINE} -gt 72 ]; then echo "❌ Commit message too long (max 72 characters)" exit 1 fi
echo "✅ Commit message is valid"
undefined
FIRST_LINE=$(echo "$COMMIT_MSG" | head -n1) if [ ${#FIRST_LINE} -gt 72 ]; then echo "❌ 提交信息过长(最多72个字符)" exit 1 fi
echo "✅ 提交信息格式有效"
undefined

4. Commitlint Configuration

4. Commitlint配置

javascript
// 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']
  }
};
javascript
// 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. Pre-push Hook (Comprehensive)

5. 全面的Pre-push钩子

bash
#!/usr/bin/env bash
bash
#!/usr/bin/env bash

.husky/pre-push

.husky/pre-push

BRANCH=$(git rev-parse --abbrev-ref HEAD)
BRANCH=$(git rev-parse --abbrev-ref HEAD)

Prevent direct pushes to main

Prevent direct pushes to main

if [[ "$BRANCH" =~ ^(main|master)$ ]]; then echo "❌ Direct push to $BRANCH not allowed" exit 1 fi
npm test && npm run lint && npm run build
undefined
if [[ "$BRANCH" =~ ^(main|master)$ ]]; then echo "❌ 不允许直接推送到$BRANCH分支" exit 1 fi
npm test && npm run lint && npm run build
undefined

6. Pre-commit Framework (Python)

6. Python环境下的Pre-commit框架

yaml
undefined
yaml
undefined

.pre-commit-config.yaml

.pre-commit-config.yaml

repos:
undefined
repos:
undefined

7. Secret Detection Hook

7. 敏感信息检测钩子

bash
#!/bin/bash
bash
#!/bin/bash

.husky/pre-commit-secrets

.husky/pre-commit-secrets

git diff --cached | grep -E 'password|api_key|secret|token' && exit 1 echo "✅ No secrets detected"
undefined
git diff --cached | grep -E 'password|api_key|secret|token' && exit 1 echo "✅ 未检测到敏感信息"
undefined

8. Husky in package.json

8. package.json中的Husky配置

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

Best Practices

最佳实践

✅ DO

✅ 建议

  • Enforce pre-commit linting and formatting
  • Validate commit message format
  • Scan for secrets before commit
  • Run tests on pre-push
  • Skip hooks only with
    --no-verify
    (rarely)
  • Document hook requirements in README
  • Use consistent hook configuration
  • Make hooks fast (< 5 seconds)
  • Provide helpful error messages
  • Allow developers to bypass with clear warnings
  • 强制执行提交前的代码扫描与格式化
  • 验证提交信息格式
  • 提交前扫描敏感信息
  • 推送前运行测试
  • 仅在特殊情况下使用
    --no-verify
    跳过钩子
  • 在README中记录钩子要求
  • 使用统一的钩子配置
  • 确保钩子执行速度快(<5秒)
  • 提供清晰的错误提示信息
  • 允许开发者绕过钩子并给出明确警告

❌ DON'T

❌ 避免

  • Skip checks with
    --no-verify
  • Store secrets in committed files
  • Use inconsistent implementations
  • Ignore hook errors
  • Run full test suite on pre-commit
  • 随意使用
    --no-verify
    跳过检查
  • 在已提交的文件中存储敏感信息
  • 使用不一致的钩子实现
  • 忽略钩子错误
  • 在提交前运行完整测试套件

Resources

参考资源