Gitフック「Lefthookの勝ちデース」:マルチ言語・マルチリポジトリ環境におけるHusky vs Lefthook徹底比較
おはようございます、こんにちは、こんばんは。
スペースマーケットでWebエンジニアをしています、s0arです。
タイトルがオチなんですけど一旦全部読んでください。
個人開発のプロジェクトでGitフックの管理しようとして、Claude Codeに聞いたら「Lefthookがええやで~」って言われました。
ほな使ってみるやで~ってことで、せっかくだから、俺はこのメモを書くぜ!
この記事 is 何
Gitフックマネージャーとして広く使われているHuskyと、マルチ言語環境に強いLefthookを比較します。
結論から言うと、マルチ言語・マルチリポジトリ環境ではLefthookの勝ちデース
「え、Huskyでええやん」って思う人もいるかもしれへん。
Rails、iOS、Android、Flutterのリポジトリにもpackage.jsonを追加する覚悟があるなら無理にとは言わん。
お前がそう思うんやったらそうなんやろ、ワイは嫌やけど(変則関西式島)
前提:どんな環境を想定しているか
この記事では以下のような環境を想定しています:
- 複数の独立したリポジトリ(モノレポではない)
- 多様な技術スタック(Rails、NestJS、Next.js、iOS、Android、Flutter)
- チーム全体でコード品質を統一したい
- パフォーマンスとセットアップの容易さを重視
Huskyしか勝たんという皆様、それで全然OK。ブラウザバックしてOKデース。
でも数日後、ここに戻ってきてください、きっとHuskyのここがすごい!的な反論記事が書かれているでしょう。
(私の手によって)(見事なマッチポンプ)
逆にちょっとでも「ぼ、僕にできるかなぁ?」と思った方はこのメモの通りにすれば勝てマース。
言語・フレームワーク非依存性:最も重要な判断基準
複数の技術スタックを持つ環境において、この観点が最も重要な判断基準になります。
| リポジトリ | Node.js環境 | Husky | Lefthook |
|---|---|---|---|
| Ruby on Rails | なし(通常) | npm/package.json必須 | gem install lefthook |
| NestJS | あり | 利用可 | npm経由で利用可 |
| Next.js | あり | 利用可 | npm経由で利用可 |
| iOS (Swift) | なし | npm/package.json必須 | brew install lefthook |
| Android (Kotlin) | なし | npm/package.json必須 | brew/aptで利用可 |
| Flutter | なし(通常) | npm/package.json必須 | brew/aptで利用可 |
Huskyの根本的な問題点は、インストールと実行にNode.js環境が必須である点です。
これ、何が困るかって言うと:
- RailsプロジェクトにJavaScriptの依存関係が混入する(なんか…嫌やん…)
- iOS/Android開発者にNode.jsのインストールを強制する(モバイルエンジニアさんキレない?大丈夫そ?)
- 各リポジトリで異なるランタイム要件が発生する(這い寄る混沌)
一方、Lefthookは各言語のエコシステムに自然に統合できます:
# Ruby開発者(Railsリポジトリ)
gem install lefthook
# Node.js開発者(NestJS/Next.jsリポジトリ)
npm install lefthook --save-dev
# iOS開発者(Swiftリポジトリ)
brew install lefthook
# Android開発者(Kotlinリポジトリ)
brew install lefthook # または apt install lefthook
# Flutter開発者
brew install lefthook
はえ〜、インストール方法が選べるの便利杉内
てかもうbrewだけでいいんじゃないかな
パフォーマンス比較:Lefthookが圧倒的優位
パフォーマンスの差は実測データで明確に示されています。
5つの並列タスク実行において、Lefthookは約1秒で完了するのに対し、逐次実行のHuskyは約5.15秒を要しました。
| 指標 | Husky | Lefthook |
|---|---|---|
| 実行方式 | 逐次実行(bash経由) | 並列実行(ネイティブ) |
| 依存関係 | lint-staged併用で約1,500パッケージ追加 | 単一バイナリ、依存なし |
| 起動時間 | shell初期化が必要 | 即時起動 |
Huskyの5倍速い
どっかの赤いやつでも3倍やからね?
Lefthookの並列実行は設定で簡単に有効化できます:
pre-commit:
parallel: true # これだけで並列実行が有効に
commands:
lint:
run: yarn lint
test:
run: yarn test
parallel: trueを1行追加するだけ。簡単すぎて涙そうそう。
セットアップと設定管理
両ツールとも初期セットアップは数分で完了しますが、複数リポジトリ運用においてLefthookの統一フォーマットが大きな利点となります。
Huskyのアプローチ
.husky/ディレクトリ内に個別のシェルスクリプトを配置する方式です。フックが増えるとファイル数も増加します:
# Huskyセットアップ(Node.jsリポジトリのみ)
npm install --save-dev husky
npx husky init
# .husky/pre-commit, .husky/pre-push等のファイルを個別作成
Lefthookのアプローチ
単一のYAMLファイルで全フックを一元管理します。どの言語のリポジトリでも同じlefthook.ymlという構造で設定できます:
# lefthook.yml - 全設定がここに集約
pre-commit:
parallel: true
commands:
lint:
glob: "*.{ts,tsx}"
run: yarn eslint {staged_files}
format:
run: yarn prettier --write {staged_files}
stage_fixed: true
pre-push:
commands:
test:
run: yarn test
設定ファイルが1つにまとまってるの、管理しやすくてグーなのです。
各言語向け設定テンプレート
複数リポジトリ運用では、言語ごとのテンプレートを用意することで導入がスムーズになります。
Ruby on Rails用
# lefthook.yml
pre-commit:
parallel: true
commands:
rubocop:
glob: "*.rb"
run: bundle exec rubocop -A {staged_files}
stage_fixed: true
erb-lint:
glob: "*.erb"
run: bundle exec erblint {staged_files}
pre-push:
commands:
rspec:
run: bundle exec rspec
NestJS / Next.js用
# lefthook.yml
pre-commit:
parallel: true
commands:
eslint:
glob: "*.{ts,tsx,js,jsx}"
run: yarn eslint --fix {staged_files}
stage_fixed: true
prettier:
glob: "*.{ts,tsx,js,jsx,json,md}"
run: yarn prettier --write {staged_files}
stage_fixed: true
typecheck:
run: yarn tsc --noEmit
pre-push:
commands:
test:
run: yarn test
iOS (Swift)用
# lefthook.yml
pre-commit:
parallel: true
commands:
swiftlint:
glob: "*.swift"
run: swiftlint --fix {staged_files}
stage_fixed: true
swiftformat:
glob: "*.swift"
run: swiftformat {staged_files}
stage_fixed: true
Android (Kotlin)用
# lefthook.yml
pre-commit:
parallel: true
commands:
ktlint:
glob: "*.kt"
run: ktlint -F {staged_files}
stage_fixed: true
detekt:
glob: "*.kt"
run: ./gradlew detekt
Flutter用
# lefthook.yml
pre-commit:
parallel: true
commands:
format:
glob: "*.dart"
run: dart format {staged_files}
stage_fixed: true
analyze:
run: flutter analyze
pre-push:
commands:
test:
run: flutter test
どの言語でもlefthook.ymlという同じ形式で設定できるの、チーム全体で一貫性が保ててグーなのです。
チーム利用:リモート設定継承
複数リポジトリ構成で特に有効なのが、Lefthookのリモート設定継承機能です。
共通のフック設定を専用リポジトリで管理し、各プロジェクトから参照できます:
# 各リポジトリのlefthook.yml
remotes:
- git_url: https://github.com/your-company/shared-hooks
ref: main
configs:
- common.yml # 共通ルール
- rails.yml # Rails固有(必要に応じて)
# ローカル設定で上書き・追加も可能
pre-commit:
commands:
project-specific:
run: ./scripts/custom-check.sh
shared-hooksリポジトリの構成例:
shared-hooks/
├── common.yml # commit-msg検証など共通ルール
├── rails.yml # Rubocop等のRails向け設定
├── typescript.yml # ESLint/Prettier等のTS向け設定
├── swift.yml # SwiftLint等のiOS向け設定
├── kotlin.yml # ktlint等のAndroid向け設定
└── flutter.yml # dart format等のFlutter向け設定
これ、チーム全体で一貫したコード品質基準を維持しながら、各プロジェクト固有の設定も柔軟に追加できるんですよね。爆アド。
ローカルオーバーライドも可能で、個人の開発環境でのみ特定のフックをスキップしたい場合に便利です:
# lefthook-local.yml(.gitignore対象)
pre-commit:
exclude_tags:
- slow-tests
その他の比較ポイント
lint-stagedとの関係
Huskyはlint-stagedとの併用が事実上の標準となっています。
一方、Lefthookは{staged_files}やglobによる組み込みのファイルフィルタリングがあり、lint-staged不要です。
# Lefthookなら組み込みでステージングファイル対応
commands:
lint:
glob: "*.ts"
run: eslint {staged_files}
lint-staged分の依存が減るの、地味にうれC。
コミュニティ規模
ドキュメントとコミュニティの規模ではHuskyが優位です。
週間ダウンロード数はHusky: 約1,900万、Lefthook: 約71万と大きな差があります。
ただし、Lefthookは Evil Martians による積極的なメンテナンスが継続しており、Discourse、GitLab、Yandexなどの大規模プロジェクトでの採用実績もあります。
GitLabが使ってるなら安心感は、ありまぁす!
クロスプラットフォーム対応
両ツールともWindows/Mac/Linuxをサポートしていますが、Lefthookはプラットフォーム別のネイティブバイナリを提供するため、より安定した動作が期待できます。
まとめ
| 要件 | Husky | Lefthook | 勝者 |
|---|---|---|---|
| 複数リポジトリ構成 | Node.js必須 | 言語別インストール可 | Lefthook |
| パフォーマンス | 逐次実行 | 並列実行 | Lefthook |
| セットアップ容易性 | Node.jsリポジトリのみ | 全言語で統一フォーマット | Lefthook |
| フレームワーク非依存 | Node.js依存 | 完全非依存 | Lefthook |
| チーム利用 | 大きなコミュニティ | リモート設定共有 | Lefthook |
マルチ言語・マルチリポジトリ環境では、Lefthookが唯一の現実的な選択肢です。
いや、流石に過言かも?
でも、Huskyを選んだ場合、Rails/iOS/Android/Flutterの各リポジトリにpackage.jsonを追加して、開発者全員にNode.jsのインストールを強制することになります。
それはちょっと…ほら…ねえ…
推奨する導入アプローチ
- 共通フック設定を管理する専用リポジトリを作成
- 各言語向けのテンプレート(上記参照)を用意
- 各リポジトリでLefthookをインストールし、リモート設定を継承
- プロジェクト固有の設定はローカルで追加
この構成により、チーム全体で一貫したコード品質を維持しながら、各技術スタックの特性に合わせた柔軟な運用が可能!たぶんおそらくmaybe
Lefthook、良さげじゃんね?
以上終わりです。
参考リンク
スペースを簡単に貸し借りできるサービス「スペースマーケット」のエンジニアによる公式ブログです。 弊社採用技術スタックはこちら -> whatweuse.dev/company/spacemarket
Discussion