ワークフローの自動化:Gitクライアントサイドフックの実践ガイド
Gitフックは、Gitエコシステム内で強力でありながら、しばしば過小評価されているツールです。これらにより、コミット、プッシュ、マージなどのイベントの前後に、開発ワークフローの特定のポイントでカスタムスクリプトを自動的にトリガーできます。ローカルリポジトリで作業する個々の開発者にとって、クライアントサイドフックは、コード品質の強制、ローカルテストの実行、および中央サーバーサイドの強制に依存せずに、サブミット前のチェックを標準化するために不可欠です。
このガイドでは、最も一般的で役立つタイプであるpre-commitとpost-mergeに焦点を当てて、Gitクライアントサイドフックの仕組みを探ります。これらのフックをマスターすることで、繰り返しタスクを自動化し、エラーを早期に検出し、日常の開発プロセスにおける一貫性と信頼性を大幅に向上させることができます。
Gitフックの理解
Gitフックは、Gitが特定のコア操作の前後に自動的に実行する実行可能スクリプトです。これらは、すべてのGitリポジトリの.git/hooksディレクトリに存在します。Gitにはサンプルフック(通常は.sampleで終わる)が付属していますが、.sample拡張子を削除して名前を変更した場合にのみアクティブになります。
クライアントサイドフック vs. サーバーサイドフック
2つの主なタイプを区別することが重要です。
- クライアントサイドフック:ローカル開発者のマシンで実行されます(例:
pre-commit、commit-msg)。これらは、ローカル検証とユーザーエクスペリエンスの向上に優れています。 - サーバーサイドフック:プッシュが受信されたときに中央サーバーで実行されます(例:
pre-receive、post-receive)。これらは通常、プロジェクト全体の強制ポリシーに使用されます。
重要事項:クライアントサイドフックはローカルであるため、リポジトリをクローンしても自動的にクローンまたは共有されません。すべてのセットアップは、各開発者が手動で行うか、初期化スクリプトを通じて管理する必要があります。
クライアントサイドフックの場所と有効化
すべてのクライアントサイドフックは、リポジトリ内の.git/hooksディレクトリにあります。
新しいリポジトリを初期化すると、Gitはテンプレートを提供します。
git init
# これにより、pre-commit.sampleのようなサンプルファイルが格納された.git/hooksディレクトリが作成されます
フックを有効にするには、サンプルファイルをリネームするだけです。たとえば、pre-commitフックを有効にするには、次のようにします。
cd .git/hooks
cp pre-commit.sample pre-commit
chmod +x pre-commit
ここにあるスクリプトは実行可能である必要があります(そのためchmod +x)。通常はシェルスクリプトとして実行されますが、シェバン行(#!/bin/bash、#!/usr/bin/env pythonなど)が存在し、インタプリタが利用可能であれば、どの言語でも記述できます。
実践例1:pre-commitフック
pre-commitフックは、Gitがコミットメッセージを要求する直前に実行されます。コミットされるコードのチェックを実行するのに理想的な場所です。
pre-commitの一般的なユースケース:
- リンティング/スタイルチェック:コードが確立されたスタイルガイド(例:ESLint、Black)に準拠していることを確認します。
- 単体テストの実行:高速で重要なテストを実行します。
- 構文チェック:基本的な構文の正しさを検証します。
- 誤ったコミットの防止:秘密鍵やデバッグステートメントが残っていないことを確認します。
簡単なpre-commitフックの作成(シェル例)
この例のスクリプトは、ステージングされたファイルにTODO:という単語が含まれているかどうかを確認し、見つかった場合はコミットを失敗させて、開発者にこれらのプレースホルダーを処理するように強制します。
.git/hooks/pre-commitファイルを作成し、以下のコンテンツを追加します。
#!/bin/bash
# 1. ステージングされたファイルに'TODO:'が含まれているかチェック
STAGED_FILES=$(git diff --cached --name-only)
if grep -q "TODO:" <<< "$STAGED_FILES"; then
echo "\n[HOOK FAILED] ステージングされたファイルに'TODO:'マーカーが見つかりました。コミット前に解決してください。"
# マーカーを含む特定のファイルを出力します(オプション)
git diff --cached | grep "TODO:"
exit 1 # ゼロ以外の終了コードでコミットを中止
fi
# 2. Pythonファイルに対して基本的な構文チェックを実行します('python -m py_compile'が必要です)
for FILE in $(git diff --cached --name-only --diff-filter=ACM | grep '\.py$'); do
echo "$FILE の構文をチェック中..."
python -m py_compile "$FILE" > /dev/null 2>&1
if [ $? -ne 0 ]; then
echo "[HOOK FAILED] $FILE に構文エラーが見つかりました。"
exit 1
fi
done
# すべてのチェックに合格した場合
echo "Pre-commitチェックは正常に完了しました。"
exit 0 # コミットを許可するためにゼロで終了
スクリプトがゼロ以外のステータス(exit 1など)で終了した場合、Gitは直ちにコミットプロセスを中止し、エラーメッセージを表示します。
ベストプラクティス:複雑なリンティングやフォーマットについては、Husky(JavaScriptエコシステム用)やPre-commit(フレームワークに依存しないツール)のような外部フック管理ツールを検討してください。これらのツールは、フックのインストール、共有、依存関係の管理を自動的に行います。
実践例2:post-mergeフック
post-mergeフックは、git merge操作が正常に完了した直後に実行されます。このフックは、マージされた新しいコードに基づいて、クリーンアップを実行したり、ローカル依存関係を更新したりするのに役立ちます。
post-mergeの一般的なユースケース:
- サブモジュールの更新:依存リポジトリを自動的にリフレッシュします。
- 依存関係の再構築:依存関係ファイル(
package.json、requirements.txt)が変更された場合、npm installまたは同等のコマンドを実行します。 - ユーザーへの通知:関連するブランチ情報を表示します。
簡単なpost-mergeフックの作成(依存関係の更新)
プロジェクトでNode.jsを使用している場合、package.jsonまたはpackage-lock.jsonが変更されたブランチをマージした後に、node_modulesが最新であることを確認したい場合があります。
.git/hooks/post-mergeファイルを作成します。
#!/bin/bash
echo "Post-merge hook triggered."
# package.json または package-lock.json がマージで変更されたかチェック
if git diff --name-only HEAD@{1} HEAD | grep -Eq "(package\.json|package-lock\.json)"; then
echo "依存関係ファイルが変更されました。npm install を実行します..."
npm install
if [ $? -eq 0 ]; then
echo "依存関係が正常に更新されました。"
else
echo "警告:マージ後にnpm installが失敗しました。手動で 'npm install' を実行してください。"
fi
else
echo "依存関係ファイルは変更されていません。npm install をスキップします。"
fi
exit 0
このフックは、Gitのリファレンスログ機能(HEAD@{1}はマージ前の状態を参照)を利用してファイルを比較し、アクションを条件付きにして、不要な実行を回避します。
その他の役立つクライアントサイドフック
pre-commitとpost-mergeは非常に広く使用されていますが、ワークフローを合理化できる他のクライアントサイドフックもいくつかあります。
commit-msg:ユーザーがコミットメッセージを入力した後、コミットが確定する前に実行されます。コミットメッセージの標準(例:Conventional Commits形式)を強制するのに役立ちます。pre-rebase:リベースが開始される前に実行されます。リベースから保護すべき特定のブランチがあるかチェックできます。post-checkout:git checkoutが成功した後実行されます。チェックアウトされたブランチに基づいて、環境変数やツールの構成を切り替えるのに役立ちます。
| フック名 | トリガーポイント | 主なユースケース |
|---|---|---|
pre-commit |
コミット作成前 | コードリンティング、ローカルテスト、フォーマット |
commit-msg |
メッセージ入力後 | メッセージ形式の強制(例:JIRAチケット) |
post-merge |
マージ成功後 | サブモジュールの更新、依存関係の更新 |
post-checkout |
チェックアウト成功後 | 環境構成の切り替え |
まとめと次のステップ
クライアントサイドGitフックは、繰り返しタスクを自動化し、開発環境で直接ローカル品質標準を強制するためのオーバーヘッドゼロの方法を提供します。これらは、ずさんなコミットや統合問題に対する最初の防御線として機能します。
効果的に使用するには:
- 繰り返しタスクの特定:コミットまたはマージ前に手動で実行するチェックを決定します。
.git/hooksの場所:プロジェクト内のこのディレクトリに移動します。- 有効化とスクリプト化:
.sampleファイルをコピーし、リネームし、実行可能であることを確認し(chmod +x)、自動化ロジックを記述します。 - 管理ツールの検討:チームの場合は、
pre-commitなどのツールを調査して、開発者間でフックのインストールを同期させます。