626 pre-commit 代码质量钩子
一句话概述:pre-commit 是 Git 钩子管理工具,在你提交代码前自动运行检查(格式化、语法检查、安全扫描),把问题挡在代码进入仓库之前,是团队代码质量的"守门员"。
核心知识点速查表
| 知识点 | 说明 |
|---|
| 最新版本 | pre-commit v6.0.0+(2026年) |
| 核心功能 | Git commit 前自动运行代码检查和格式化 |
| 支持语言 | Python、JavaScript、Go、Rust、Shell 等全语言 |
| 配置文件 | .pre-commit-config.yaml |
| 2026趋势 | Ruff 替代 Black/Flake8/isort,成为 Python 检查主流 |
| 适用场景 | 个人项目、团队协作、CI/CD |
一、安装配置
# 安装 pre-commit
pip install pre-commit # Python 安装
# 或
brew install pre-commit # macOS
# 或
conda install -c conda-forge pre-commit # Conda
# 验证安装
pre-commit --version # 输出:pre-commit 6.x.x
1.1 初始化项目
# 在 Git 项目根目录下
pre-commit install # 安装 Git 钩子(在 .git/hooks/ 下创建 pre-commit)
# 白话:安装后,每次 git commit 会自动运行检查
# 可选:安装其他阶段的钩子
pre-commit install --hook-type commit-msg # commit 消息检查
pre-commit install --hook-type pre-push # push 前检查
二、基本使用
2.1 配置文件
# .pre-commit-config.yaml(项目根目录)
repos:
# ---- 通用检查(所有项目都应该有) ----
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0 # 使用的版本(固定版本号)
hooks:
- id: trailing-whitespace # 删除行尾空格
- id: end-of-file-fixer # 确保文件以换行符结尾
- id: check-yaml # 检查 YAML 语法
- id: check-json # 检查 JSON 语法
- id: check-toml # 检查 TOML 语法
- id: check-added-large-files # 防止提交大文件(默认 > 500KB)
args: ['--maxkb=1000'] # 自定义阈值:1MB
- id: check-merge-conflict # 检查是否遗留合并冲突标记
- id: detect-private-key # 检测是否意外提交私钥
- id: check-case-conflict # 检查文件名大小写冲突
# ---- Python 代码检查(Ruff:一个工具替代 Black + Flake8 + isort) ----
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.11.0
hooks:
- id: ruff # 代码检查(替代 Flake8 + isort)
args: [--fix] # 自动修复可修复的问题
- id: ruff-format # 代码格式化(替代 Black)
# 白话:Ruff 用 Rust 写的,比 Black+Flake8 快 100 倍
# ---- 安全检查(检测密钥泄露) ----
- repo: https://github.com/gitleaks/gitleaks
rev: v8.24.0
hooks:
- id: gitleaks # 扫描代码中的密钥、密码、Token
# 白话:防止你不小心把 API Key 提交到 Git
2.2 常用命令
# 手动运行(不需要 commit)
pre-commit run --all-files # 对所有文件运行检查
pre-commit run --files src/main.py # 只检查指定文件
pre-commit run ruff --all-files # 只运行 ruff 检查
# 更新钩子版本
pre-commit autoupdate # 自动更新所有钩子到最新版本
# 跳过钩子(紧急情况)
git commit --no-verify -m "紧急修复" # 跳过所有钩子(慎用!)
# 或
SKIP=ruff git commit -m "跳过ruff" # 只跳过特定钩子
# 清理缓存
pre-commit clean # 清理钩子环境缓存
pre-commit gc # 垃圾回收
三、各语言配置模板
3.1 Python 项目(推荐配置)
# .pre-commit-config.yaml
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-added-large-files
- id: detect-private-key
# Ruff(一站式 Python 代码质量工具)
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.11.0
hooks:
- id: ruff
args: [--fix, --select, "E,F,I,UP,N,B"] # 启用多种规则
# E=pycodestyle, F=pyflakes, I=isort, UP=pyupgrade, N=pep8-naming, B=bugbear
- id: ruff-format
# 类型检查
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.15.0
hooks:
- id: mypy # Python 静态类型检查
additional_dependencies: # mypy 需要的额外依赖
- types-requests
# 安全检查
- repo: https://github.com/gitleaks/gitleaks
rev: v8.24.0
hooks:
- id: gitleaks
3.2 JavaScript/TypeScript 项目
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-json
- id: check-added-large-files
# ESLint(JS/TS 代码检查)
- repo: https://github.com/pre-commit/mirrors-eslint
rev: v9.20.0
hooks:
- id: eslint
files: \.[jt]sx?$ # 匹配 .js .jsx .ts .tsx 文件
types: [file]
additional_dependencies:
- eslint@9
- typescript
# Prettier(格式化)
- repo: https://github.com/pre-commit/mirrors-prettier
rev: v4.0.0
hooks:
- id: prettier
types_or: [javascript, typescript, json, yaml, markdown, css]
3.3 通用项目(多语言)
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-json
- id: check-toml
- id: check-added-large-files
- id: check-merge-conflict
- id: detect-private-key
- id: mixed-line-ending # 统一换行符
args: ['--fix=lf'] # 统一为 LF(Unix 风格)
# Shell 脚本检查
- repo: https://github.com/shellcheck-py/shellcheck-py
rev: v0.10.0
hooks:
- id: shellcheck # Shell 脚本静态分析
# Markdown 检查
- repo: https://github.com/igorshubovych/markdownlint-cli
rev: v0.44.0
hooks:
- id: markdownlint # Markdown 格式检查
args: ['--fix'] # 自动修复
# Dockerfile 检查
- repo: https://github.com/hadolint/hadolint
rev: v2.12.0
hooks:
- id: hadolint # Dockerfile 最佳实践检查
# 密钥泄露检查
- repo: https://github.com/gitleaks/gitleaks
rev: v8.24.0
hooks:
- id: gitleaks
四、高级用法
4.1 自定义本地钩子
repos:
# 本地自定义钩子(不需要从远程仓库拉取)
- repo: local
hooks:
- id: pytest-check # 自定义 ID
name: 运行 pytest 测试 # 显示名称
entry: pytest tests/ -x # 要执行的命令
language: system # 使用系统已安装的工具
pass_filenames: false # 不传文件名给命令
always_run: true # 每次 commit 都运行
stages: [pre-commit] # 在 pre-commit 阶段运行
- id: check-todo
name: 检查 TODO 注释
entry: bash -c 'grep -rn "TODO\|FIXME\|HACK" --include="*.py" src/ && exit 1 || exit 0'
language: system
pass_filenames: false
4.2 Commit 消息检查
repos:
# commitlint:检查 commit 消息格式
- repo: https://github.com/alessandrojcm/commitlint-pre-commit-hook
rev: v9.18.0
hooks:
- id: commitlint
stages: [commit-msg] # 在 commit-msg 阶段运行
additional_dependencies:
- '@commitlint/config-conventional'
# 白话:强制 commit 消息格式为 "feat: xxx" / "fix: xxx" 等
# 安装 commit-msg 钩子
pre-commit install --hook-type commit-msg
4.3 CI 中使用 pre-commit
# .github/workflows/pre-commit.yml
name: pre-commit 检查
on: [push, pull_request]
jobs:
pre-commit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- uses: pre-commit/action@v3.0.1 # 官方 GitHub Action
# 白话:在 CI 中也运行 pre-commit,防止有人跳过本地钩子
4.4 排除文件和目录
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.11.0
hooks:
- id: ruff
exclude: | # 排除的文件/目录(正则表达式)
(?x)^(
migrations/.*| # 排除数据库迁移文件
vendor/.*| # 排除第三方代码
.*_generated\.py # 排除自动生成的文件
)$
args: [--fix]
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: trailing-whitespace
exclude: \.md$ # Markdown 文件不删尾部空格
五、常见报错与解决
| 问题 | 解决 |
|---|
hook failed 后提交失败 | 查看输出,修复问题后重新 git add 和 git commit |
ruff 自动修复了文件 | 文件已被修改,git add 重新暂存后再提交 |
| 钩子运行太慢 | 用 Ruff 替代 Black+Flake8(快 100 倍);或减少 --all-files |
pre-commit install 没效果 | 检查是否在 Git 仓库根目录运行 |
| 版本冲突 | 运行 pre-commit autoupdate 更新到最新版 |
六、速查表
| 操作 | 命令 |
|---|
| 安装 | pip install pre-commit |
| 初始化钩子 | pre-commit install |
| 运行全部检查 | pre-commit run --all-files |
| 运行单个钩子 | pre-commit run 钩子ID --all-files |
| 更新钩子版本 | pre-commit autoupdate |
| 跳过钩子提交 | git commit --no-verify |
| 跳过特定钩子 | SKIP=钩子ID git commit |
| 清理缓存 | pre-commit clean |
| 安装消息钩子 | pre-commit install --hook-type commit-msg |
| CI 中运行 | uses: pre-commit/action@v3.0.1 |
七、同类工具对比
| 特性 | pre-commit | Husky (JS) | Lefthook | lint-staged |
|---|
| 语言 | Python | Node.js | Go | Node.js |
| 多语言支持 | 所有 | JS/TS为主 | 所有 | JS/TS为主 |
| 配置方式 | YAML | JSON/JS | YAML | JSON |
| 钩子生态 | 极丰富 | npm 生态 | 增长中 | 无(搭配用) |
| 性能 | 良好 | 良好 | 极快 | 良好 |
| 适合场景 | 通用 | Node项目 | 通用 | 搭配 Husky |
选型建议:Python 项目或多语言项目首选 pre-commit(生态最完善);纯 Node.js 项目可用 Husky + lint-staged;追求极速选 Lefthook。
参考资料:pre-commit 官方文档 | GitHub | 支持的 Hooks 列表