.pre-commit-config.yaml不生效的主因是未运行pre-commit install(而非install-hooks)导致钩子未写入.git/hooks/pre-commit;新增修复型钩子默认只检查暂存文件,需pre-commit run --all-files手动触发;default_stages缺失或language_version未显式指定也会导致跳过。

pre-commit 安装后 .pre-commit-config.yaml 不生效?检查钩子是否被跳过
常见现象是执行 git commit 后完全没触发任何检查,连 black 或 flake8 的提示都没有。根本原因通常是:钩子没正确安装,或安装时跳过了某些步骤。
- 必须在项目根目录下运行
pre-commit install(不是install-hooks);该命令会把钩子写入.git/hooks/pre-commit文件,缺这步就等于没接通 Git - 如果之前已提交过代码,而你新增了
trailing-whitespace这类修复型钩子,默认只检查「将要提交的文件」——它不会扫历史文件,也不会自动修,得手动跑pre-commit run --all-files - 检查
.pre-commit-config.yaml顶层是否有default_stages: [commit],否则部分钩子(如commit-msg类)可能不响应普通提交
用 pyproject.toml 管理依赖时,pre-commit 钩子仍报 ModuleNotFoundError?隔离环境没打通
pre-commit 默认为每个钩子创建独立虚拟环境,但它不会自动读取你项目里的 pyproject.toml 中定义的依赖或 Python 版本。如果你的钩子(比如 pylint)依赖特定库或解释器,容易失败。
- 在钩子配置里显式指定
python版本:用language_version: python3.11(而非system),确保和项目一致 - 若钩子需额外包(如
pylint要pylint-django),在对应钩子下加additional_dependencies字段,例如:additional_dependencies: ["pylint-django"]
- 避免用
language: system—— 它直接调系统 PATH 下的命令,不可复现,CI 极易挂
为什么 black 和 isort 冲突?顺序和配置必须对齐
二者都改 import 和格式,但 isort 默认不按 black 的行宽切分,black 又会重排 import 行,导致反复提交都过不了钩子。
- 让
isort兼容black:在.isort.cfg或pyproject.toml的[tool.isort]下加profile = "black" - 强制执行顺序:在
.pre-commit-config.yaml中,把isort放在black前面(钩子按列表顺序运行) - 别同时启用
black的--skip-string-normalization和isort的force_single_line_imports,它们会互相推翻格式结果
CI 上 pre-commit 失败但本地正常?缓存和版本漂移是主因
最典型的是 CI 报 check-yaml failed 或 end-of-file-fixer failed,而你本地 pre-commit run 没问题。这不是环境差异,是 pre-commit 自身行为导致的。
立即学习“Python免费学习笔记(深入)”;
- pre-commit 缓存钩子环境在
~/.cache/pre-commit/,CI 每次都是干净环境,所以首次运行会重新下载、构建——可能因网络或镜像源失败。可在 CI 前加pre-commit clean防旧缓存干扰 - 钩子版本写死:所有
rev:字段必须用具体 tag(如rev: v24.3.0),禁用rev: main或rev: master,否则某天上游更新破坏兼容性 - CI 使用的 Python 版本必须和
language_version严格一致,比如设了python3.11却在 CI 用python3.12,钩子环境构建会静默失败
真正麻烦的从来不是配不配得上,而是某次 pre-commit autoupdate 后没人看 rev 变了没、有没有破坏性变更、CI 日志里那行 “hook id xxx is not installed” 是不是被当警告忽略了。


















