コミット前にチェックしたい(pre-commit)
$ pre-commit --version
pre-commit 4.6.2
$ pre-commit install
$ pre-commit run --all-files
pre-commitはGit 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)
$ pre-commit sample-config > .pre-commit-config.yaml
pre-commit sample-configコマンドで、雛形となる.pre-commit-config.yamlを出力できます。
出力されるrevは固定の古いバージョンなので、次のように書き換えて使うのがオススメです。
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.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で確認できます。
フックをインストールしたい(install)
$ pre-commit install
pre-commit installでGit Hooksを有効化できます。
.pre-commit-config.yamlの設定が完了したら実行してください。
フックを実行したい(run)
$ pre-commit run --all-files
$ pre-commit run -a # 短縮形
pre-commit run --all-files(短縮形-a)で
すべてのファイルに対してチェックを実行します。
trailing-whitespaceやend-of-file-fixerなどのフックは自動でファイルを修正します。
フックを追加したい
$ pre-commit install --install-hooks
$ pre-commit install --install-hooks --hook-type pre-commit
$ pre-commit install --install-hooks --hook-type commit-msg
--install-hooksで、.pre-commit-config.yamlに書かれたフックをインストールできます。
--hook-type フックタイプで、フックのタイミングを追加できます。
フックのタイミング
フックのタイミングは[stages]で変更できます。
デフォルトではpre-commit(コミットの直前)に実行されます。
Git Hook |
タイミング |
設定例 |
|---|---|---|
|
コミットの直前 |
|
|
マージコミットの直前 |
|
|
コミットメッセージ作成の直後 |
|
|
コミットメッセージ作成の直前 |
|
|
プッシュの直前 |
|
|
リベースの直前 |
|
|
ブランチ切り替え後 |
|
|
コミット後 |
|
|
マージ後 |
|
|
コミット書き換え後( |
|
pre-commit install --helpの--hook-typeで、実際にサポートされているタイミングの一覧を確認できます。
設定ファイルでタイミングを指定する例:
# .pre-commit-config.yaml
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
hooks:
- id: detect-private-key
stages: [pre-push] # プッシュの直前に実行
フックを確認したい
$ find .git/hooks -type f ! -name "*.sample" -perm -u+x
pre-commit自身に、フックを一覧する機能はありません。
.git/hooks/を直接確認して、フックが追加されているかを確認します。
findコマンドを使う場合、-perm -u+xのようにハイフンを付けることで、実行可能なファイルだけに絞り込めます
事前チェックしたい(pre-commit-hooks)
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.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したい(ruff-pre-commit)
ruffは、Pythonプロジェクトの
リンター&フォーマッターです。
コミットごとに自動チェックすることで、コードの表記ゆれを抑えることができます。
フックの設定方法はフォーマッター/リンターしたい(ruff)に整理しました。
commitizenしたい(commitizen)
commitizen (cz)はコミットメッセージの形式を守るためのツールです。
stages: [commit-msg]でコミットメッセージを保存したあとにフックがかかるようにしておきます。
フックの設定方法はセマンティック・バージョニングしたい(commitizen)に整理しました。
poetryしたい
repos:
- repo: ...
- repo: https://github.com/python-poetry/poetry
rev: 2.4.1
hooks:
- id: poetry-check
args: [--lock]
stages: [pre-push]
#- id: poetry-lock
#- id: poetry-install
- repo: https://github.com/python-poetry/poetry-plugin-export
rev: 1.10.0
hooks:
- id: poetry-export
args: [--format, requirements.txt, --output, requirements.txt]
stages: [pre-push]
Pythonプロジェクトをpoetryで管理している場合は、
poetry-check(=poetry check)、
poetry-lock(=poetry lock)、
poetry-export(=poetry export)、
poetry-install(=poetry install)
のフックを導入してみるとよいかもしれません。
それぞれに適切なargsを設定して使うとよいと思います。
また、コミット時ではなくプッシュ時(pre-push)に設定するとよいと思います。
注意
poetry-exportフックは、poetry本体(python-poetry/poetry)ではなく、
poetry-plugin-exportという別リポジトリに移動しました。
poetry本体のrepoを指定すると、
is not present in repositoryエラーになります。
poetry exportコマンド自体も、poetry本体からは削除されており、
別途プラグインとしてインストールしないと使えません。
注釈
Read the Docsに公開するためにrequirements.txtが必要です。
このリポジトリも、poetry-exportフックを使って、
requirements.txtを生成できるようにしてあります。
脆弱性を検出したい(Bandit)
repos:
- repo: ...
- repo: ...
- repo: https://github.com/PyCQA/bandit
rev: 1.9.4
hooks:
- id: bandit
args: ["-r", "ディレクトリ名"]
BanditはPythonコードの潜在的なセキュリティ上の問題を検出するリンターです。
shell=Trueを使ったsubprocess呼び出しなど、脆弱性につながりやすいパターンを警告してくれます。
-rオプションで、指定したディレクトリを再帰的にスキャンします。
pytestしたい
repos:
- repo: local
hooks:
- id: pytest
name: pytest
entry: uv run pytest --verbose
language: system
pass_filenames: false
always_run: true
stages: [pre-push]
pytest用の公式フックはありません。
pre-commitはローカル(local)にインストールされているコマンドを使うことができます。
プッシュ時(pre-push)にテストを走らせるとよいと思います。
entryに実行するコマンドを指定します。
uvでプロジェクトの依存関係を管理している場合、
pytestは仮想環境(.venv)の中にインストールされているはずなので、
entry: pytestではなくentry: uv run pytestのように指定してください。
pass_filenames: falseがないと、変更されたファイル名がそのままpytestの引数として渡されてしまい、うまく動かないので注意してください。
always_run: trueで、対象ファイルの変更有無にかかわらず毎回実行します。
注釈
テストはCI/CDでも実行しているかもしれません。 ローカルからのプッシュ前に確認を追加することで、パイプライン時間の無駄遣いを減らすことができます。