プログラミングをしていて、こんな経験はありませんか?
「あっ、コミットした後にスペルミスに気づいた…」
「フォーマットを整えるの、忘れてた…」
コードをGitにコミットする前に、自動的にチェックしてくれる仕組みがあったら便利ですよね。
それを実現するのがpre-commitフックです。
コミット操作の「直前」に自動的にスクリプトを実行し、問題があればコミットを止めてくれる——この便利な機能を使えば、チーム全体のコード品質が向上します。
今回は、pre-commitフックの基本から、実際の設定方法、便利なツール、そして実務での活用例まで、分かりやすく解説していきますね。
pre-commitフックとは?基本を理解しよう

Gitのフック機能
Git hook(Gitフック)とは、Gitの特定の操作が行われた時に、自動的にスクリプトを実行する仕組みのことです。
フック(hook)の語源:
「引っかける」という意味。Gitの操作に「引っかかって」スクリプトが実行されるイメージです。
主なGitフックの種類:
- pre-commit:コミット前に実行
- pre-push:プッシュ前に実行
- post-commit:コミット後に実行
- commit-msg:コミットメッセージ作成時に実行
この中で最もよく使われるのが、pre-commitフックです。
pre-commitフックの役割
pre-commitは、git commit コマンドを実行した時、実際にコミットされる直前に走るスクリプトです。
処理の流れ:
1. git commit を実行
2. ↓
3. pre-commitフックが実行される
4. ↓
5. スクリプトが成功(終了コード0)
→ コミット続行
6. ↓
7. スクリプトが失敗(終了コード0以外)
→ コミット中止
例え:
空港の保安検査のようなものです。
- 搭乗(コミット)する前に、手荷物検査(チェック)がある
- 問題なければ通過、問題があれば止められる
何をチェックできるのか
pre-commitフックでは、様々なチェックを自動化できます。
コードの品質チェック:
- 構文エラーの検出
- コーディング規約の違反チェック
- 未使用の変数や関数の検出
フォーマットの自動修正:
- インデントの統一
- 行末の空白削除
- 改行コードの統一
セキュリティチェック:
- 秘密情報(APIキー、パスワード)の混入検出
- 機密ファイルのコミット防止
テストの実行:
- ユニットテストの実行
- 型チェック
- リンターの実行
なぜpre-commitフックが必要なのか
人的ミスを防ぐ
よくあるミス:
- デバッグ用のコードを残したままコミット
- フォーマットされていないコードをコミット
- テストが通っていないコードをコミット
- コミットメッセージの誤字脱字
pre-commitフックで防げる:
自動チェックにより、コミット前にミスを検出できます。
チーム全体のコード品質向上
統一されたルール:
- 全員が同じチェックを受ける
- コードレビューの負担が軽減
- 品質基準が明確
例:
- Aさん:Pythonのコードを常に
blackでフォーマット - Bさん:フォーマットを忘れがち
→ pre-commitフックで全員が自動フォーマット
レビューの効率化
コードレビューの焦点:
- × 「インデントが揃ってない」
- × 「未使用の変数がある」
- ○ 「このロジックは改善できる」
- ○ 「エッジケースを考慮すべき」
機械的なチェックは自動化し、人間は設計やロジックのレビューに集中できます。
早期発見・早期修正
バグ発見のコスト:
- コミット前:数秒で修正
- コミット後:修正コミットが必要
- プッシュ後:リモートの履歴も汚れる
- 本番環境:大問題
早い段階で見つけるほど、修正のコストは低くなります。
pre-commitフックの設定方法
基本:手動でスクリプトを作成
Gitのフックは、.git/hooks/ ディレクトリにスクリプトファイルを置くだけで動作します。
手順:
1. フックディレクトリを確認
cd your-project
ls .git/hooks/
既にサンプルファイル(.sampleという拡張子)があります。
2. pre-commitファイルを作成
# .git/hooks/pre-commit ファイルを作成
touch .git/hooks/pre-commit
# 実行権限を付与
chmod +x .git/hooks/pre-commit
3. スクリプトを書く
.git/hooks/pre-commit の例(シンプル):
#!/bin/sh
# Pythonファイルの構文チェック
for file in $(git diff --cached --name-only --diff-filter=ACM | grep '\.py$'); do
python -m py_compile "$file"
if [ $? -ne 0 ]; then
echo "Python syntax error in $file"
exit 1
fi
done
echo "All checks passed!"
exit 0
4. 動作確認
git add .
git commit -m "Test commit"
スクリプトが実行され、問題があればコミットが止まります。
基本スクリプトの構造
シェルスクリプトの基本形:
#!/bin/sh
# ここにチェック処理を書く
# 成功の場合
exit 0
# 失敗の場合(コミットを中止)
exit 1
重要なポイント:
- 1行目の
#!/bin/shは必須(シバン) exit 0で成功、それ以外で失敗- 実行権限(
chmod +x)が必要
問題点:手動設定の限界
手動でフックを作成する方法には、いくつかの問題があります。
問題1:共有が難しい
.git/hooks/はGitで管理されない- チームメンバーそれぞれが手動で設定する必要がある
問題2:メンテナンスが大変
- スクリプトを更新するのが手間
- 複数のプロジェクトで同じ設定を使いまわせない
問題3:複雑なチェックを書くのが大変
- 各種リンターやフォーマッターの統合が必要
- エラーハンドリングが面倒
そこで登場するのが、pre-commitフレームワークです。
pre-commitフレームワーク
pre-commitツールとは
pre-commitは、Gitフックを簡単に管理できるPython製のツールです。
公式サイト:https://pre-commit.com/
特徴:
- 設定ファイル(YAML)でフックを管理
- 設定ファイルをGitで共有できる
- 豊富なプラグイン(フック)が用意されている
- 複数のプログラミング言語に対応
メリット:
- チーム全体で同じチェックを実行できる
- 設定が簡単
- メンテナンスが楽
インストール方法
pipでインストール:
pip install pre-commit
Homebrewでインストール(Mac):
brew install pre-commit
バージョン確認:
pre-commit --version
基本的な使い方
1. 設定ファイルの作成
プロジェクトのルートディレクトリに .pre-commit-config.yaml を作成します。
.pre-commit-config.yaml の例(Python):
repos:
# 基本的なチェック
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- id: trailing-whitespace # 行末の空白を削除
- id: end-of-file-fixer # ファイル末尾の改行を統一
- id: check-yaml # YAMLファイルの構文チェック
- id: check-added-large-files # 大きなファイルの検出
# Pythonコードのフォーマット
- repo: https://github.com/psf/black
rev: 23.12.1
hooks:
- id: black
# import文のソート
- repo: https://github.com/pycqa/isort
rev: 5.13.2
hooks:
- id: isort
2. pre-commitのインストール
# Gitフックとして登録
pre-commit install
これで .git/hooks/pre-commit が自動的に作成されます。
3. 動作確認
# 手動で全ファイルをチェック
pre-commit run --all-files
# または、普通にコミットしてみる
git add .
git commit -m "Test commit"
4. 結果の確認
成功した場合:
Trim Trailing Whitespace.....................................Passed
Fix End of Files.............................................Passed
Check Yaml...................................................Passed
Check for added large files..................................Passed
black....................................................Passed
isort....................................................Passed
失敗した場合:
black....................................................Failed
- hook id: black
- files were modified by this hook
reformatted example.py
All done! ✨ 🍰 ✨
1 file reformatted.
修正が必要な場合、ツールが自動修正してくれることもあります。
設定ファイルの構造
基本構造:
repos: # リポジトリのリスト
- repo: <GitHubリポジトリURL> # フックの提供元
rev: <バージョン> # 使用するバージョン
hooks: # 実行するフック
- id: <フックID> # フックの識別子
args: [...] # オプション引数
files: <正規表現> # 対象ファイル
exclude: <正規表現> # 除外ファイル
複数のrepoを追加できる:
異なるツールを組み合わせて使えます。
実用的な設定例
Python プロジェクト
repos:
# 基本的なチェック
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-json
- id: check-added-large-files
args: ['--maxkb=500']
- id: debug-statements # print文やdebuggerの検出
# コードフォーマット(Black)
- repo: https://github.com/psf/black
rev: 23.12.1
hooks:
- id: black
language_version: python3.11
# import文のソート(isort)
- repo: https://github.com/pycqa/isort
rev: 5.13.2
hooks:
- id: isort
args: ["--profile", "black"]
# リンター(Flake8)
- repo: https://github.com/pycqa/flake8
rev: 7.0.0
hooks:
- id: flake8
args: ['--max-line-length=88', '--extend-ignore=E203']
# 型チェック(mypy)
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.8.0
hooks:
- id: mypy
additional_dependencies: [types-requests]
JavaScript / TypeScript プロジェクト
repos:
# 基本チェック
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-json
- id: check-yaml
# ESLint
- repo: https://github.com/pre-commit/mirrors-eslint
rev: v8.56.0
hooks:
- id: eslint
files: \.[jt]sx?$
types: [file]
additional_dependencies:
- eslint@8.56.0
- eslint-config-prettier@9.1.0
# Prettier
- repo: https://github.com/pre-commit/mirrors-prettier
rev: v3.1.0
hooks:
- id: prettier
types_or: [javascript, jsx, ts, tsx, json, yaml, markdown]
マルチ言語プロジェクト
repos:
# 全プロジェクト共通
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-json
- id: check-merge-conflict
# Python
- repo: https://github.com/psf/black
rev: 23.12.1
hooks:
- id: black
files: \.py$
# JavaScript
- repo: https://github.com/pre-commit/mirrors-prettier
rev: v3.1.0
hooks:
- id: prettier
files: \.[jt]sx?$
# Markdown
- repo: https://github.com/pre-commit/mirrors-prettier
rev: v3.1.0
hooks:
- id: prettier
files: \.md$
秘密情報の検出
repos:
# 秘密情報のスキャン
- repo: https://github.com/Yelp/detect-secrets
rev: v1.4.0
hooks:
- id: detect-secrets
args: ['--baseline', '.secrets.baseline']
exclude: package-lock.json
重要:
APIキーやパスワードなどの機密情報が誤ってコミットされるのを防ぎます。
便利なフック一覧
pre-commit-hooks(公式)
最もよく使われる基本的なフック集です。
ファイルの整形:
trailing-whitespace:行末の空白削除end-of-file-fixer:ファイル末尾に改行を追加mixed-line-ending:改行コードを統一
構文チェック:
check-yaml:YAMLファイルの検証check-json:JSONファイルの検証check-toml:TOMLファイルの検証check-xml:XMLファイルの検証
セキュリティ:
detect-private-key:秘密鍵の検出detect-aws-credentials:AWS認証情報の検出
その他:
check-added-large-files:大きなファイルの検出check-merge-conflict:マージコンフリクトマーカーの検出check-case-conflict:ファイル名の大文字小文字の衝突検出
言語別の人気フック
Python:
black:コードフォーマッターisort:import文のソートflake8:リンターmypy:型チェックpylint:静的解析
JavaScript/TypeScript:
eslint:リンターprettier:フォーマッターtslint:TypeScriptリンター(非推奨)
Go:
gofmt:コードフォーマットgolint:リンター
Rust:
rustfmt:コードフォーマットcargo-check:コンパイルチェック
実行オプションとカスタマイズ
特定のフックだけを実行
# blackだけを実行
pre-commit run black
# trailing-whitespaceだけを実行
pre-commit run trailing-whitespace
全ファイルに対して実行
# 全ファイルをチェック(初回やCIで有用)
pre-commit run --all-files
通常はステージングされたファイル(git add したファイル)だけがチェックされます。
フックのスキップ
一時的にフックをスキップすることもできます。
# 全てのフックをスキップしてコミット
git commit -m "Message" --no-verify
# または
SKIP=pre-commit git commit -m "Message"
注意:
緊急時のみ使用し、後で修正しましょう。
特定のファイルを除外
.pre-commit-config.yaml:
repos:
- repo: https://github.com/psf/black
rev: 23.12.1
hooks:
- id: black
exclude: ^(migrations/|legacy/) # migrationsとlegacyを除外
正規表現で除外パターンを指定できます。
特定のファイルだけを対象
repos:
- repo: https://github.com/psf/black
rev: 23.12.1
hooks:
- id: black
files: ^(src/|tests/) # srcとtestsだけを対象
トラブルシューティング
フックが実行されない
原因1:インストールされていない
# 解決策
pre-commit install
原因2:実行権限がない
# 解決策
chmod +x .git/hooks/pre-commit
原因3:設定ファイルが見つからない
.pre-commit-config.yamlがプロジェクトルートにあるか確認
フックが失敗し続ける
原因1:構文エラー
# YAMLの構文チェック
pre-commit validate-config
原因2:古いバージョン
# フックを最新に更新
pre-commit autoupdate
原因3:依存関係の問題
# クリーンインストール
pre-commit clean
pre-commit install
コミットが遅い
原因:フックが多すぎる、または重い処理をしている
対策1:軽量なフックだけを使う
# 重いmypyを削除
# - id: mypy
対策2:特定のファイルだけをチェック
hooks:
- id: mypy
files: ^src/ # testsは除外
対策3:CIに処理を移す
- 軽いチェックだけpre-commit
- 重いチェックはCI/CDで実行
自動修正されたファイルの扱い
一部のフック(blackやprettierなど)は、自動的にファイルを修正します。
動作:
- コミット実行
- フックがファイルを修正
- コミットは失敗(修正されたファイルがステージングされていないため)
- 再度
git addしてコミット
解決策:
# 1回目(フックが修正)
git commit -m "Message"
# 自動修正されたファイルを再ステージング
git add -u
# 2回目(コミット成功)
git commit -m "Message"
CI/CDとの連携
GitHub Actions での実行
.github/workflows/pre-commit.yml:
name: pre-commit
on:
pull_request:
push:
branches: [main]
jobs:
pre-commit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- uses: pre-commit/action@v3.0.0
メリット:
- ローカルでスキップされたコミットもチェックできる
- 全ファイルを対象にチェック
- プルリクエスト時に自動実行
GitLab CI での実行
.gitlab-ci.yml:
pre-commit:
image: python:3.11
before_script:
- pip install pre-commit
script:
- pre-commit run --all-files
only:
- merge_requests
- main
ローカルとCIの使い分け
ローカル(pre-commit):
- 軽量で速いチェック
- フォーマット、構文チェック
- 開発者が即座にフィードバックを得られる
CI/CD:
- 時間のかかる処理
- テスト、ビルド、デプロイ
- 全体的な品質保証
チーム導入のベストプラクティス
段階的な導入
ステップ1:基本的なフックから
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
まずは誰もが受け入れやすい軽量なチェックから。
ステップ2:フォーマッターを追加
# コードフォーマット
- repo: https://github.com/psf/black
rev: 23.12.1
hooks:
- id: black
自動修正されるため、開発者の負担が少ない。
ステップ3:リンターを追加
# リンター
- repo: https://github.com/pycqa/flake8
rev: 7.0.0
hooks:
- id: flake8
コード品質を向上させる。
ドキュメントの整備
README.md に追記:
## 開発環境のセットアップ
### pre-commitのインストール
\`\`\`bash
pip install pre-commit
pre-commit install
\`\`\`
### 初回チェック
\`\`\`bash
pre-commit run --all-files
\`\`\`
新しいメンバーが迷わないように。
チームへの説明
導入時に伝えるべきこと:
- pre-commitの目的(コード品質向上)
- メリット(レビュー効率化、バグの早期発見)
- 設定方法(簡単な手順)
- トラブル時の対処法(スキップ方法など)
デモを行う:
実際にコミットして、フックが動く様子を見せる。
よくある質問と回答
Q1:pre-commitフックは強制すべき?
A:チームの方針によりますが、推奨です。
強制する場合:
- CIでもチェックする
.pre-commit-config.yamlをリポジトリに含める- READMEに設定手順を記載
任意にする場合:
- 各自の判断で使う
- ただし、CIで同じチェックを実行
Q2:全てのチェックをpre-commitで行うべき?
A:いいえ、軽量なチェックだけにしましょう。
pre-commitに適している:
- フォーマット(1秒以内)
- 構文チェック(数秒)
- 軽量なリンター(数秒)
CIに回すべき:
- テスト(数分)
- ビルド(数分)
- セキュリティスキャン(数分)
Q3:既存プロジェクトへの導入は大変?
A:段階的に導入すれば問題ありません。
手順:
.pre-commit-config.yamlを作成(基本的なフックのみ)pre-commit run --all-filesで全ファイルをチェック- 大量のエラーが出る場合は、除外設定を追加
- 徐々に除外を減らしていく
Q4:pre-commitフックをバイパスする方法は?
A:--no-verify オプションを使います。
git commit -m "Urgent fix" --no-verify
注意:
- 緊急時のみ使用
- 後で修正を忘れずに
- 頻繁に使うのは避ける
Q5:フックが遅すぎる場合は?
A:以下の方法で高速化できます。
対策:
- 重いフックを削除または軽量化
filesやexcludeで対象を絞る- 並列実行(
-jオプション) - CIに処理を移す
まとめ:pre-commitフックでコード品質を自動化しよう
pre-commitフックは、コミット前の自動チェックを実現する強力な仕組みです。
この記事のポイント:
- pre-commitフックはコミット直前に自動実行されるスクリプト
- コードの品質チェック、フォーマット、セキュリティスキャンなどを自動化
- 手動でも設定できるが、pre-commitフレームワークの利用が推奨
.pre-commit-config.yamlで簡単に設定・共有できる- Python、JavaScript、Go、Rustなど多言語に対応
- 基本的なフック(trailing-whitespace、end-of-file-fixerなど)から始める
- フォーマッター(black、prettier)で自動修正が便利
- 重いチェックはCIに回し、pre-commitは軽量に保つ
--no-verifyで一時的にスキップ可能(緊急時のみ)- チーム導入は段階的に、ドキュメント整備も忘れずに
実践のコツ:
- まずは軽量なフックから導入
- 自動修正されるフォーマッターは開発者に優しい
- ドキュメントを整備して、新メンバーが迷わないように
- CIと組み合わせて、二重のチェック体制を構築
「あとで直そう」が積み重なると、技術的負債になります。
pre-commitフックで自動化すれば、常にクリーンなコードを保てますよ。
まずは基本的な設定から始めて、チーム全体のコード品質を向上させてくださいね!

コメント