チャプター ▾ 第2版

8.3 Git のカスタマイズ - Git フック

Git フック

他の多くのバージョン管理システムと同様に、Git には特定の重要なアクションが発生したときにカスタムスクリプトを実行する方法があります。これらのフックには、クライアントサイドとサーバーサイドの2つのグループがあります。クライアントサイドフックは、コミットやマージなどの操作によってトリガーされ、サーバーサイドフックは、プッシュされたコミットの受信などのネットワーク操作で実行されます。これらのフックはあらゆる目的で使用できます。

フックのインストール

フックはすべて、Git ディレクトリの hooks サブディレクトリに格納されています。ほとんどのプロジェクトでは、これは .git/hooks です。git init で新しいリポジトリを初期化すると、Git はフックディレクトリに多くのサンプルスクリプトを設定します。その多くはそれ自体が有用ですが、各スクリプトの入力値も文書化されています。すべての例はシェルスクリプトとして書かれており、Perl もいくつか含まれていますが、適切に名前が付けられた実行可能なスクリプトであれば、Ruby や Python など、慣れ親しんだ言語で書かれていても問題なく動作します。バンドルされているフックスクリプトを使用する場合は、名前を変更する必要があります。ファイル名の末尾はすべて .sample です。

フックスクリプトを有効にするには、.git ディレクトリの hooks サブディレクトリに、適切な名前(拡張子なし)で実行可能なファイルを配置します。その時点から、呼び出されるようになります。ここでは、主要なフックファイル名のほとんどについて説明します。

クライアントサイドフック

クライアントサイドフックは多数あります。このセクションでは、コミットワークフローフック、電子メールワークフロースクリプト、およびその他のすべてに分類します。

クライアントサイドフックは、リポジトリをクローンしてもコピーされないことに注意することが重要です。これらのスクリプトの目的がポリシーを強制することである場合は、おそらくサーバーサイドでそれを行う必要があります。例については、Git 強制ポリシーの例を参照してください。

コミットワークフローフック

最初の4つのフックは、コミットプロセスに関係しています。

pre-commit フックは、コミットメッセージを入力する前に最初に実行されます。コミットされるスナップショットを検査して、何か忘れ物がないか、テストが実行されているか、コードで検査する必要があるものを確認するために使用されます。このフックからゼロ以外の値で終了するとコミットは中止されますが、git commit --no-verify でバイパスできます。コードスタイルチェック(lint または同等のものを実行)、末尾の空白のチェック(デフォルトのフックはまさにこれを行います)、新しいメソッドの適切なドキュメントのチェックなどを行うことができます。

prepare-commit-msg フックは、コミットメッセージエディタが起動される前に、デフォルトメッセージが作成された後に実行されます。コミット作成者がデフォルトメッセージを見る前に、それを編集できます。このフックはいくつかのパラメーターを受け取ります。これまでのコミットメッセージを保持するファイルへのパス、コミットの種類、および修正コミットの場合はコミット SHA-1 です。このフックは通常、通常のコミットには有用ではありません。むしろ、テンプレート化されたコミットメッセージ、マージコミット、スカッシュされたコミット、修正コミットなど、デフォルトメッセージが自動生成されるコミットに適しています。コミットテンプレートと組み合わせて、プログラムで情報を挿入するために使用できます。

commit-msg フックは1つのパラメーターを受け取ります。これも開発者によって書かれたコミットメッセージを含む一時ファイルへのパスです。このスクリプトがゼロ以外の値で終了すると、Git はコミットプロセスを中止します。したがって、コミットを許可する前に、プロジェクトの状態またはコミットメッセージを検証するために使用できます。この章の最後のセクションで、このフックを使用してコミットメッセージが必須パターンに準拠していることを確認する方法を示します。

コミットプロセス全体が完了した後、post-commit フックが実行されます。パラメーターは受け取りませんが、git log -1 HEAD を実行することで最後のコミットを簡単に取得できます。通常、このスクリプトは通知などに使用されます。

メールワークフローフック

メールベースのワークフロー用に3つのクライアントサイドフックを設定できます。これらはすべて git am コマンドによって呼び出されるため、ワークフローでこのコマンドを使用していない場合は、次のセクションにスキップしても問題ありません。git format-patch で準備されたパッチをメールで受け取っている場合は、これらのいくつか役立つかもしれません。

最初に実行されるフックは applypatch-msg です。これは1つの引数を受け取ります。提案されたコミットメッセージを含む一時ファイルの名前です。このスクリプトがゼロ以外の値で終了すると、Git はパッチを中止します。これを使用して、コミットメッセージが適切にフォーマットされていることを確認したり、スクリプトがその場で編集することでメッセージを正規化したりできます。

