🤔

git の pre-commit hook はなるべく使わないほうがいいのでは

2022/12/13に公開

※この記事の内容は https://nazo.hatenablog.com/entry/dont-use-pre-commit-hook と同一です。

git に pre-commit hook という、コミット直前に何かのプログラムを実行する機能があります。これを用いて lint や test を実行したりすることがありますが、この利用は極力避けたほうが良いのではと考えています。

なぜ?

  • 個人の環境で実行した結果は信用できない
  • ローカルコンピューターで待たせてはいけない
  • pre-commit の挙動や中断などで動作が怪しくなることがある

個人の環境で実行した結果は信用できない

全員が完全に同じ環境で pre-commit hook を実行しているかは誰にもわかりません。言語やライブラリのバージョンに差がある可能性もあります。また、hook をスキップする方法もあります。

それだけを信用してチェックを行ったと判断するのは危険であるため、CI で実行することを優先すべきです。

ローカルコンピューターで待たせてはいけない

チェック項目が増えると、hook の実行時間も増えます。

あくまで hook で行う処理の大半はガードレールなので、ちゃんと書いていれば一発通過するはずで、そのために毎回各自が待たされるのは無駄です。

チェック内容に自信がなければコミット前に手動実行すると思いますので、それでチェックが通っても pre-commit hook は実行され、さらに時間をかけてしまいます。

チェックに時間がかかりすぎるようになると、チェックを迂回するための策を考えてしまう可能性があります。

チェックが通る前提でコードを書き、素早く push して開発を効率化しましょう。

pre-commit の挙動や中断などで動作が怪しくなることがある

ライブラリの更新などで pre-commit hook がアップデートされた場合などや、極端にリビジョンに差があって pre-commit の挙動に差があるブランチに切り替えた場合などに、pre-commit スクリプトとライブラリが一致していない等でおかしな挙動をすることがあります。他にも様々な理由で予期せぬ結果を起こすことがあります。

git commit に機能を追加してしまうことで、 git commit 時に git commit 以外のことを考える必要が出てきます。

そんなこと言っても変なコードが push されたらどうするの?

CI で防げばいいです。そのための CI です。

CI と同等の動作を「任意で」ローカルで実行できることは必要ですが、最終判断はあくまで CI にやらせましょう。

CI で必ずチェックすることで、変なコードがマージされるのを確実に防ぐことができます。また、常に同じ環境である CI に実行させることによって、環境ごとで結果に違いが出るといった現象も防ぐことができます。

その割には有名なライブラリたくさんあるし使っている人もいっぱいいるよ!

Ruby の pre-commit gem や nodejs の Husky + lint-staged などがあり、特に nodejs 界隈ではボイラープレートに組み込まれていたりします。

どれも有名かつ人気があるので使うべきかと思いますが、「出来がよく実用しても問題ないから人気である」と「必ず使う必要がある」は全く関係がありません。これまでの理由により、基本的には使う必要はないものです。

どうしても忘れっぽい人やチェックする習慣がない初学者は任意で有効化して利用する、というのはありかもしれませんが、強制するものではないと思います。

リモートに push されること自体が望ましくないものを防ぐ場合は使って良いと思います。例えば git-secrets のようなものです。一般的な lint エラーやテストの失敗といったものはリモートに push されても何の問題もありません。誰もマージできないだけです。

まとめ

よほどの理由がない限り、pre-commit hookは使わないほうがいいと思ったほうが良いでしょう。各自の判断で手動実行 + 必ず CI でチェック、でほとんどの場合は十分です。絶対に使うなというわけではないですが、なぜ pre-commit hook を使う必要があるのか、何のために使うのかをよく考えて利用しましょう。

参考

https://www.thoughtworks.com/insights/blog/pre-commit-don-t-git-hooked

Discussion