pre-commitの代替ツールのprekを試してみた

に公開

はじめに

prekというpre-commitの高速なRust製の代替ツールがあることを知ったので試してみたいと思います。

https://github.com/j178/prek

何を試してみたか

自分にとって身近なプロジェクト構成で、どのくらい早くなるのかを確認したかったため、適当なPythonプロジェクトを作成し、prek公式のベンチマークと同じように、hyperfineを使って複数のシナリオで測定しました。

  • 初期インストール(install_hook)
  • フック実行(対象なし、全フック、特定フック)

全体環境

  • MacBook Air/Apple M3/16GB
  • mise: 2025.10.7 macos-arm64 (2025-10-10)
  • hyperfine: 1.19.0

miseとhyperfineはbrewで導入しています。
それ以外に使ったツールやバージョンはmiseやuvによって管理しています。

prekの導入(pre-commitも)

miseを使って環境を構築しました。

.mise.toml
[tools]
python = "3.14"
pre-commit = "4.3.0"
uv = "0.8.13"
prek = "0.2.5"
mise install

これでpre-commitとprekの両方が使える状態になります。

プロジェクトの設定

.pre-commit-config.yaml

pre-commitとprekで使用する設定ファイルをこのような形で準備しています。

.pre-commit-config.yaml
repos:
  # General pre-commit hooks
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v6.0.0
    hooks:
      - id: trailing-whitespace
        stages: [pre-commit, manual]
      - id: end-of-file-fixer
        stages: [pre-commit, manual]
      - id: check-yaml
        stages: [pre-commit, manual]
      - id: check-toml
        stages: [pre-commit, manual]
      - id: check-added-large-files
        args: [--maxkb=500]
        stages: [pre-commit, manual]
      - id: check-merge-conflict
        stages: [pre-commit, manual]
      - id: check-docstring-first
        stages: [pre-commit, manual]
        files: \.py$
      - id: debug-statements
        stages: [pre-commit, manual]
        files: \.py$
      - id: check-ast
        stages: [pre-commit, manual]
        files: \.py$

  - repo: https://github.com/astral-sh/ruff-pre-commit
    rev: v0.14.0
    hooks:
      - id: ruff
        args: [--fix]
        stages: [pre-commit, manual]
        files: \.py$
      - id: ruff-format
        stages: [pre-commit, manual]
        files: \.py$

  - repo: https://github.com/pre-commit/mirrors-mypy
    rev: v1.18.2
    hooks:
      - id: mypy
        stages: [pre-commit, manual]
        files: \.py$
        additional_dependencies: []

pyproject.toml

mypyとruffの設定を入れた適当なプロジェクトを作成し、下記のようなpyproject.tomlを配置します。

pyproject.toml
[project]
name = "prek-sandbox"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.14"
dependencies = []

[dependency-groups]
dev = [
    "mypy>=1.18.2",
    "ruff>=0.14.0",
]

[tool.ruff]
target-version = "py314"
line-length = 100

[tool.ruff.lint]
select = [
    "E",   # pycodestyle errors
    "W",   # pycodestyle warnings
    "F",   # pyflakes
    "I",   # isort
    "B",   # flake8-bugbear
    "C4",  # flake8-comprehensions
    "UP",  # pyupgrade
    "ANN", # flake8-annotations
]

[tool.mypy]
python_version = "3.14"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true
disallow_incomplete_defs = true
check_untyped_defs = true
no_implicit_optional = true
warn_redundant_casts = true
warn_unused_ignores = true
warn_no_return = true
strict_equality = true

ソースコードなど

mypyとruffが動くように適当にsrcディレクトリを作成し、Pythonファイルを作成します。
今回のお試してはコードの内容は関係ないので、全部生成AIに作成してもらいました。

$ tree src
src
├── api_client.py
├── data_processor.py
├── database.py
├── main.py
├── utils.py
└── validators.py

1 directory, 6 files

ベンチマーク結果

初期インストール(install-hooks)

Gitフックへの登録や環境セットアップを行うコマンドは、prek install-hookspre-commit install-hooksです。
下記を手動で3回実行して結果を確認します。

hyperfine \
    --prepare 'prek clean && pre-commit clean && uv cache clean' \
    --runs 1 \
    'prek install-hooks' \
    'pre-commit install-hooks'
実行回 prek pre-commit 倍率
1回目 3.449 s 8.580 s 2.49倍
2回目 2.603 s 8.579 s 3.30倍
3回目 3.577 s 8.633 s 2.41倍

初期セットアップ時も、prekが2.4〜3.3倍高速でした。

全フック実行(変更がなく全部スキップされる)

フックの実行はGitフックに登録してgit commitでも良いのですが、今回は測定なのでprek runpre-commit runコマンドを使って実行します。
まずはGitのStaged Changesにファイルがない状態での実行です。