git am 経由でパッチを適用するときに次に実行されるフックは pre-applypatch です。少し紛らわしいですが、パッチが適用された後にコミットが行われる前に実行されるため、コミットを行う前にスナップショットを検査するために使用できます。このスクリプトでテストを実行したり、作業ツリーを検査したりできます。何か不足しているか、テストがパスしない場合、ゼロ以外の値で終了すると、パッチをコミットせずに git am スクリプトが中止されます。

git am 操作中に最後に実行されるフックは post-applypatch で、コミットが行われた後に実行されます。これを使用して、パッチをプルしたことをグループまたはパッチの作成者に通知できます。このスクリプトでパッチ適用プロセスを停止することはできません。

その他のクライアントフック

pre-rebase フックは、リベースを行う前に実行され、ゼロ以外の値で終了することでプロセスを停止できます。このフックを使用して、すでにプッシュされたコミットのリベースを禁止できます。Git がインストールするサンプル pre-rebase フックはこれを行います。ただし、ワークフローと一致しない可能性のあるいくつかの仮定があります。

post-rewrite フックは、git commit --amendgit rebase などのコミットを置き換えるコマンドによって実行されます(git filter-branch では実行されません)。単一の引数は、書き換えをトリガーしたコマンドであり、stdin を介して書き換えのリストを受け取ります。このフックは、post-checkout および post-merge フックと同じ用途の多くを持っています。

git checkout が成功すると、post-checkout フックが実行されます。これを使用して、プロジェクト環境に合わせて作業ディレクトリを適切に設定できます。これは、ソース管理したくない大きなバイナリファイルの移動、ドキュメントの自動生成などを行うことを意味する場合があります。

post-merge フックは、merge コマンドが成功した後に実行されます。これを使用して、Git が追跡できないアクセス許可データなどの作業ツリーのデータを復元できます。このフックは、作業ツリーが変更されたときにコピーしたい Git 管理外ファイルの存在を同様に検証できます。

pre-push フックは git push 時に、リモート参照が更新された後、オブジェクトが転送される前に実行されます。リモートの名前と場所をパラメーターとして受け取り、stdin を介して更新される参照のリストを受け取ります。これを使用して、プッシュが行われる前に一連の参照更新を検証できます(ゼロ以外の終了コードはプッシュを中止します)。

Git は、通常の操作の一部として、git gc --auto を呼び出すことで時々ガベージコレクションを行います。pre-auto-gc フックは、ガベージコレクションが行われる直前に呼び出され、これが起こっていることを通知したり、今が適切でない場合はコレクションを中止したりするために使用できます。

サーバーサイドフック

クライアントサイドフックに加えて、システム管理者としていくつかの重要なサーバーサイドフックを使用して、プロジェクトのほぼあらゆる種類のポリシーを強制できます。これらのスクリプトは、サーバーへのプッシュの前後に実行されます。プリフックはいつでもゼロ以外の値で終了してプッシュを拒否し、クライアントにエラーメッセージを返すことができます。希望に応じて複雑なプッシュポリシーを設定できます。

pre-receive

クライアントからのプッシュを処理するときに最初に実行されるスクリプトは pre-receive です。stdin からプッシュされている参照のリストを受け取ります。ゼロ以外の値で終了すると、それらはすべて受け入れられません。このフックを使用して、更新された参照のいずれも非高速フォワードでないことを確認したり、プッシュで変更しているすべての参照とファイルへのアクセス制御を行ったりすることができます。

update

update スクリプトは pre-receive スクリプトと非常によく似ていますが、プッシャーが更新しようとしているブランチごとに一度実行される点が異なります。プッシャーが複数のブランチにプッシュしようとしている場合、pre-receive は一度しか実行されませんが、update はプッシュしているブランチごとに一度実行されます。stdin から読み取る代わりに、このスクリプトは3つの引数を受け取ります。参照(ブランチ)の名前、プッシュ前の参照が指していた SHA-1、およびユーザーがプッシュしようとしている SHA-1 です。update スクリプトがゼロ以外の値で終了すると、その参照のみが拒否されます。他の参照は引き続き更新できます。

post-receive

post-receive フックはプロセス全体が完了した後に実行され、他のサービスを更新したりユーザーに通知したりするために使用できます。pre-receive フックと同じ stdin データを受け取ります。例としては、リストへのメール送信、継続的インテグレーションサーバーへの通知、チケット追跡システムの更新などがあります。コミットメッセージを解析して、開く、変更する、または閉じる必要があるチケットがあるかどうかを確認することもできます。このスクリプトはプッシュプロセスを停止できませんが、完了するまでクライアントは切断されないため、時間がかかる可能性のあることを試す場合は注意してください。

ヒント

他の人が読む必要があるスクリプト/フックを作成する場合は、コマンドラインフラグの長いバージョンを推奨します。半年後には感謝するでしょう。

scroll-to-top