pre-commitフックとは?コミット前に自動チェックする便利な仕組みを解説

プログラミング・IT

プログラミングをしていて、こんな経験はありませんか?

「あっ、コミットした後にスペルミスに気づいた…」
「フォーマットを整えるの、忘れてた…」

コードをGitにコミットする前に、自動的にチェックしてくれる仕組みがあったら便利ですよね。

それを実現するのがpre-commitフックです。

コミット操作の「直前」に自動的にスクリプトを実行し、問題があればコミットを止めてくれる——この便利な機能を使えば、チーム全体のコード品質が向上します。

今回は、pre-commitフックの基本から、実際の設定方法、便利なツール、そして実務での活用例まで、分かりやすく解説していきますね。

スポンサーリンク
  1. pre-commitフックとは?基本を理解しよう
    1. Gitのフック機能
    2. pre-commitフックの役割
    3. 何をチェックできるのか
  2. なぜpre-commitフックが必要なのか
    1. 人的ミスを防ぐ
    2. チーム全体のコード品質向上
    3. レビューの効率化
    4. 早期発見・早期修正
  3. pre-commitフックの設定方法
    1. 基本:手動でスクリプトを作成
    2. 基本スクリプトの構造
    3. 問題点:手動設定の限界
  4. pre-commitフレームワーク
    1. pre-commitツールとは
    2. インストール方法
    3. 基本的な使い方
    4. 設定ファイルの構造
  5. 実用的な設定例
    1. Python プロジェクト
    2. JavaScript / TypeScript プロジェクト
    3. マルチ言語プロジェクト
    4. 秘密情報の検出
  6. 便利なフック一覧
    1. pre-commit-hooks(公式)
    2. 言語別の人気フック
  7. 実行オプションとカスタマイズ
    1. 特定のフックだけを実行
    2. 全ファイルに対して実行
    3. フックのスキップ
    4. 特定のファイルを除外
    5. 特定のファイルだけを対象
  8. トラブルシューティング
    1. フックが実行されない
    2. フックが失敗し続ける
    3. コミットが遅い
    4. 自動修正されたファイルの扱い
  9. CI/CDとの連携
    1. GitHub Actions での実行
    2. GitLab CI での実行
    3. ローカルとCIの使い分け
  10. チーム導入のベストプラクティス
    1. 段階的な導入
    2. ドキュメントの整備
    3. チームへの説明
  11. よくある質問と回答
    1. Q1:pre-commitフックは強制すべき?
    2. Q2:全てのチェックをpre-commitで行うべき?
    3. Q3:既存プロジェクトへの導入は大変?
    4. Q4:pre-commitフックをバイパスする方法は?
    5. Q5:フックが遅すぎる場合は?
  12. まとめ: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など)は、自動的にファイルを修正します。

動作:

  1. コミット実行
  2. フックがファイルを修正
  3. コミットは失敗(修正されたファイルがステージングされていないため)
  4. 再度 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:段階的に導入すれば問題ありません。

手順:

  1. .pre-commit-config.yaml を作成(基本的なフックのみ)
  2. pre-commit run --all-files で全ファイルをチェック
  3. 大量のエラーが出る場合は、除外設定を追加
  4. 徐々に除外を減らしていく

Q4:pre-commitフックをバイパスする方法は?

A:--no-verify オプションを使います。

git commit -m "Urgent fix" --no-verify

注意:

  • 緊急時のみ使用
  • 後で修正を忘れずに
  • 頻繁に使うのは避ける

Q5:フックが遅すぎる場合は?

A:以下の方法で高速化できます。

対策:

  • 重いフックを削除または軽量化
  • filesexclude で対象を絞る
  • 並列実行(-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フックで自動化すれば、常にクリーンなコードを保てますよ。

まずは基本的な設定から始めて、チーム全体のコード品質を向上させてくださいね!

コメント

タイトルとURLをコピーしました