pre-commit 是 Python 生态中管理 git hooks 的事实标准,但其性能瓶颈在现代开发流程中日益突出。prek 作为 Rust 重写的替代品,不仅实现了完全兼容,还通过三级并行化、共享工具链缓存和增量检查等机制,实现了 1.76 倍至 10 倍的性能提升。本文将从工程实现角度,拆解 prek 的核心优化策略,并给出可操作的参数与监控建议。
并行化架构:三级并行的工程实现
prek 的并行化并非简单的多线程处理,而是覆盖了从仓库克隆到钩子运行的全流程。其设计理念是将可并行的任务最大化,同时处理依赖冲突,确保正确性。
第一级并行是仓库克隆。在安装 hooks 时,prek 会并行克隆多个仓库(repos),而 pre-commit 通常是顺序执行。这一优化在仓库数量多时效果显著,例如 Apache Airflow 的配置包含数十个仓库,prek 的并行克隆可将安装时间从 187 秒降至 18 秒。
第二级并行是钩子安装。当多个 hooks 的依赖不冲突时,prek 会并行安装它们的环境与工具链。相比之下,pre-commit 为每个 hook 创建独立的虚拟环境,顺序安装依赖,导致安装时间线性增长。prek 通过共享工具链减少了重复安装,进一步缩短了时间。
第三级并行是钩子运行。prek 支持按优先级调度钩子运行,相同优先级的钩子可并发执行。这在多个独立检查(如 lint、format、type check)时尤为有效。pre-commit 则通常顺序运行钩子,或依赖外部并行配置。
工程参数方面,可通过 .pre-commit-config.yaml 中的 priority 字段调整钩子优先级,数值越小优先级越高。默认情况下,prek 会自动调度并发,但需注意依赖顺序的钩子不要设置相同优先级。
缓存策略:共享工具链与 uv 集成
prek 的缓存策略核心是 “共享工具链”。pre-commit 为每个 hook 维护独立的虚拟环境,不仅占用磁盘空间(约 1.6GB),还导致重复安装开销。prek 则复用工具链与环境,减少了约 50% 的磁盘占用(810MB vs 1.6GB)。
在实现上,prek 使用 uv 管理 Python 虚拟环境与依赖。uv 是用 Rust 编写的极速包管理器,其性能远高于 pip。prek 通过内置的 uv 集成,加速了依赖解析与安装过程。对于非 Python 工具(如 Node.js、Go、Rust),prek 也实现了共享安装,减少了重复下载。
缓存失效方面,prek 使用 prek clean 命令清除缓存,而 uv 缓存可通过 uv cache clean 管理。在 CI/CD 场景中,建议在安装前清理缓存以获得准确的冷启动时间。
增量检查:Git 感知的文件过滤
增量检查是提升开发体验的关键。prek 实现了 Git 感知的文件过滤,避免每次都扫描全部文件。
主要参数是 --last-commit,它仅运行上次提交更改的文件对应的 hooks。这在日常开发中非常实用,避免了全量扫描的延迟。另一个参数是 --directory,支持指定目录级增量检查,适用于 monorepo 工作流。
需要注意的是,增量检查依赖于 Git 历史,非 Git 工作流需手动指定文件列表。
性能数据汇总
以下数据来自官方 benchmark 与独立测试:
- 冷安装(Apache Airflow):prek 18.4s vs pre-commit 187s(10.17 倍)。
- 磁盘占用:prek 810MB vs pre-commit 1.6GB(50% 节省)。
- 运行时(check-toml,fast path):prek 77.1ms vs pre-commit 351.6ms(4.56 倍)。
- 运行时(无 fast path):prek 137.3ms vs pre-commit 397.6ms(2.9 倍)。
- 真实项目(vllm):冷运行 17s vs 55s(3.2 倍),暖缓存 7s vs 12s(1.7 倍)。
- 个人仓库(6 hooks):冷安装 22.8s vs 40.1s(1.76 倍),暖运行 26.3ms vs 176.7ms(6.72 倍)。
这些数据表明,prek 在安装与运行阶段均有显著提升,且提升幅度与项目规模正相关。
工程落地清单
监控指标:
- 安装时间:
hyperfine测量冷安装时间,关注 10 秒以上的项目。 - 运行时间:使用
--warmup 3 --runs 5测量暖运行时间,关注单次 commit 延迟。 - 缓存命中率:通过
prek list查看 hooks 状态,确认缓存是否生效。
迁移步骤:
- 安装 prek:
pip install prek或uv tool install prek。 - 运行
prek install --install-hooks,无需修改.pre-commit-config.yaml。 - 验证 hooks 运行正常,优先测试高频使用的 hooks。
- 监控性能数据,确认提升符合预期。
回滚方案:如遇兼容性问题,可通过 pip install pre-commit 回滚,并恢复 pre-commit install 原工作流。