init-pre-commit

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Initialize Pre-Commit Configuration

初始化Pre-Commit配置

Initialize or augment a
.pre-commit-config.yaml
for the current project. If a config exists, parse it and only add hooks that aren't already present. Never alter existing hook behavior or remove hooks the project already uses.
为当前项目初始化或补充
.pre-commit-config.yaml
配置。如果配置文件已存在,则解析文件仅添加尚未配置的hook,绝对不会修改已有hook的行为,也不会删除项目正在使用的hook。

When to Use

适用场景

  • Setting up a new project
  • Adding pre-commit to an existing project
  • Augmenting an existing pre-commit config with additional hooks
  • Standardizing code quality checks across a team
  • Ensuring conventional commits compliance
  • Enforcing security best practices before code lands
  • Running fast tests before every commit
  • 新项目搭建时
  • 为现有项目添加pre-commit能力
  • 为已有的pre-commit配置补充额外的hook
  • 统一团队的代码质量检查标准
  • 确保约定式提交规范落地
  • 在代码入库前强制执行安全最佳实践
  • 每次提交前运行快速测试

Process

操作流程

1. Check for Existing Configuration

1. 检查已有配置

First, check if
.pre-commit-config.yaml
already exists in the project root:
bash
ls -la .pre-commit-config.yaml 2>/dev/null || echo "No pre-commit config found"
If it exists, parse it to identify existing hooks:
bash
undefined
首先检查项目根目录是否已存在
.pre-commit-config.yaml
bash
ls -la .pre-commit-config.yaml 2>/dev/null || echo "No pre-commit config found"
如果文件已存在,解析文件识别已有的hook:
bash
undefined

Extract existing hook IDs

提取已有hook ID

grep -E "^\s+- id:" .pre-commit-config.yaml | sed 's/.*- id: //' | sort -u
grep -E "^\s+- id:" .pre-commit-config.yaml | sed 's/.*- id: //' | sort -u

Extract existing repos

提取已有仓库地址

grep -E "^\s+- repo:" .pre-commit-config.yaml | sed 's/.*- repo: //' | sort -u

**Do not overwrite or modify existing hooks.** Only add hooks that aren't already configured.
grep -E "^\s+- repo:" .pre-commit-config.yaml | sed 's/.*- repo: //' | sort -u

**不要覆盖或修改已有的hook**,仅添加尚未配置的hook。

2. Detect Project Technologies

2. 检测项目技术栈

Analyze the project structure to determine what languages and technologies are present:
bash
undefined
分析项目结构判断项目使用的编程语言和技术栈:
bash
undefined

Check for common project files

检查常见项目文件

find . -maxdepth 2 -type f (
-name "Cargo.toml" -o
-name "package.json" -o
-name "pyproject.toml" -o
-name "setup.py" -o
-name "requirements.txt" -o
-name "go.mod" -o
-name ".rs" -o
-name "
.py" -o
-name ".ts" -o
-name "
.tsx" -o
-name ".js" -o
-name "
.go" -o
-name ".sh" -o
-name "
.md" -o
-name "Dockerfile" -o
-name "docker-compose.yml" -o
-name ".tf" -o
-name "
.yaml" -o
-name "*.yml"
) 2>/dev/null | head -50

Also check for specific directories:

```bash
ls -la 2>/dev/null | grep -E "(api|mobile|web|frontend|backend|src|app|tests|docs)"
find . -maxdepth 2 -type f (
-name "Cargo.toml" -o
-name "package.json" -o
-name "pyproject.toml" -o
-name "setup.py" -o
-name "requirements.txt" -o
-name "go.mod" -o
-name ".rs" -o
-name "
.py" -o
-name ".ts" -o
-name "
.tsx" -o
-name ".js" -o
-name "
.go" -o
-name ".sh" -o
-name "
.md" -o
-name "Dockerfile" -o
-name "docker-compose.yml" -o
-name ".tf" -o
-name "
.yaml" -o
-name "*.yml"
) 2>/dev/null | head -50

同时检查是否存在特定目录:

```bash
ls -la 2>/dev/null | grep -E "(api|mobile|web|frontend|backend|src|app|tests|docs)"

3. Ask for Clarification (If Needed)

3. 必要时询问用户确认

If no clear technology indicators are found, or if the project structure is ambiguous, ask the user:
"I don't see clear indicators of specific languages in this project. What languages or technologies are you expecting to use? (e.g., Rust, TypeScript/React, Python, Go, etc.)"
如果没有找到明确的技术栈标识,或者项目结构模糊不清,询问用户:
"我没有在项目中找到明确的编程语言标识,你预期这个项目会使用哪些语言或技术?例如:Rust、TypeScript/React、Python、Go等。"

4. Determine Hooks to Add

4. 确定需要添加的hook

Compare recommended hooks against existing configuration. For each hook category, check if an equivalent already exists:
Hook PurposeExisting Hook Patterns to Check
Commit message format
conventional-pre-commit
,
commitlint
Trailing whitespace
trailing-whitespace
EOF fixer
end-of-file-fixer
Secret scanning
detect-private-key
,
gitleaks
,
ripsecrets
Formatting (Rust)
cargo-fmt
,
cargo fmt
Formatting (Python)
ruff-format
,
black
,
autopep8
Formatting (JS/TS)
prettier
Linting (Rust)
cargo-clippy
,
cargo clippy
Linting (Python)
ruff
,
flake8
,
pylint
Linting (JS/TS)
eslint
Type checking (TS)
tsc
,
typescript
Type checking (Python)
mypy
Testing (Python)
pytest
Testing (Rust)
cargo-test
,
cargo test
Testing (JS/TS)
jest
,
vitest
Complexity
lizard
Spell checking
codespell
,
cspell
SQL linting
sqlfluff
Shell linting
shellcheck
Markdown linting
markdownlint
Skip any hook that already has an equivalent. Report these as "already configured."
将推荐的hook与已有配置对比,针对每个hook类别,检查是否已有等效的hook存在:
Hook用途需检查的已有hook匹配规则
提交信息格式检查
conventional-pre-commit
,
commitlint
行尾空格清理
trailing-whitespace
文件尾换行修复
end-of-file-fixer
密钥扫描
detect-private-key
,
gitleaks
,
ripsecrets
Rust代码格式化
cargo-fmt
,
cargo fmt
Python代码格式化
ruff-format
,
black
,
autopep8
JS/TS代码格式化
prettier
Rust代码检查
cargo-clippy
,
cargo clippy
Python代码检查
ruff
,
flake8
,
pylint
JS/TS代码检查
eslint
TS类型检查
tsc
,
typescript
Python类型检查
mypy
Python测试
pytest
Rust测试
cargo-test
,
cargo test
JS/TS测试
jest
,
vitest
圈复杂度检查
lizard
拼写检查
codespell
,
cspell
SQL代码检查
sqlfluff
Shell脚本检查
shellcheck
Markdown检查
markdownlint
跳过所有已有等效实现的hook,将这些hook标记为"已配置"。

