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