概要
hookとは
- 特定のアクションが発生した時にカスタムスクリプトを叩く方法
hookの種類
大きく分けて二つのグループがある
- クライアントサイド
- コミットワークフローフック
- Eメールワークフローフック
- その他のクライアントフック
- サーバーサイド
hookの準備(インストール)
hookの使い方
Gitに同梱されているスクリプトのサンプルがこの
hooks
ディレクトリに格納されます。サンプルの多くはそのままでも十分有用ですし、また、各スクリプトの入力値に関するドキュメントもついています。サンプルは全てシェルスクリプト
で書かれており、その中の一部ではPerl
も使われています。ですが、どんなスクリプトでも、実行可能かつ適切に命名されてさえいれば、問題なく動きます。Ruby や Python などで書くこともできます。これら同梱のフックスクリプトを使用する場合は、ファイル名の末尾が .sample となっていますので適宜リネームしてください。フックスクリプトを有効にするには、Gitディレクトリの hooks サブディレクトリに、実行可能なファイルを適切な名前(拡張子は使えません)で配置すれば、以降そのファイルが呼び出されます。 ここでは重要なフックファイル名をいくつか取り上げます。
hookの種類(一部紹介)
クライアントサイドフック
コミットやマージといったクライアントでの操作の際に実行されます。
コミットワークフローフック
pre-commit フック
コミットメッセージが入力される前に実行されます。 これは、いまからコミットされるスナップショットを検査したり、何かし忘れた事がないか確認したり、テストが実行できるか確認したり、何かしらコードを検査する目的で使用されます。 このフックがゼロでない値を返すと、コミットが中断されます。また、この検査は git commit --no-verify で飛ばすこともできます。 ここではコーディングスタイルの検査(lintを実行するなど)や、行末の空白文字の検査(デフォルトのフックがまさにそうです)、新しく追加されたメソッドのドキュメントが正しいかどうかの検査といったことが可能です。
prepare-commit-msg フック
コミットメッセージエディターが起動する直前、デフォルトメッセージが生成された直後に実行されます。 このフックでは、デフォルトメッセージを、コミットの作者の目に触れる前に編集できます。 このフックにはパラメータがあり、その時点でのコミットメッセージを保存したファイルへのパス、コミットのタイプ、さらにamendされたコミットの場合はコミットの SHA-1 をパラメータとして取ります。 このフックは普段のコミットにおいてはあまり有用ではありませんが、テンプレートが用意されているコミットメッセージ・mergeコミット・squashコミット・amendコミットのような、デフォルトメッセージが自動生成されるコミットにおいて効果を発揮します。 コミットメッセージのテンプレートと組み合わせれば、プログラムで情報を動的に挿入できます。
commit-msg フック
開発者の書いたコミットメッセージを保存した一時ファイルへのパスをパラメータに取ります。 このスクリプトがゼロ以外の値を返した場合、Git はコミットプロセスを中断します。これを使えば、コミットを許可して処理を進める前に、プロジェクトの状態やコミットメッセージを検査できます。 この章の最後のセクションでは、このフックを使用してコミットメッセージが要求された様式に沿っているか検査するデモンストレーションを行います。
post-commit フック
コミットプロセスが全て完了した後には、post-commitフックが実行されます。 このフックはパラメータを取りませんが、
git log -1 HEAD を実行することで直前のコミットを簡単に取り出すことができます。 一般的にこのスクリプトは何かしらの通知といった目的に使用されます。
Eメールワークフローフック
Eメールを使ったワークフロー用として、三種類のクライアントサイドフックを設定できます。 これらはすべて git am コマンドに対して起動されるものなので、ふだんのワークフローでこのコマンドを使っていない場合は次のセクションまで読み飛ばしてもかまいません。 git format-patch で作ったパッチを受け取ることがあるなら、ここで説明する内容の中に有用なものがあるかもしれません。
applypatch-msg フック
これは引数をひとつ(コミットメッセージを含む一時ファイル名)だけ受け取ります。 このスクリプトがゼロ以外の戻り値で終了した場合、Git はパッチの処理を強制終了させます。 このフックを使うと、コミットメッセージの書式が正しいかどうかを確認したり、スクリプトで正しい書式に手直ししたりできます。
pre-applypatch フック
少々ややこしいのですが、このフックはパッチが 適用された後 、コミットが作成される前に実行されます。そのため、このフックでは、スナップショットの内容を、コミットする前に調べることができます。 このスクリプトを使えば、テストを実行したり、ワーキングツリーの調査をしたりといったことが行えます。 なにか抜けがあったりテストが失敗したりした場合はスクリプトをゼロ以外の戻り値で終了させます。そうすれば、git am はパッチをコミットせずに強制終了します。
post-applypatch フック
このフックは、コミットが作成された後に実行されます。 これを使うと、特定のグループのメンバーや、プルしたパッチの作者に対して、処理の完了を伝えることができます。 このスクリプトでは、パッチの適用を中断させることはできません。
その他のクライアントフック
pre-rebase フック
何かをリベースする前に実行され、ゼロ以外を返せばその処理を中断できます。 このフックを使うと、既にプッシュ済みのコミットのリベースを却下できます。 Git に同梱されているサンプルの pre-rebase フックがこの処理を行いますが、このフックの前提となっている条件のなかには読者のワークフローに合わないものもあるでしょう。
post-rewrite フック
既存のコミットを書き換えるコマンド、例えば git commit --amend や git rebase を実行した際に実行されます(ただし git filter-branch では実行されません)。 引数はひとつで、コミットの書き換えを行ったコマンドを引数に取ります。また、書き換えを行ったファイルのリストを stdin から受け取ります。 このフックは post-checkout や post-merge といったフックと同じ用途に使えます。
post-checkout フック
git checkout が正常に終了すると、post-checkout フックが実行されます。これを使うと、作業ディレクトリを自分のプロジェクトの環境にあわせて設定できます。 たとえば、バージョン管理対象外の巨大なバイナリファイルを作業ディレクトリに取り込んだり、ドキュメントを自動生成したりといった処理が行えます。
post-merge フック
merge コマンドが正常に終了したときに実行されます。 これを使うと、Git では追跡できないパーミッション情報などを作業ツリーに復元できます。 作業ツリーに変更が加わったときに取り込みたい Git の管理対象外のファイルの存在確認などにも使えます。
pre-push フック
git push を実行した際、リモート参照が更新された後、オブジェクトの転送が始まる前に実行されます。 このフックはリモートの名前と場所を引数に取ります。また、これから更新する参照のリストを stdin から受け取ります。 このフックは、プッシュを行う前に、更新される参照を検査するのに使用できます(ゼロ以外の値を返すとプッシュが中断されます)。
pre-auto-gc フック
Git は通常の操作の一環として、時折 git gc --auto を実行してガベージコレクションを行います。 pre-auto-gc フックは、ガベージコレクションが実行される直前に呼び出されます。このフックは、ガベージコレクションが実行されることを通知したり、タイミングが悪い場合にガベージコレクションを中断したりするのに使用できます。
サーバーサイドフック
プッシュされたコミットの受け取りといったネットワーク操作の際に実行される
システム管理者としてプロジェクトのポリシーを強制させる際には、クライアントサイドフックに加え、いくつかのサーバーサイドフックを使うこともできます。 これらのスクリプトは、サーバへのプッシュの前後に実行されます。 pre フックをゼロ以外の値で終了させると、プッシュを却下してエラーメッセージをクライアントに返すことができます。つまり、プッシュに関して、好きなだけ複雑なポリシーを設定できるということです。
pre-receive フック
クライアントからのプッシュを処理するときに最初に実行されるスクリプトが pre-receive です。 このスクリプトは、プッシュされた参照のリストを標準入力から受け取ります。ゼロ以外の値で終了させると、これらはすべて却下されます。 このフックを使うと、更新内容がすべてfast-forwardであることをチェックしたり、プッシュによって変更されるファイルや参照に対するアクセス制御を行ったりできます。
update フック
update スクリプトは pre-receive スクリプトと似ていますが、プッシュしてきた人が更新しようとしているブランチごとに実行されるという点が異なります。 複数のブランチへのプッシュがあったときに pre-receive が実行されるのは一度だけですが、update はブランチ単位でそれぞれ一度ずつ実行されます。 このスクリプトは、標準入力を読み込むのではなく三つの引数を受け取ります。参照 (ブランチ) の名前、プッシュ前を指す参照の SHA-1、そしてプッシュしようとしている参照の SHA-1 です。 update スクリプトをゼロ以外で終了させると、その参照のみが却下されます。それ以外の参照はそのまま更新を続行します。
post-receive フック
post-receive フックは処理が終了した後で実行されるもので、他のサービスの更新やユーザーへの通知などに使えます。 このフックは、 pre-receive フックと同じデータを標準入力から受け取ります。 サンプルのスクリプトには、リストをメールしたり、継続的インテグレーションサーバーへ通知したり、チケット追跡システムを更新したりといった処理が含まれています。コミットメッセージを解析して、チケットのオープン・修正・クローズなどの必要性を調べることもできます。 このスクリプトではプッシュの処理を中断させることはできませんが、クライアント側ではこのスクリプトが終了するまで接続を切断できません。このスクリプトで時間のかかる処理をさせるときには十分注意しましょう。