背景:深夜2時のCI/CDトラブル
深夜2時、Slackの通知が鳴り止みませんでした。本番環境のビルドパイプラインがエラーで停止したのです。原因は意外なものでした。チームのある開発者がWindowsマシンでGoのコードをプッシュした際、リンターの実行を忘れていました。本来、こうしたエラーはGit Hooksを使ってローカル環境で事前に阻止すべきものです。
以前は、Huskyを愛用していました。しかし、プロジェクトがPython、Go、Rustを含むモノレポ(Monorepo)へと拡大するにつれ、問題が発生しました。バックエンドエンジニアに、Git Hookを動かすためだけにNode.jsをインストールさせるのは不合理な要求です。さらに、Huskyは逐次実行(シリアル実行)のため、非常に低速です。大規模なコミットでは、リンターの完了を待つのに30秒以上かかることもあり、その待ち時間のせいで集中力が切れ、誤ってgit push --forceという悲惨なコマンドを叩いてしまうこともありました。
そこで出会ったのがLefthookです。Goで書かれたLefthookは単一のバイナリファイルで動作し、非常に軽量で、Node.js環境に依存しません。
Lefthookのインストール:あらゆるワークフローに柔軟に対応
Lefthookは環境を選びません。プロジェクトに合わせて、いくつかの方法で導入できます。
方法1:Node.jsプロジェクトの場合
npm install lefthook --save-dev
# または
yarn add -D lefthook
方法2:スタンドアロンでのインストール(Go、Python、Rustなど)
プロジェクトでpackage.jsonを使用していない場合は、システムに直接インストールします:
# macOS (Homebrew)
brew install lefthook
# Go経由でインストール
go install github.com/evilmartians/lefthook@latest
インストール後、lefthook installコマンドで初期化します。プロジェクトのルートディレクトリにlefthook.ymlファイルが作成されます。ここでコミットプロセス全体を管理します。
設定:並列実行による真のパワー
Lefthookの最大の魅力は、YAMLによる極めて明快な設定ファイルです。以下は、JSのリンターチェックとGoのコードフォーマットを同時に実行するための設定例です:
# lefthook.yml
pre-commit:
parallel: true # 時間短縮のためコマンドを並列実行
commands:
linter-js:
glob: "*.{js,ts,tsx}" # 変更されたファイルのみをフィルタリング
run: npx eslint {staged_files} --fix
formatter-go:
root: "backend/"
glob: "*.go"
run: go fmt {staged_files} && git add {staged_files}
check-secret:
run: gitleaks detect --source . --verbose
なぜこの設定がHuskyより優れているのか?
- parallel: true: Huskyは各コマンドを1つずつ実行しますが、LefthookはCPUを最大限に活用して並列実行します。5つのタスクがある場合、待ち時間は30秒から5〜7秒程度に短縮されます。
- {staged_files}: プロジェクト全体をスキャンする代わりに、Lefthookは
git addされたファイルのリストのみをコマンドに渡します。これにより、処理速度が飛躍的に向上します。 - globフィルタ: ファイル形式ごとに実行するリンターを正確に指定できるため、リソースの無駄を省けます。
実践的なシチュエーションへの対応
緊急の修正(ホットフィックス)が必要で、軽微なスタイルエラーのチェックを待ちたくないこともあるでしょう。
プロフェッショナルなHookのスキップ方法
安全性の低い--no-verifyフラグを使う代わりに、Lefthookでは環境変数を使って特定のコマンドをスキップできます:
LEFTHOOK=0 git commit -m "緊急の修正"
または、確信がある場合に限り、シークレットチェックのみをスキップすることも可能です:
SKIP=check-secret git commit -m "一時的なコミット"
チーム全員が確実に実行するようにする
同僚がHookのインストールを「忘れる」のを防ぐために、package.jsonに以下のスクリプトを追加しましょう:
{
"scripts": {
"postinstall": "lefthook install"
}
}
npm installを実行するたびに、Lefthookが自動的に.git/hooks内のHookを再設定します。これで、サーバーにプッシュする前のコードチェックを誰も「回避」できなくなります。
実戦経験:シークレット漏洩で損失を出さないために
設定はいつでもlefthook run pre-commitコマンドでテストできます。このコマンドはコミットプロセスをシミュレートし、詳細なログを出力します。エラーが発生した場合、Lefthookは雑多なログを出すのではなく、どのコマンドが失敗したかを明確に示してくれます。
私自身の苦い経験から得た教訓です。常にpre-commitステップにgitleaksを組み込んでください。以前、誤ってAWSのシークレットキーをGitHubにプッシュしてしまい、わずか5分後にAmazonから警告を受けたことがあります。それ以来、私のすべてのプロジェクトでcheck-secretは必須のステップとなっています。
結論
Huskyは純粋なJavaScriptの小規模プロジェクトには依然として適しています。しかし、速度、モノレポへの柔軟な対応、そして多人数チームでの安定性を求めるなら、Lefthookは代替不可能な選択肢です。移行にかかる時間はわずか15分ですが、それによって何時間もの待ち時間を節約し、不必要なビルド失敗を未然に防ぐことができます。