hyperfine \
    --warmup 3 \
    --runs 10 \
    'prek run' \
    'pre-commit run'
コマンド 平均時間 範囲
prek run 91.1 ms ± 0.6 ms 90.4 ms … 92.4 ms
pre-commit run 314.6 ms ± 4.4 ms 310.9 ms … 326.6 ms

結果: prekが3.45倍高速

全フック実行(チェック対象あり)

次に、ファイルがStaged Changesに含まれる状態にして測定してみます。
正しくチェックされていることが確認できるように、Pythonの型チェックでruffとmypyでエラーがでるような状態で実行しています。

hyperfine \
    --warmup 3 \
    --ignore-failure \
    --runs 10 \
    'prek run' \
    'pre-commit run'
コマンド 平均時間 範囲
prek run 547.3 ms ± 69.8 ms 518.6 ms … 744.9 ms
pre-commit run 996.2 ms ± 68.6 ms 967.4 ms … 1190.6 ms

結果: prekが1.82倍高速

エラー処理や出力の生成を含む場合でも、大幅な高速化が確認できました。
実際にruffやmypyも動いているため、それらの実行時間のほうの割合が大きくなった結果だと考えられます。

特定フック実行(ruff)

続いて、ファイルがStaged Changesに含まれる状態で、ruffのフックだけが実行されるように指定して実行してみます。

hyperfine \
    --warmup 3 \
    --ignore-failure \
    --runs 10 \
    'prek run -a ruff' \
    'pre-commit run -a ruff'
コマンド 平均時間 範囲
prek run -a ruff 68.7 ms ± 5.1 ms 60.1 ms … 75.1 ms
pre-commit run -a ruff 263.6 ms ± 1.2 ms 261.8 ms … 266.3 ms

結果: prekが3.84倍高速

特定フック実行(check-toml)

同じく、ファイルがStaged Changesに含まれる状態で、check-tomlのフックだけが実行されるように指定して実行してみます。

hyperfine \
    --warmup 3 \
    --runs 10 \
    'prek run -a check-toml' \
    'pre-commit run -a check-toml'
コマンド 平均時間 範囲
prek run -a check-toml 54.4 ms ± 2.0 ms 53.0 ms … 59.3 ms
pre-commit run -a check-toml 276.6 ms ± 1.0 ms 275.4 ms … 277.9 ms

結果: prekが5.08倍高速

軽量なフックほど、起動オーバーヘッドの差が顕著に現れています。

prekならではの機能

prekには、pre-commitにはない便利な機能が多数実装されています。

フック一覧表示

$ prek list
.:trailing-whitespace
.:end-of-file-fixer
.:check-yaml
.:check-toml
.:check-added-large-files
.:check-merge-conflict
.:check-docstring-first
.:debug-statements
.:check-ast
.:ruff
.:ruff-format
.:mypy

pre-commitにはlistコマンドがなく、設定されているフックの概要を把握しやすくなっています。

ワークスペースモード

こちらはまだ試せていませんが、prekはワークスペースモードをサポートしており、モノレポ内の複数のサブプロジェクトをそれぞれの.pre-commit-config.yamlファイルで管理できます。pre-commitではsub-pre-commitという別のツールを使うことでしかできなかったので、公式にサポートされるのはありがたいです。

# ワークスペース全体で実行
$ prek run

# 特定のプロジェクトのみ実行
$ prek run project1 project2

感想

良かった点

  • 体感できる速度向上: 今回測定したシナリオでは1.82〜5.08倍の高速化が確認できました。特に軽量なフックほど高速化の恩恵が大きく、開発中の快適性が大幅に向上します
  • 完全互換性: 既存の.pre-commit-config.yamlをそのまま使えるため、移行コストがゼロでした
  • 豊富な独自機能: prek list--last-commit--directoryなど、pre-commitにはない便利そうな機能が多数追加されています
  • ワークスペースモード: モノレポでの利用を想定した機能があり、大規模プロジェクトでの活用が期待できます

注意点

  • まだアルファ版のため、本番利用には慎重な検証が必要です
  • 一部の言語がなかったり、サブコマンドが未実装です(TODO参照)

結論

小規模ですが、身近なプロジェクトでも速いことが確認できました。

  • 通常実行: 91.1 ms vs 314.6 ms(3.45倍高速)
  • 軽量フック: 50〜70 ms vs 260〜280 ms(約5倍高速)
  • 初期セットアップ: 2.6〜3.6秒 vs 8.6秒(約3倍高速)

開発中に何度も実行するpre-commitの時間が大幅に短縮されるためかなり嬉しい結果となりました。(チーム開発としてpre-commitは入れておくのが好きなんですけど、あまり体験としては好きではなかった。)
pre-commitからの移行も設定ファイルがそのまま使えて楽だったため、気軽に試せるのも良いところ。

期待して安定版のリリースを待ちたいと思います!

Discussion