5. Generate or Augment Configuration

5. 生成或补充配置

If no config exists: Create a new
.pre-commit-config.yaml
with all recommended hooks for detected technologies.
If config exists: Append only the missing hooks to the existing configuration. Preserve:
  • Existing
    repos
    entries (don't modify)
  • Existing hook configurations (don't change args, files, etc.)
  • Existing
    ci:
    configuration
  • Comments and formatting
如果不存在配置文件:根据检测到的技术栈,创建全新的
.pre-commit-config.yaml
文件,包含所有推荐的hook。
如果配置文件已存在:仅将缺失的hook追加到现有配置中,保留以下内容:
  • 已有
    repos
    条目(不要修改)
  • 已有hook配置(不要修改参数、文件匹配规则等)
  • 已有
    ci:
    配置
  • 注释和格式

Example: Augmenting Existing Config

示例:补充现有配置

Before:
yaml
repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v5.0.0
    hooks:
      - id: trailing-whitespace
      - id: end-of-file-fixer
After (adding missing hooks):
yaml
repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v5.0.0
    hooks:
      - id: trailing-whitespace
      - id: end-of-file-fixer

  # Added by init-pre-commit skill
  - repo: https://github.com/compilerla/conventional-pre-commit
    rev: v4.0.0
    hooks:
      - id: conventional-pre-commit
        stages: [commit-msg]

  - repo: https://github.com/gitleaks/gitleaks
    rev: v8.23.3
    hooks:
      - id: gitleaks
修改前:
yaml
repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v5.0.0
    hooks:
      - id: trailing-whitespace
      - id: end-of-file-fixer
修改后(添加缺失的hook):
yaml
repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v5.0.0
    hooks:
      - id: trailing-whitespace
      - id: end-of-file-fixer

  # Added by init-pre-commit skill
  - repo: https://github.com/compilerla/conventional-pre-commit
    rev: v4.0.0
    hooks:
      - id: conventional-pre-commit
        stages: [commit-msg]

  - repo: https://github.com/gitleaks/gitleaks
    rev: v8.23.3
    hooks:
      - id: gitleaks

6. Report Results

6. 反馈配置结果

After generating or augmenting, provide a summary:
Pre-commit configuration updated.

Added (5 hooks):
  ✓ conventional-pre-commit (commit message format)
  ✓ gitleaks (secret scanning)
  ✓ codespell (spell checking)
  ✓ cargo-clippy (Rust linting)
  ✓ lizard (cyclomatic complexity)

Already configured (3 hooks):
  • trailing-whitespace
  • end-of-file-fixer
  • prettier

Skipped (not applicable):
  • sqlfluff (no SQL files found)
  • depcheck (not a Node.js project)
生成或补充配置完成后,提供汇总信息:
Pre-commit配置已更新。

已添加(5个hook):
  ✓ conventional-pre-commit(提交信息格式检查)
  ✓ gitleaks(密钥扫描)
  ✓ codespell(拼写检查)
  ✓ cargo-clippy(Rust代码检查)
  ✓ lizard(圈复杂度检查)

已配置(3个hook):
  • trailing-whitespace
  • end-of-file-fixer
  • prettier

已跳过(不适用):
  • sqlfluff(未检测到SQL文件)
  • depcheck(非Node.js项目)

7. Install and Test

7. 安装并测试配置

After generating or augmenting the configuration, instruct the user to:
bash
undefined
生成或补充配置完成后,指导用户执行以下操作:
bash
undefined

Install pre-commit hooks

安装pre-commit钩子

pre-commit install pre-commit install --hook-type commit-msg
pre-commit install pre-commit install --hook-type commit-msg

Test on all files

对所有文件运行测试

pre-commit run --all-files
undefined
pre-commit run --all-files
undefined

8. Add Language-Specific Hooks

8. 添加语言专属hook

Based on detected technologies, add appropriate hooks:
根据检测到的技术栈,添加对应的hook:

Rust Projects

Rust项目

yaml
  # Rust — formatting, linting
  - repo: local
    hooks:
      - id: cargo-fmt
        name: cargo fmt
        language: system
        entry: cargo fmt -- --check
        pass_filenames: false
        types: [rust]

      - id: cargo-clippy
        name: cargo clippy
        language: system
        entry: cargo clippy -- -D warnings
        pass_filenames: false
        types: [rust]
Note: If the project has a non-standard structure (e.g., Rust code in
api/
subdirectory), adjust the
--manifest-path
accordingly:
yaml
entry: cargo fmt --manifest-path api/Cargo.toml -- --check
yaml
  # Rust — formatting, linting
  - repo: local
    hooks:
      - id: cargo-fmt
        name: cargo fmt
        language: system
        entry: cargo fmt -- --check
        pass_filenames: false
        types: [rust]

      - id: cargo-clippy
        name: cargo clippy
        language: system
        entry: cargo clippy -- -D warnings
        pass_filenames: false
        types: [rust]
注意: 如果项目结构非标准(例如Rust代码放在
api/
子目录下),对应调整
--manifest-path
参数:
yaml
entry: cargo fmt --manifest-path api/Cargo.toml -- --check

TypeScript/JavaScript Projects

TypeScript/JavaScript项目

yaml
  # TypeScript/JavaScript — formatting, linting
  # Note: ESLint v9 requires flat config (eslint.config.js). Use v8 for legacy .eslintrc configs.
  - repo: https://github.com/pre-commit/mirrors-eslint
    rev: v8.57.1
    hooks:
      - id: eslint
        additional_dependencies:
          - eslint@8.57.1
          - eslint-config-prettier
          - eslint-plugin-import
        files: \.(ts|tsx|js|jsx)$

  - repo: https://github.com/pre-commit/mirrors-prettier
    rev: v3.1.0
    hooks:
      - id: prettier
        types_or: [javascript, jsx, ts, tsx, json, yaml, markdown]
        args: [--prose-wrap=always, --print-width=88]
yaml
  # TypeScript/JavaScript — formatting, linting
  # Note: ESLint v9 requires flat config (eslint.config.js). Use v8 for legacy .eslintrc configs.
  - repo: https://github.com/pre-commit/mirrors-eslint
    rev: v8.57.1
    hooks:
      - id: eslint
        additional_dependencies:
          - eslint@8.57.1
          - eslint-config-prettier
          - eslint-plugin-import
        files: \.(ts|tsx|js|jsx)$

  - repo: https://github.com/pre-commit/mirrors-prettier
    rev: v3.1.0
    hooks:
      - id: prettier
        types_or: [javascript, jsx, ts, tsx, json, yaml, markdown]
        args: [--prose-wrap=always, --print-width=88]

Python Projects

Python项目

yaml
  # Python — formatting, linting
  - repo: https://github.com/astral-sh/ruff-pre-commit
    rev: v0.9.3
    hooks:
      - id: ruff
        args: [--fix]
      - id: ruff-format

  # Python type checking (if mypy is configured)
  - repo: https://github.com/pre-commit/mirrors-mypy
    rev: v1.14.1
    hooks:
      - id: mypy
        additional_dependencies: [types-all]
        args: [--ignore-missing-imports]
yaml
  # Python — formatting, linting
  - repo: https://github.com/astral-sh/ruff-pre-commit
    rev: v0.9.3
    hooks:
      - id: ruff
        args: [--fix]
      - id: ruff-format

  # Python type checking (if mypy is configured)
  - repo: https://github.com/pre-commit/mirrors-mypy
    rev: v1.14.1
    hooks:
      - id: mypy
        additional_dependencies: [types-all]
        args: [--ignore-missing-imports]

Go Projects

Go项目

yaml
  # Go — formatting, linting
  - repo: https://github.com/golangci/golangci-lint
    rev: v1.63.4
    hooks:
      - id: golangci-lint
        args: [--fix]

  - repo: local
    hooks:
      - id: go-fmt
        name: go fmt
        language: system
        entry: gofmt -l -w
        types: [go]
yaml
  # Go — formatting, linting
  - repo: https://github.com/golangci/golangci-lint
    rev: v1.63.4
    hooks:
      - id: golangci-lint
        args: [--fix]

  - repo: local
    hooks:
      - id: go-fmt
        name: go fmt
        language: system
        entry: gofmt -l -w
        types: [go]

Shell Scripts

Shell脚本

yaml
  # Shell script linting and formatting
  - repo: https://github.com/shellcheck-py/shellcheck-py
    rev: v0.10.0.1
    hooks:
      - id: shellcheck
        args: [--severity=warning]

  - repo: https://github.com/scop/pre-commit-shfmt
    rev: v3.11.0-1
    hooks:
      - id: shfmt
        args: [-i=2, -ci, -w]
yaml
  # Shell script linting and formatting
  - repo: https://github.com/shellcheck-py/shellcheck-py
    rev: v0.10.0.1
    hooks:
      - id: shellcheck
        args: [--severity=warning]

  - repo: https://github.com/scop/pre-commit-shfmt
    rev: v3.11.0-1
    hooks:
      - id: shfmt
        args: [-i=2, -ci, -w]

Markdown

Markdown

yaml
  # Markdown linting
  - repo: https://github.com/igorshubovych/markdownlint-cli
    rev: v0.44.0
    hooks:
      - id: markdownlint
        args: [--fix, --disable, MD013, MD033, --]
yaml
  # Markdown linting
  - repo: https://github.com/igorshubovych/markdownlint-cli
    rev: v0.44.0
    hooks:
      - id: markdownlint
        args: [--fix, --disable, MD013, MD033, --]

Docker

Docker

yaml
  # Dockerfile linting
  - repo: https://github.com/hadolint/hadolint
    rev: v2.12.0
    hooks:
      - id: hadolint
        args: [--ignore, DL3008, --ignore, DL3018]
yaml
  # Dockerfile linting
  - repo: https://github.com/hadolint/hadolint
    rev: v2.12.0
    hooks:
      - id: hadolint
        args: [--ignore, DL3008, --ignore, DL3018]

Terraform

Terraform

yaml
  # Terraform formatting and validation
  - repo: https://github.com/antonbabenko/pre-commit-terraform
    rev: v1.96.2
    hooks:
      - id: terraform_fmt
      - id: terraform_validate
      - id: terraform_tflint
yaml
  # Terraform formatting and validation
  - repo: https://github.com/antonbabenko/pre-commit-terraform
    rev: v1.96.2
    hooks:
      - id: terraform_fmt
      - id: terraform_validate
      - id: terraform_tflint

9. Add Security Hooks (Secret Scanning)

9. 添加安全hook(密钥扫描)

Secret scanning catches API keys, tokens, and credentials before they enter git history. This is critical to run on every commit because once a secret is committed, it's in the history forever—even if you delete the file.
Note: Dependency audits (
cargo audit
,
npm audit
), SAST tools (
semgrep
,
bandit
), and license compliance checks are not included here. These belong in CI because:
  • Dependencies change rarely (lockfiles update infrequently)
  • Running on every commit is wasteful
  • New vulnerabilities are discovered over time, not just when you commit
密钥扫描可以在API密钥、令牌、凭证进入Git历史前发现风险,这是每次提交必须运行的检查,因为一旦密钥被提交,即使删除文件,它也会永久留在历史记录中。
注意: 依赖审计(
cargo audit
npm audit
)、SAST工具(
semgrep
bandit
)和许可证合规检查不包含在此处,这些适合放在CI中运行,原因如下:
  • 依赖变动频率低(锁文件很少更新)
  • 每次提交都运行会造成资源浪费
  • 新的漏洞是持续被发现的,不仅仅是在提交时才会出现

Secret Scanning

密钥扫描

yaml
  # Gitleaks — comprehensive secret scanning
  - repo: https://github.com/gitleaks/gitleaks
    rev: v8.23.3
    hooks:
      - id: gitleaks
The core configuration already includes
detect-private-key
for basic secret detection. Use
gitleaks
for more comprehensive scanning.
yaml
  # Gitleaks — comprehensive secret scanning
  - repo: https://github.com/gitleaks/gitleaks
    rev: v8.23.3
    hooks:
      - id: gitleaks
核心配置已经包含了基础密钥检测工具
detect-private-key
,可以使用
gitleaks
实现更全面的扫描。

Security Hook Summary

安全hook汇总

HookPurposeStageSpeed
detect-private-key
Basic secret detectionpre-commitInstant
gitleaks
Comprehensive secret scanningpre-commitFast
CI-only security checks (not in pre-commit):
  • cargo audit
    /
    npm audit
    — Dependency vulnerability scanning
  • semgrep
    /
    bandit
    — Static application security testing
  • pip-licenses
    /
    license-checker
    — License compliance
Hook用途运行阶段速度
detect-private-key
基础密钥检测pre-commit即时
gitleaks
全面密钥扫描pre-commit
仅在CI中运行的安全检查(不放在pre-commit中):
  • cargo audit
    /
    npm audit
    — 依赖漏洞扫描
  • semgrep
    /
    bandit
    — 静态应用安全测试
  • pip-licenses
    /
    license-checker
    — 许可证合规检查

10. Add Cyclomatic Complexity Checks

10. 添加圈复杂度检查

For maintainability, add cyclomatic complexity analysis. Use lizard for universal support:
yaml
  # Cyclomatic complexity check
  - repo: local
    hooks:
      - id: lizard
        name: lizard (cyclomatic complexity)
        language: system
        entry: lizard -C 15 -w -x "*/tests/*" -x "*/migrations/*" -x "*/node_modules/*" -x "*/target/*" -x "*/dist/*" -x "*/.git/*" -x "*/__pycache__/*"
        pass_filenames: false
        types_or: [python, rust, ts, tsx, javascript, jsx, go, c, cpp, java]
Configuration Notes:
  • -C 15
    : Warn on functions with complexity > 15 (adjust based on team preference)
  • -w
    : Only show warnings
  • -x
    : Exclude test files, generated code, and dependencies
为了代码可维护性,添加圈复杂度分析,使用lizard实现多语言支持:
yaml
  # Cyclomatic complexity check
  - repo: local
    hooks:
      - id: lizard
        name: lizard (cyclomatic complexity)
        language: system
        entry: lizard -C 15 -w -x "*/tests/*" -x "*/migrations/*" -x "*/node_modules/*" -x "*/target/*" -x "*/dist/*" -x "*/.git/*" -x "*/__pycache__/*"
        pass_filenames: false
        types_or: [python, rust, ts, tsx, javascript, jsx, go, c, cpp, java]
配置说明:
  • -C 15
    :当函数复杂度超过15时发出警告(可根据团队偏好调整)
  • -w
    :仅显示警告
  • -x
    :排除测试文件、生成代码和依赖目录

11. Add Testing Hooks

11. 添加测试hook

Run fast tests before every commit to catch regressions early. Only include tests that complete in under 10 seconds.
每次提交前运行快速测试,尽早发现代码回归。仅包含运行时间低于10秒的测试。

Python Testing

Python测试

yaml
  # Python — run fast tests
  - repo: local
    hooks:
      - id: pytest-fast
        name: pytest (fast tests only)
        language: system
        entry: pytest -m "not slow" -x -q
        pass_filenames: false
        types: [python]
yaml
  # Python — run fast tests
  - repo: local
    hooks:
      - id: pytest-fast
        name: pytest (fast tests only)
        language: system
        entry: pytest -m "not slow" -x -q
        pass_filenames: false
        types: [python]

Rust Testing

Rust测试

yaml
  # Rust — run fast tests
  - repo: local
    hooks:
      - id: cargo-test
        name: cargo test (fast)
        language: system
        entry: cargo test --lib -- --test-threads=4 -q
        pass_filenames: false
        types: [rust]
yaml
  # Rust — run fast tests
  - repo: local
    hooks:
      - id: cargo-test
        name: cargo test (fast)
        language: system
        entry: cargo test --lib -- --test-threads=4 -q
        pass_filenames: false
        types: [rust]

TypeScript/JavaScript Testing

TypeScript/JavaScript测试

yaml
  # TypeScript — run fast tests
  - repo: local
    hooks:
      - id: jest-fast
        name: jest (fast tests)
        language: system
        entry: npx jest --testPathPattern="^(?!.*\.slow\.)" --passWithNoTests
        pass_filenames: false
        types_or: [ts, tsx, js, jsx]
yaml
  # TypeScript — run fast tests
  - repo: local
    hooks:
      - id: jest-fast
        name: jest (fast tests)
        language: system
        entry: npx jest --testPathPattern="^(?!.*\.slow\.)" --passWithNoTests
        pass_filenames: false
        types_or: [ts, tsx, js, jsx]

Coverage Threshold Enforcement

覆盖率阈值强制检查

Enforce minimum coverage on changed files:
yaml
  # Python — coverage threshold
  - repo: local
    hooks:
      - id: coverage-check
        name: coverage threshold (80%)
        language: system
        entry: pytest --cov --cov-fail-under=80 -q
        pass_filenames: false
        types: [python]
对修改的文件强制执行最低覆盖率要求:
yaml
  # Python — coverage threshold
  - repo: local
    hooks:
      - id: coverage-check
        name: coverage threshold (80%)
        language: system
        entry: pytest --cov --cov-fail-under=80 -q
        pass_filenames: false
        types: [python]

Testing Hook Guidelines

测试hook指导原则

GuidelineReason
< 10 secondsPre-commit runs on every commit; slow hooks break flow
Use
-x
flag
Stop on first failure; faster feedback
Exclude slow testsMark integration/e2e tests with
@pytest.mark.slow
or similar
Parallel executionUse
--test-threads
or
--maxWorkers
for speed
CI for full suiteRun complete test suite in CI, not pre-commit
原则原因
运行时间 < 10秒每次提交都会运行pre-commit,过慢的hook会打断开发流程
使用
-x
参数
遇到第一个失败就停止,反馈速度更快
排除慢速测试给集成/端到端测试添加
@pytest.mark.slow
或类似标记排除
并行执行使用
--test-threads
--maxWorkers
提升速度
CI运行完整测试套件完整测试套件在CI中运行,不要放在pre-commit里

12. Add Changelog Enforcement

12. 添加更新日志强制检查

Optionally require CHANGELOG updates for user-facing changes. This integrates with the
update-changelog
skill.
可选要求用户面向用户的变更必须更新CHANGELOG,该能力与
update-changelog
skill集成。

Basic Changelog Check

基础更新日志检查

yaml
  # Require CHANGELOG update for feat/fix commits
  - repo: local
    hooks:
      - id: changelog-check
        name: changelog check
        language: system
        entry: bash -c '
          commit_msg=$(cat "$1");
          if echo "$commit_msg" | grep -qE "^(feat|fix)(\(.+\))?!?:"; then
            if ! git diff --cached --name-only | grep -q "CHANGELOG"; then
              echo "ERROR: feat/fix commits require CHANGELOG update";
              echo "       Add entry or use --no-verify to skip";
              exit 1;
            fi;
          fi
        '
        args: [.git/COMMIT_EDITMSG]
        stages: [commit-msg]
        pass_filenames: false
yaml
  # Require CHANGELOG update for feat/fix commits
  - repo: local
    hooks:
      - id: changelog-check
        name: changelog check
        language: system
        entry: bash -c '
          commit_msg=$(cat "$1");
          if echo "$commit_msg" | grep -qE "^(feat|fix)(\(.+\))?!?:"; then
            if ! git diff --cached --name-only | grep -q "CHANGELOG"; then
              echo "ERROR: feat/fix commits require CHANGELOG update";
              echo "       Add entry or use --no-verify to skip";
              exit 1;
            fi;
          fi
        '
        args: [.git/COMMIT_EDITMSG]
        stages: [commit-msg]
        pass_filenames: false

Changelog with Breaking Change Detection

破坏性变更更新日志检查

yaml
  # Require CHANGELOG for breaking changes
  - repo: local
    hooks:
      - id: changelog-breaking
        name: changelog (breaking changes)
        language: system
        entry: bash -c '
          commit_msg=$(cat "$1");
          if echo "$commit_msg" | grep -qE "^.+!:" || echo "$commit_msg" | grep -q "BREAKING CHANGE:"; then
            if ! git diff --cached --name-only | grep -q "CHANGELOG"; then
              echo "ERROR: Breaking changes require CHANGELOG update";
              exit 1;
            fi;
          fi
        '
        args: [.git/COMMIT_EDITMSG]
        stages: [commit-msg]
        pass_filenames: false
yaml
  # Require CHANGELOG for breaking changes
  - repo: local
    hooks:
      - id: changelog-breaking
        name: changelog (breaking changes)
        language: system
        entry: bash -c '
          commit_msg=$(cat "$1");
          if echo "$commit_msg" | grep -qE "^.+!:" || echo "$commit_msg" | grep -q "BREAKING CHANGE:"; then
            if ! git diff --cached --name-only | grep -q "CHANGELOG"; then
              echo "ERROR: Breaking changes require CHANGELOG update";
              exit 1;
            fi;
          fi
        '
        args: [.git/COMMIT_EDITMSG]
        stages: [commit-msg]
        pass_filenames: false

Changelog Hook Options

更新日志hook选项

ModeWhen RequiredUse Case
feat/fix only
feat:
or
fix:
commits
Standard projects
Breaking changes
!:
or
BREAKING CHANGE:
Critical changes only
All user-facing`featfix
Tip: Allow bypass with
--no-verify
for WIP commits, but enforce in CI.
模式触发条件适用场景
仅feat/fix
feat:
fix:
提交
标准项目
仅破坏性变更
!:
BREAKING CHANGE:
仅针对重大变更
所有面向用户变更`featfix
提示: 允许WIP提交使用
--no-verify
绕过检查,但要在CI中强制执行该规则。

13. Add Static Analysis Hooks

13. 添加静态分析hook

These hooks catch issues that linters and formatters miss: typos, SQL problems, and dependency bloat.
这些hook可以发现代码检查和格式化工具遗漏的问题:拼写错误、SQL问题、依赖冗余。

Spell Checking (
codespell
)

拼写检查(
codespell

Catches typos in comments, docstrings, and string literals. Fast and catches embarrassing mistakes that linters miss.
yaml
  # Spell checking for code and docs
  - repo: https://github.com/codespell-project/codespell
    rev: v2.3.0
    hooks:
      - id: codespell
        args: [--skip="*.lock,*.min.js,*.min.css,*.snap"]
Why it's valuable: Agents often introduce typos in comments and documentation. This catches them immediately.
发现注释、文档字符串、字符串字面量中的拼写错误,运行速度快,可以发现代码检查工具遗漏的低级错误。
yaml
  # Spell checking for code and docs
  - repo: https://github.com/codespell-project/codespell
    rev: v2.3.0
    hooks:
      - id: codespell
        args: [--skip="*.lock,*.min.js,*.min.css,*.snap"]
价值: AI生成的代码经常会在注释和文档中出现拼写错误,该工具可以即时发现这些问题。

SQL Linting (
sqlfluff
)

SQL检查(
sqlfluff

For projects with SQL files, migrations, or raw SQL. Catches syntax errors, inconsistent formatting, and some injection-prone patterns.
yaml
  # SQL linting and formatting
  - repo: https://github.com/sqlfluff/sqlfluff
    rev: 3.2.5
    hooks:
      - id: sqlfluff-lint
        args: [--dialect, "ansi"]
      - id: sqlfluff-fix
        args: [--dialect, "ansi"]
When to add: Only if the project has
.sql
files or migration directories. If you use an ORM (Prisma, Diesel, SQLAlchemy), SQL injection is largely prevented at the ORM level.
适用于包含SQL文件、迁移文件或原生SQL的项目,可以发现语法错误、格式不一致和部分注入风险代码。
yaml
  # SQL linting and formatting
  - repo: https://github.com/sqlfluff/sqlfluff
    rev: 3.2.5
    hooks:
      - id: sqlfluff-lint
        args: [--dialect, "ansi"]
      - id: sqlfluff-fix
        args: [--dialect, "ansi"]
添加时机: 仅当项目包含
.sql
文件或迁移目录时添加。如果你使用ORM(Prisma、Diesel、SQLAlchemy),ORM层面已经基本避免了SQL注入风险。

Unused Dependencies (
depcheck
)

未使用依赖检查(
depcheck

For Node.js projects. Catches dependencies declared in
package.json
but never imported.
yaml
  # Check for unused dependencies
  - repo: local
    hooks:
      - id: depcheck
        name: depcheck
        language: system
        entry: npx depcheck --ignores="@types/*,eslint-config-*"
        pass_filenames: false
        files: package\.json$
Why it's valuable: Agents often add dependencies while experimenting but may not clean up. This catches unused deps before they accumulate.
适用于Node.js项目,可以发现
package.json
中声明但从未导入的依赖。
yaml
  # Check for unused dependencies
  - repo: local
    hooks:
      - id: depcheck
        name: depcheck
        language: system
        entry: npx depcheck --ignores="@types/*,eslint-config-*"
        pass_filenames: false
        files: package\.json$
价值: AI在实验功能时经常会添加依赖但忘记清理,该工具可以在冗余依赖累积前发现问题。

Static Analysis Hook Summary

静态分析hook汇总

HookPurposeSpeedWhen to Add
codespell
Typos in comments/docsFastAll projects
sqlfluff
SQL syntax and formattingFastProjects with SQL files
depcheck
Unused Node.js dependenciesMediumNode.js projects
Hook用途速度添加时机
codespell
注释/文档拼写检查所有项目
sqlfluff
SQL语法和格式化检查包含SQL文件的项目
depcheck
未使用的Node.js依赖检查Node.js项目

14. Additional Maintainability Hooks (Optional)

14. 额外可维护性hook(可选)

The core configuration already includes many essential hooks. Consider these additional hooks based on your project's specific needs:
HookPurposeWhen to Add
check-xml
Validate XML syntaxAny XML files
check-symlinks
Ensure symlinks point to real filesProjects with symlinks
destroyed-symlinks
Detect accidentally destroyed symlinksProjects with symlinks
check-executables-have-shebangs
Ensure executables have proper shebangShell scripts
check-shebang-scripts-are-executable
Ensure scripts with shebang are executableShell scripts
check-ast
Validate Python syntaxPython projects
debug-statements
Prevent committing debug breakpointsPython projects
double-quote-string-fixer
Enforce double quotes in PythonPython projects
commitlint
Enforce conventional commit format (alternative)If conventional-pre-commit doesn't work
ripsecrets
Alternative to gitleaks for secretsAll projects
Note: The following hooks are already included in the core configuration:
  • check-json
    ,
    check-yaml
    ,
    check-toml
    — Syntax validation
  • mixed-line-ending
    ,
    fix-byte-order-marker
    — Line ending/encoding consistency
  • forbid-new-submodules
    — Prevent accidental submodules
  • detect-private-key
    — Basic secret detection
  • no-commit-to-branch
    — Protect main/master branches
For comprehensive secret scanning, uncomment the
gitleaks
hook in the core configuration.
核心配置已经包含了很多必要的hook,可以根据项目的具体需求考虑添加以下额外hook
Hook用途添加时机
check-xml
验证XML语法包含XML文件的项目
check-symlinks
确保软链接指向真实文件包含软链接的项目
destroyed-symlinks
检测意外损坏的软链接包含软链接的项目
check-executables-have-shebangs
确保可执行文件有正确的shebang包含Shell脚本的项目
check-shebang-scripts-are-executable
确保带shebang的脚本有可执行权限包含Shell脚本的项目
check-ast
验证Python语法Python项目
debug-statements
防止提交调试断点Python项目
double-quote-string-fixer
强制Python使用双引号Python项目
commitlint
强制约定式提交规范(替代方案)当conventional-pre-commit不可用时
ripsecrets
gitleaks的替代密钥扫描工具所有项目
注意: 以下hook已经包含在核心配置中:
  • check-json
    check-yaml
    check-toml
    — 语法验证
  • mixed-line-ending
    fix-byte-order-marker
    — 行尾/编码一致性检查
  • forbid-new-submodules
    — 防止意外添加子模块
  • detect-private-key
    — 基础密钥检测
  • no-commit-to-branch
    — 保护main/master分支
如需全面的密钥扫描,取消核心配置中
gitleaks
hook的注释即可。

15. Optimize Hook Performance

15. 优化hook性能

Slow hooks kill developer productivity. Apply these optimizations to keep pre-commit under 5 seconds.
过慢的hook会降低开发者生产效率,按照以下优化方案可以将pre-commit运行时间控制在5秒以内。

Use
fail_fast
for Critical Hooks

关键hook使用
fail_fast

Stop early on critical failures:
yaml
repos:
  - repo: https://github.com/compilerla/conventional-pre-commit
    rev: v4.0.0
    hooks:
      - id: conventional-pre-commit
        stages: [commit-msg]
        fail_fast: true  # Stop immediately on bad commit message
遇到关键失败时提前停止:
yaml
repos:
  - repo: https://github.com/compilerla/conventional-pre-commit
    rev: v4.0.0
    hooks:
      - id: conventional-pre-commit
        stages: [commit-msg]
        fail_fast: true  # 提交信息不符合规范时直接停止

Scope Hooks to Changed Files

限制hook仅对变更文件运行

Only run hooks on relevant files:
yaml
  - repo: local
    hooks:
      - id: cargo-clippy
        name: cargo clippy
        language: system
        entry: cargo clippy -- -D warnings
        pass_filenames: false
        files: \.rs$  # Only run when Rust files change
仅在相关文件变更时运行对应hook:
yaml
  - repo: local
    hooks:
      - id: cargo-clippy
        name: cargo clippy
        language: system
        entry: cargo clippy -- -D warnings
        pass_filenames: false
        files: \.rs$  # 仅当Rust文件变更时运行

Use
types_or
for Multiple File Types

多文件类型使用
types_or

More efficient than regex
files:
:
yaml
  - repo: local
    hooks:
      - id: lizard
        types_or: [python, rust, javascript, typescript]  # Faster than regex
比正则
files:
匹配效率更高:
yaml
  - repo: local
    hooks:
      - id: lizard
        types_or: [python, rust, javascript, typescript]  # 比正则匹配更快

Cache Expensive Operations

缓存耗时操作

For hooks that download dependencies, use environment caching:
yaml
  # ESLint with cached dependencies
  - repo: https://github.com/pre-commit/mirrors-eslint
    rev: v8.57.1
    hooks:
      - id: eslint
        additional_dependencies:
          - eslint@8.57.1
        args: ["--cache", "--cache-location", ".eslintcache"]
对于需要下载依赖的hook,使用环境缓存:
yaml
  # ESLint with cached dependencies
  - repo: https://github.com/pre-commit/mirrors-eslint
    rev: v8.57.1
    hooks:
      - id: eslint
        additional_dependencies:
          - eslint@8.57.1
        args: ["--cache", "--cache-location", ".eslintcache"]

Parallel Execution

并行执行

Pre-commit runs hooks in parallel by default. To control concurrency:
yaml
undefined
pre-commit默认并行运行hook,可通过以下方式控制并发数:
yaml
undefined

In .pre-commit-config.yaml (top level)

在.pre-commit-config.yaml顶层配置

default_language_version: python: python3.12
default_language_version: python: python3.12

Limit parallel hooks (useful for resource-intensive tools)

限制并行hook数量(适用于资源消耗高的工具)

pre-commit run --config .pre-commit-config.yaml --all-files

pre-commit run --config .pre-commit-config.yaml --all-files


Or run manually with parallelism:

```bash
pre-commit run --all-files --show-diff-on-failure

或者手动运行时指定并行度:

```bash
pre-commit run --all-files --show-diff-on-failure

Skip Slow Hooks Locally

本地跳过慢速hook

For development, skip slow hooks but enforce in CI:
yaml
  # Slow hook example — only run manually
  - repo: local
    hooks:
      - id: slow-check
        name: slow check
        language: system
        entry: ./scripts/slow-check.sh
        stages: [manual]  # Only run with --hook-stage manual
Then in CI:
bash
pre-commit run --all-files --hook-stage manual
开发阶段可以跳过慢速hook,但在CI中强制执行:
yaml
  # 慢hook示例 — 仅手动运行
  - repo: local
    hooks:
      - id: slow-check
        name: slow check
        language: system
        entry: ./scripts/slow-check.sh
        stages: [manual]  # 仅在指定--hook-stage manual时运行
在CI中运行时:
bash
pre-commit run --all-files --hook-stage manual

Performance Benchmarks

性能基准

Hook TypeTarget TimeOptimization
Formatting< 1sUse
--check
mode
Linting< 3sScope to changed files
Type checking< 5sIncremental mode
Testing< 10sFast tests only
Hook类型目标运行时间优化手段
格式化< 1s使用
--check
模式
代码检查< 3s仅针对变更文件运行
类型检查< 5s使用增量模式
测试< 10s仅运行快速测试

Example: Full Multi-Language Configuration

示例:完整多语言配置

Here's a complete example for a project using Rust + TypeScript (like Lexi):
yaml
repos:
  # Conventional commit message format
  - repo: https://github.com/compilerla/conventional-pre-commit
    rev: v4.0.0
    hooks:
      - id: conventional-pre-commit
        stages: [commit-msg]
        fail_fast: true

  # General file hygiene and syntax validation
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v5.0.0
    hooks:
      - id: trailing-whitespace
      - id: end-of-file-fixer
      - id: check-merge-conflict
      - id: check-added-large-files
        args: ["--maxkb=500"]
      - id: check-case-conflict
      - id: detect-private-key
      - id: check-executables-have-shebangs
      - id: check-shebang-scripts-are-executable
      - id: check-json
      - id: check-yaml
      - id: check-toml
      - id: mixed-line-ending
      - id: fix-byte-order-marker
      - id: forbid-new-submodules

  # Secret detection (comprehensive scanning)
  - repo: https://github.com/gitleaks/gitleaks
    rev: v8.23.3
    hooks:
      - id: gitleaks

  # Spell checking
  - repo: https://github.com/codespell-project/codespell
    rev: v2.3.0
    hooks:
      - id: codespell
        args: [--skip="*.lock,*.min.js,*.min.css"]

  # Protect main/master branches
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v5.0.0
    hooks:
      - id: no-commit-to-branch
        args: [--branch, main, --branch, master]

  # Rust — formatting, linting
  - repo: local
    hooks:
      - id: cargo-fmt
        name: cargo fmt
        language: system
        entry: cargo fmt --manifest-path api/Cargo.toml -- --check
        pass_filenames: false
        types: [rust]

      - id: cargo-clippy
        name: cargo clippy
        language: system
        entry: cargo clippy --manifest-path api/Cargo.toml -- -D warnings
        pass_filenames: false
        types: [rust]

  # Cyclomatic complexity
  - repo: local
    hooks:
      - id: lizard
        name: lizard (cyclomatic complexity)
        language: system
        entry: lizard -C 15 -w -x "*/tests/*" -x "*/migrations/*" -x "*/node_modules/*" -x "*/target/*" -x "*/dist/*"
        pass_filenames: false
        types_or: [rust, ts, tsx]

  # TypeScript — type checking
  - repo: local
    hooks:
      - id: tsc
        name: tsc
        language: system
        entry: bash -c 'cd mobile && npx tsc --noEmit'
        pass_filenames: false
        types_or: [ts, tsx]

  # TypeScript — fast tests
  - repo: local
    hooks:
      - id: jest-fast
        name: jest (fast tests)
        language: system
        entry: bash -c 'cd mobile && npx jest --testPathPattern="^(?!.*\.slow\.)" --passWithNoTests'
        pass_filenames: false
        types_or: [ts, tsx]

  # Changelog enforcement for feat/fix commits
  - repo: local
    hooks:
      - id: changelog-check
        name: changelog check
        language: system
        entry: bash -c '
          commit_msg=$(cat "$1");
          if echo "$commit_msg" | grep -qE "^(feat|fix)(\(.+\))?!?:"; then
            if ! git diff --cached --name-only | grep -q "CHANGELOG"; then
              echo "ERROR: feat/fix commits require CHANGELOG update";
              exit 1;
            fi;
          fi
        '
        args: [.git/COMMIT_EDITMSG]
        stages: [commit-msg]
        pass_filenames: false

ci:
  autofix_commit_msg: |
    [pre-commit.ci] auto fixes from pre-commit.com hooks
  autofix_prs: true
  autoupdate_schedule: weekly
以下是Rust + TypeScript项目的完整配置示例(类似Lexi项目):
yaml
repos:
  # Conventional commit message format
  - repo: https://github.com/compilerla/conventional-pre-commit
    rev: v4.0.0
    hooks:
      - id: conventional-pre-commit
        stages: [commit-msg]
        fail_fast: true

  # General file hygiene and syntax validation
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v5.0.0
    hooks:
      - id: trailing-whitespace
      - id: end-of-file-fixer
      - id: check-merge-conflict
      - id: check-added-large-files
        args: ["--maxkb=500"]
      - id: check-case-conflict
      - id: detect-private-key
      - id: check-executables-have-shebangs
      - id: check-shebang-scripts-are-executable
      - id: check-json
      - id: check-yaml
      - id: check-toml
      - id: mixed-line-ending
      - id: fix-byte-order-marker
      - id: forbid-new-submodules

  # Secret detection (comprehensive scanning)
  - repo: https://github.com/gitleaks/gitleaks
    rev: v8.23.3
    hooks:
      - id: gitleaks

  # Spell checking
  - repo: https://github.com/codespell-project/codespell
    rev: v2.3.0
    hooks:
      - id: codespell
        args: [--skip="*.lock,*.min.js,*.min.css"]

  # Protect main/master branches
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v5.0.0
    hooks:
      - id: no-commit-to-branch
        args: [--branch, main, --branch, master]

  # Rust — formatting, linting
  - repo: local
    hooks:
      - id: cargo-fmt
        name: cargo fmt
        language: system
        entry: cargo fmt --manifest-path api/Cargo.toml -- --check
        pass_filenames: false
        types: [rust]

      - id: cargo-clippy
        name: cargo clippy
        language: system
        entry: cargo clippy --manifest-path api/Cargo.toml -- -D warnings
        pass_filenames: false
        types: [rust]

  # Cyclomatic complexity
  - repo: local
    hooks:
      - id: lizard
        name: lizard (cyclomatic complexity)
        language: system
        entry: lizard -C 15 -w -x "*/tests/*" -x "*/migrations/*" -x "*/node_modules/*" -x "*/target/*" -x "*/dist/*"
        pass_filenames: false
        types_or: [rust, ts, tsx]

  # TypeScript — type checking
  - repo: local
    hooks:
      - id: tsc
        name: tsc
        language: system
        entry: bash -c 'cd mobile && npx tsc --noEmit'
        pass_filenames: false
        types_or: [ts, tsx]

  # TypeScript — fast tests
  - repo: local
    hooks:
      - id: jest-fast
        name: jest (fast tests)
        language: system
        entry: bash -c 'cd mobile && npx jest --testPathPattern="^(?!.*\.slow\.)" --passWithNoTests'
        pass_filenames: false
        types_or: [ts, tsx]

  # Changelog enforcement for feat/fix commits
  - repo: local
    hooks:
      - id: changelog-check
        name: changelog check
        language: system
        entry: bash -c '
          commit_msg=$(cat "$1");
          if echo "$commit_msg" | grep -qE "^(feat|fix)(\(.+\))?!?:"; then
            if ! git diff --cached --name-only | grep -q "CHANGELOG"; then
              echo "ERROR: feat/fix commits require CHANGELOG update";
              exit 1;
            fi;
          fi
        '
        args: [.git/COMMIT_EDITMSG]
        stages: [commit-msg]
        pass_filenames: false

ci:
  autofix_commit_msg: |
    [pre-commit.ci] auto fixes from pre-commit.com hooks
  autofix_prs: true
  autoupdate_schedule: weekly

Hook Reference Quick Guide

Hook参考速查

Language-Specific Hooks

语言专属hook

LanguageFormatterLinterComplexityType CheckTesting
Rust
cargo fmt
cargo clippy
lizardN/A
cargo test
TypeScript
prettier
eslint
lizard
tsc --noEmit
jest
Python
ruff format
ruff
lizard
mypy
pytest
Go
gofmt
golangci-lint
lizard
go vet
go test
Shell
shfmt
shellcheck
N/AN/AN/A
Markdown
markdownlint --fix
markdownlint
N/AN/AN/A
JSON/YAML
prettier
check-json/yaml
N/AN/AN/A
编程语言格式化工具代码检查工具复杂度检查类型检查测试工具
Rust
cargo fmt
cargo clippy
lizard
cargo test
TypeScript
prettier
eslint
lizard
tsc --noEmit
jest
Python
ruff format
ruff
lizard
mypy
pytest
Go
gofmt
golangci-lint
lizard
go vet
go test
Shell
shfmt
shellcheck
Markdown
markdownlint --fix
markdownlint
JSON/YAML
prettier
check-json/yaml

Cross-Cutting Hooks

通用hook

HookPurposeWhen to Use
codespell
Typos in comments/docsAll projects
sqlfluff
SQL syntax and formattingProjects with SQL files
depcheck
Unused Node.js dependenciesNode.js projects
lizard
Cyclomatic complexityAll projects
gitleaks
Secret scanningAll projects
Note: Security checks (dependency audits, SAST, license compliance) belong in CI, not pre-commit. See section 6 for secret scanning which runs in pre-commit.
Hook用途适用场景
codespell
注释/文档拼写检查所有项目
sqlfluff
SQL语法和格式化检查包含SQL文件的项目
depcheck
未使用的Node.js依赖检查Node.js项目
lizard
圈复杂度检查所有项目
gitleaks
密钥扫描所有项目
注意: 安全检查(依赖审计、SAST、许可证合规)适合放在CI中运行,不要放在pre-commit里。密钥扫描属于快速检查,可在pre-commit中运行,详见第6节。

Best Practices

最佳实践

  1. Local hooks vs. Repository hooks: Use local hooks (
    language: system
    ) for tools already in the project's toolchain (e.g.,
    cargo
    ,
    npm
    ,
    go
    ). Use repository hooks for standalone tools.
  2. Passing filenames: Set
    pass_filenames: false
    when the tool needs to run at project level (e.g.,
    cargo clippy
    ,
    tsc
    ).
  3. Complexity threshold: Start with
    -C 15
    and adjust based on your codebase. High-complexity functions are harder to test and maintain.
  4. Exclusions: Always exclude generated code, dependencies, and test files from complexity checks.
  5. CI integration: Add the
    ci:
    section to enable pre-commit.ci or similar services for automated fixes.
  6. Keep hooks under 5 seconds: Pre-commit runs on every commit. Slow hooks break developer flow. Move slow checks (full test suite, dependency audits) to CI.
  7. Use
    fail_fast
    sparingly
    : Only for critical hooks like commit message format. Most hooks should run to completion to show all issues.
  8. Test before commit, not after: Run fast tests in pre-commit, full suite in CI. This catches regressions early without blocking commits.
  9. Security in layers: Secret scanning (fast) in pre-commit, dependency audits and SAST (slow) in CI.
  1. 本地hook vs 仓库hook:对于项目工具链中已有的工具(例如
    cargo
    npm
    go
    )使用本地hook(
    language: system
    ),独立工具使用仓库hook。
  2. 传递文件名:当工具需要在项目根目录运行时(例如
    cargo clippy
    tsc
    ),设置
    pass_filenames: false
  3. 复杂度阈值:初始设置为
    -C 15
    ,可根据代码库情况调整,高复杂度函数更难测试和维护。
  4. 排除规则:复杂度检查始终要排除生成代码、依赖和测试文件。
  5. CI集成:添加
    ci:
    配置段启用pre-commit.ci或类似服务实现自动修复。
  6. hook总运行时间控制在5秒以内:每次提交都会运行pre-commit,过慢的hook会打断开发流程,将慢速检查(完整测试套件、依赖审计)迁移到CI中。
  7. 谨慎使用
    fail_fast
    :仅对提交信息格式等关键hook使用,大部分hook应该运行完全程,展示所有问题。
  8. 提交前测试而非提交后测试:pre-commit中运行快速测试,完整测试套件在CI中运行,既可以尽早发现回归,也不会阻塞提交。
  9. 分层安全策略:pre-commit中运行快速的密钥扫描,CI中运行慢速的依赖审计和SAST检查。

Troubleshooting

故障排查

IssueSolution
"lizard: command not found"Install with
uv tool install lizard
Conventional commit hook not firingEnsure
stages: [commit-msg]
is set and run
pre-commit install --hook-type commit-msg
Hook too slowAdd
files:
filter to only run on changed relevant files
Merge conflictsRun
pre-commit run check-merge-conflict --all-files
Warnings treated as errorsAdd <code>|| true</code> to the entry for warnings-only hooks
Tests fail on unrelated changesUse
files:
to scope test hooks to changed directories
Changelog check blocking WIPUse
git commit --no-verify
to bypass
Coverage threshold too strictLower threshold or exclude specific files with
--cov-config
问题解决方案
"lizard: command not found"执行
uv tool install lizard
安装
约定式提交hook不触发确保配置了
stages: [commit-msg]
,并执行
pre-commit install --hook-type commit-msg
hook运行过慢添加
files:
过滤规则,仅在相关文件变更时运行
合并冲突执行
pre-commit run check-merge-conflict --all-files
检查
警告被当作错误处理对于仅警告的hook,在entry末尾添加<code>|| true</code>
无关变更导致测试失败使用
files:
将测试hook的运行范围限定到变更目录
变更日志检查阻塞WIP提交使用
git commit --no-verify
绕过
覆盖率阈值过于严格降低阈值,或者使用
--cov-config
排除指定文件