Secret Staircase

モノレポで変更のあったプロジェクトにだけ git のフックを適用する

Jan 29, 2021

モノレポでを変更のあったプロジェクトだけに git のフックを適用するツールを作りました。

https://github.com/akr4/git-hooks-dispatch

モノレポで git のフックを使うのはなかなかやっかいです。フックは git リポジトリ単位で設定するため、フックに複数プロジェクトの処理を書くことになったり、husky (JavaScript 製フック管理ツール)を使ってフックを管理しようとすると別のプロジェクトのためのフックが上書きされてしまったりします。コミットするときに全然変更してないプロジェクトのフックが動いても困りますよね。

そうした問題はたとえば lint-staged を使うことで解決できます。しかしながら lint-staged の設定はプロジェクトをセットアップする人には難しくありませんが、他の人にとっては謎の仕組みになってしまってメンテナンスが難しくなりがちな傾向があります。JavaScript になじみのない人にはとっつきにくいかもしれません。

git-hooks-dispatch はこの問題をわかりやすい方法で解決します。

  • 変更のあったプロジェクトにだけフックを適用
  • プロジェクトごとに完結した、見通しの良いフック設定

どんなふうに動く?

pre-commit フックを例にあげて説明しましょう。こんな感じで project1project2 の 2 つのプロジェクトを含むモノレポがあったとします。

.
├── .git
│  └── hooks
│     └── pre-commit
├── project1
│  ├── foo.txt
│  └── git-hooks
│     └── pre-commit
└── project2
   └── git-hooks
      └── pre-commit

大元のフックの設定には git-hooks-dispatch を設定します。たとえば .git/hooks/pre-commit はこうなります。

.git/hooks/pre-commit

#!/bin/sh
git-hooks-dispatch $(basename $0) -- "$@"

macOS や Linux なら何も変更の必要はありません。このままコピペで設定してください。

次に、フックを設定したいプロジェクトのルートディレクトリの git-hooks にフックを置きます。(ディレクトリ名は変更できます)

project1/git-hooks/pre-commit

#!/bin/sh
npm run lint-staged

内容は本来実行したい処理を書きます。git の普通のフックですね。

これで project1 に変更があったときだけフックが実行されるようになります。

project1/foo.txt が変更されている場合は project1/git-hooks/pre-commit が動きます。project2 の方は実行されません。

まとめ

いかがですか?簡単な設定でプロジェクトごとにフック定義がわかれるので見通しが良いですよね?

PR や機能のご提案、不具合報告は大歓迎です。お気軽にご連絡ください 😀