コミット前にチェックしたい(pre-commit

$ pre-commit --version
pre-commit 3.8.0

$ pre-commit install
$ pre-commit run --all-files

pre-commitGit Hooksを使って、 コミット前などにコードのチェック作業などを自動化できるツールです。 設定ファイルは.pre-commit-config.yamlです。 Pythonで書かれていますが、いろいろなプログラミング言語やプロジェクトで使えるようになっています。

注釈

commitizenを有効にすると、自動で追加されます。

インストールしたい(pre-commit

  • pipでインストール

$ pip3 install pre-commit
$ pip3 install -U pre-commit
  • pipxでインストール

$ pipx install pre-commit
$ pipx upgrade pre-commit
  • poetryでインストール

$ poetry add pre-commit --group=dev
  • uvでインストール

$ uv tool install pre-commit
$ uv tool upgrade pre-commit

設定したい(.pre-commit-config.yaml

repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
  rev: v4.6.0  # 最新バージョンにする
  hooks:
  - id: trailing-whitespace
  - id: end-of-file-fixer
  - id: check-added-large-files
- repo: リポジトリ
  rev: バージョン
  hooks:
  - id: フック名

.pre-commit-config.yamlにフック情報を記述します。 設定できるフックはSupported Hooksで確認できます。

チェックしたい(run

$ pre-commit run --all-files

runコマンドでフックの確認ができます。 --all-filesオプションで、カレントディレクトリの下にあるすべてのファイルに対してチェックを実行します。 trailing-whitespaceend-of-file-fixerなどのフックを有効にしている場合、ファイルが自動で修正されます。

フックしたい

$ find .git/hooks -f type ! -name "*.sample" -perm u+x
.git/hooks/pre-commit

.git/hooks/で、現在有効になっているGit Hooksを確認できます。 *.sampleが付いていない実行ファイルが有効なフックです。

$ pre-commit install --hook-type フック名

--hook-type フック名オプションで、フックを追加できます。

$ pre-commit install --install-hooks --hook-type pre-commit --hook-type commit-msg

--install-hooksオプションで、複数のフックをまとめて追加できます。

# .pre-commit-config.yaml
default_install_hook_types:
  - pre-commit
  - commit-msg
  - pre-push

.pre-commit-config.yamlで有効にするフックを指定することもできます。

デフォルトはpre-commit(コミットの直前)です。 commit-msgpre-pushなど以下のGit Hooksもサポートされています。

Git Hook

タイミング

設定方法

commit-msg

コミットメッセージ作成の直後

stages: [commit-msg]

post-checkout

ブランチ切り替えの直後

stages: [post-checkout]

post-commit

コミットの直後

stages: [post-commit]

post-merge

マージの直後

stages: [post-merge]

post-rewrite

コミットを修正した直後

stages: [post-merge]

pre-commit

コミットの直前

デフォルト

pre-merge-commit

マージコミットの直前

デフォルト

pre-push

プッシュの直前

stages: [push]

pre-rebase

リベースの直前

stages: [push]

prepare-commit-msg

コミットメッセージ作成の直前

stages: [push]

# .pre-commit-config.yaml
repos:
  - repo: リポジトリ
    rev: バージョン
    hooks:
      - id: フック名
        stages:
          - フックのタイミング
          - [pre-commit, commit-msg]

また、設定ファイルのstagesセクションで、 ツールごとにpre-commitフックを実行するタイミングを設定できます。

pre-commit-hooksしたい

repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
  rev: v4.6.0
  hooks:
  - id: detect-private-key
  - id: trailing-whitespace
    args: ["--markdown-linebreak-ext=md"]
  - id: end-of-file-fixer
  - id: check-case-conflict
  - id: check-merge-conflict
  - id: check-added-large-files
    args: ["--maxkb=500"]
  - id: check-json
  - id: check-toml
  - id: check-yaml
  - id: name-tests-test
    args: [--pytest-test-first]

pre-commit-hooksのフックから、 使うとよさそうなものを選んでみました。

ruff-pre-commitしたい

ruffは、Pythonプロジェクトの リンター&フォーマッターです。 コミットごとに自動チェックすることで、コードの表記ゆれを抑えることができます。

フックの設定方法はフォーマッター/リンターしたい(ruff)に整理しました。

commitizenしたい

commitizen (cz)はコミットメッセージの形式を守るためのツールです。 stages: [commit-msg]でコミットメッセージを保存したあとにフックがかかるようにしておきます。

フックの設定方法はセマンティック・バージョニングしたい(commitizen)に整理しました。

poetryしたい

repos:
- repo: ...
- repo: https://github.com/python-poetry/poetry
  rev: 1.8.0
  hooks:
  - id: poetry-check
    args: [--lock]
    stages: [pre-push]
  #- id: poetry-lock
  - id: poetry-export
    args: [--format, requirements.txt, --output, requirements.txt]
    stages: [pre-push]
  #- id: poetry-install

Pythonプロジェクトをpoetryで管理している場合は、 poetry-check(=poetry check)、 poetry-lock(=poetry lock)、 poetry-export(=poetry export)、 poetry-install(=poetry install) のフックを導入してみるとよいかもしれません。

それぞれに適切なargsを設定して使うとよいと思います。 また、コミット時ではなくプッシュ時(pre-push)に設定するとよいと思います。

注釈

Read the Docsに公開するためにrequirements.txtが必要です。 このリポジトリも、もpoetry-exportフックを使って、 requirements.txtを生成できるようにしてあります。

脆弱性を検出したい(Bandit

repos:
- repo: ...
- repo: ...
- repo: https://github.com/PyCQA/bandit
  rev: 1.7.4
  hooks:
  - id: bandit
    args: ["-r", "ディレクトリ名"]

nbstripoutしたい

repos:
- repo: ...
- repo: https://github.com/kynan/nbstripout
  rev: 0.5.0
  hooks:
  - id: nbstripout

Jupyter Notebookを使っている場合、 実行結果を削除したファイルをコミットしたい場合があります。 nbstripoutでコミット前に出力をクリアできます。

注釈

.ipynbファイルは、実行結果を残しているといつのまにか間に肥大化している可能性があります。 また、デバッグ用途に使っている場合、 うっかりとシークレット情報を出力に残したままにしてしまう可能性もあります。 そのようなことを回避したい場合、このツールは有用です。

pytestしたい

repos:
- repo: local
  hooks:
  - id: pytest
    name: pytest
    entrypoint: pytest --verbose
    stages:
      - [pre-push]
    language: system

pytest用のフックはGitHub上にはないようです。 pre-commitはローカル(local)にインストールされているコマンドを使うことができます。 プッシュ時(pre-push)にテストを走らせるとよいと思います。

注釈

テストはCI/CDでも実行しているかもしれません。 ローカルからのプッシュ前に確認を追加することで、 パイプライン時間の無駄遣いを減らすことができます。

リファレンス