Git hooks を使ってコミットのたびに go test してもらう
先に
ざっくり以下の手順でOKです。
1. Git hooks の参照先ディレクトリを変更する
git config --local core.hooksPath .githooks
2. pre-commitを書く
#!/bin/sh
# Run go test
output=$(go test -v ./...)
exit_code=$?
# Check if the test failed
if [ $exit_code -ne 0 ]; then
echo "go test failed:"
echo "$output"
exit 1 # Return Error Code
fi
# Output succeeded
echo "$output"
exit 0
3. pre-commitに実行権限を与える
chmod a+x ./.githooks/pre-commit
なにか書いてコミットしてみる
$ git add calc/num.go
vscode ➜ /workspace (main) $ git commit -m "multiplyを追加"
? go-unittest [no test files]
? go-unittest/calc [no test files]
[main 80d05b3] multiplyを追加
1 file changed, 5 insertions(+), 1 deletion(-)
$ git add calc/num_test.go
vscode ➜ /workspace (main) $ git commit -m "add num_test"
? go-unittest [no test files]
=== RUN TestAdd
--- PASS: TestAdd (0.00s)
PASS
ok go-unittest/calc (cached)
[main fbb1309] add num_test
1 file changed, 19 insertions(+)
create mode 100644 calc/num_test.go
git add calc/num_test.go
vscode ➜ /workspace (main) $ git commit -m "mod num_test"
go test failed:
? go-unittest [no test files]
=== RUN TestAdd
num_test.go:18:
Error Trace: /workspace/calc/num_test.go:18
Error: Not equal:
expected: 8
actual : 7
Test: TestAdd
--- FAIL: TestAdd (0.00s)
FAIL
FAIL go-unittest/calc 0.003s
FAIL
$ git status
On branch main
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: calc/num_test.go
テストにfailするとcommit処理が止まるため、直後のgit statusでcommitされていないことがわかります。
説明
今回の手順のポイントを説明します。
.git/hooksはgit管理できない
Git hooks の機能はデフォルトではそのリポジトリの.git/hooks下を参照するようになっています。お手元にリポジトリがあるなら見ていただければと思いますが、hooks以下にはサンプルとして各hookのサンプルコードが格納されているので、例えば./git/hooks/pre-commit.sampleを./git/hooks/pre-commitとリネームし、中身をよしなに編集すればそのまま使うことができます。
しかしながら、.gitディレクトリの内容はgit管理することができないため、このままでは実行したいスクリプトそのものをバージョン管理することができません。
そこでgit config --local core.hooksPath .githooksというコマンドを使うと、そのリポジトリにおけるGit hooksの格納先を.githooksに変更することができます。[1]
これにより、スクリプト本体もリポジトリに含めることができ、バージョン管理も行えるようになります。
終了コードで処理を切り分ける
go testの結果は$output、終了コードは特殊変数$?に格納されます。$?を検査してgo testが成功したかどうかをチェックし、failしていたらexit 1でスクリプトを終了するようにします。
Git hooksのpre-commitは、終了コードが0以外だった場合はコミット処理を中止する仕組みになっています。
作ったhooksには実行権限を与える
作成したスクリプトファイルはそのままでは実行権限がないので、事前に実行権限を与えておきます。これを行わないとGit hooksはスクリプトファイルを実行することができず、権限不足で実行できないことは特にcommit時にも出力されないようです。[2]
まとめ
以上です!
今回はGit hooksのpre-commitを使って、コミットのたびにgo testを実行させる環境を作ってみましたが、スクリプトの内容次第でさまざまなことが行えますので、他の言語や開発環境にも応用できそうです。
ではまた!
おまけ
VSCodeのCommitボタンでもちゃんと発動します。

「Open Git Log」や「Show Command Output」を押すと結果を確認することができます。
おまけ2
pre-commitをスルーしたい場合には--no-verifyオプションをつけてcommitしましょう。乱用は禁物です。
git commit -m "testしないでいったんコミット" --no-verify
Discussion