概要
この記事ではgitのcommit時(コミットメッセージの入力前)に自動でlinterなどを実行するpre-commitフックの実装方法について解説します。
コミット前(pre-commit)のタイミングでコードのスタイルチェックやlinter、テストの実行を挟むことで、これらのチェックを通っていないコードをうっかりコミットしてしまうことを避けることができ、コードの品質を保つことにもつながります。
毎回手動でこれらのチェックツールを実行するのは面倒で忘れがちなので、pre-commitで自動で実行されるように設定しておくと便利です。
Git自体にフックという機能があり、それを活用することでコミット前に特定のスクリプトを実行することができます。
まずはGitにどのようなフックが用意されているのかざっと確認しておきましょう。
gitがcommit時に提供している4つのフック
以下4つがcommit時に用意されているフックです。
興味のある方はこちらの公式ドキュメントも参照してみてください。
フックのタイミングによって用途が異なるので、実現したいことに合わせてどのフックで実行するか検討しましょう。
なお、この記事で紹介するのはpre-commitフックになります。
pre-commitフック
- 実行タイミング
- コミットメッセージが入力される前にスクリプトが実行されます。
- 用途
- コードのスタイルチェック、リント(lint)チェック、ユニットテストの実行など。
- 実行したスクリプトが(0以外のステータスを返す)とコミットは中止されます。
prepare-commit-msgフック
- 実行タイミング
- コミットエディタが表示される直前にスクリプトが実行されます。
- 用途
- デフォルトのメッセージを設定したり、コミットメッセージのフォーマットを強制したりするために使用されます。
commit-messageフック
- 実行タイミング
- コミットメッセージを入力した後でスクリプトが実行されます。
- 用途
- コミットメッセージを検証し、特定のフォーマットに従っていることを確認するために使用されます。
- 実行したスクリプトが(0以外のステータスを返す)とコミットは中止されます。
post-commitフック
- 実行タイミング
- コミットプロセスが全て完了した後でスクリプトが実行されます。
- 用途
- 一般的には通知の送信、デプロイのトリガーなど、コミット後に実行したい一連のアクションに使用されます。
- post-commitフックの終了ステータスは無視されます。
pre-commitの実装
gitのpre-commitフックに直接スクリプトを仕込むこともできますが、よく使うチェックに関してはpre-commitというツールを使うと自分でスクリプトを書くことなく簡単に実装することができます。
ここではこのpre-commitツールを使用してgoのformatter、linterを実行する例で手順を見ていきましょう。
このツール自体は特定の開発言語向けのツールではないので、go以外の言語で利用することも可能です。
pre-commitツールのインストール
まず上記で紹介したpre-commitのツールをインストールします。
ここではmacのbrewコマンドを使用してインストールしますが、他の環境でのインストールはこちらのドキュメントを参照してください。
https://pre-commit.com/#installation
以下のコマンドでpre-commitをインストールします。
$ brew install pre-commit
インストールが完了したらコマンドが実行できるか確認してみましょう。
$ pre-commit --version
pre-commit 3.3.3 # バージョンが表示される。
バージョン情報が表示されれば正しくインストールできています。
最後にpre-commit install
コマンドでpre-commitスクリプトを設置する必要があります。
$ pre-commit install
これを実行することで、.git/hooks/pre-commit
と言うファイルが作成されて、git commit
を実行した際にスクリプトが呼び出されるようになります。
このpre-commitツールのインストール作業は各開発者のPCで一度行う必要がありますので注意してください。
以降で紹介する.pre-commit-config.yamlを作成してもpre-commit install
が完了していないとpre-commitフックが動きませんので、各開発者の環境でセットアップしておくように伝えておきましょう。
.pre-commit-config.yamlファイルを作成する
インストールしたpre-commitのツールは、.pre-commit-config.yamlというファイルを自動で読み込んでコミット前のコマンドを実行します。
例えば、git commit実行時にgo fmt
、go vet
を実行したい場合のファイルは以下のようになります。
repos:
- repo: https://github.com/TekWizely/pre-commit-golang
rev: master
hooks:
- id: go-fmt
- id: go-vet
一つ一つの要素を確認していくと次のような意味があります。
- repos
- 複数のrepoを配下に定義できる。
- repo
- 使用するpre-commitフックのリポジトリを指定する。
- 例えば上記のpre-commit-golangの場合、予めgoに関するフックがリポジトリに定義されていて、その中から使用したフックを選んで実行できる。
repo: local
とすると任意のコマンドを実行することもできる。
- rev
- repoに指定したリポジトリで使用するブランチを指定する。
- hooks
- repoに定義されているhookで使用したいものを記載する。
- hookの指定は上記のファイルの通り、
id: <hook id>
のようにする。 - hook idはリポジトリのREADMEに記載されている。
- hookの指定は上記のファイルの通り、
- repoに定義されているhookで使用したいものを記載する。
このようなファイルを作成してプロジェクトのリポジトリに含んでおくことで、チームの開発者で共有して、pre-commit時のチェックを自動化することができます。
pre-commitの動作確認
セットアップが完了したら動作を確認してみましょう。
セットアップしたディレクトリ内で、適当なファイルをgit add
してからgit commit
を実行してみます。
$ touch test
$ git add test
$ git commit
go-fmt.............................(no files to check)Skipped
go-vet.............................(no files to check)Skipped
今回はチェック対象のファイルがないのでSkippedとなっていますが、go-fmt
、go-vet
のフックが実行されていることがメッセージからわかります。
まとめ
ここまでで説明しました通り、pre-commitを仕込むことで開発者が自身でコマンドを実行すること無くformatterやlinterの実行を強制することができます。
これらはCI上で実行するケースもあると思いますが、pre-commit時に実行することでコミットする前にエラーに気づいて早期に修正できるメリットがあります。
あまり重いチェックの場合はコミットに時間がかかるため取り入れづらいと思いますが、比較的軽いチェックであればコミット前にチェックできた方が都合が良いと思います。
ぜひ積極的に取り入れて開発体験を向上させてみてください。