2026年1月24日 Tech

lefthookで実現する高速なpre-commit hook

lefthookで実現する高速なpre-commit hook

コミット前に自動でlint・format・型チェックを実行し、品質の低いコードがリポジトリに混入するのを防ぐ。それがpre-commit hookである。


なぜこれを学ぶのか

チーム開発では、コードの品質を一定に保つことが重要である。しかし、人間は忘れる。「npm run lint」を実行し忘れてコミットしてしまうことは珍しくない。

pre-commit hookを導入すれば、コミット前に自動でチェックが走る。人間が忘れても、機械が忘れない。


pre-commit hookとは

Gitには「hook」という仕組みがある。特定のタイミングで自動的にスクリプトを実行できる機能である。

hook名 実行タイミング 用途
pre-commit コミット前 lint、format、型チェック
pre-push プッシュ前 ビルド確認、テスト
commit-msg コミットメッセージ作成後 メッセージ形式のチェック

pre-commit hookでチェックに失敗すると、コミットがキャンセルされる。問題のあるコードがリポジトリに入ることを防げる。


なぜlefthookを選ぶのか

Git hook管理ツールはいくつかある。

ツール 特徴
Husky 定番。npmエコシステムで広く使われている
lefthook 高速・軽量。設定がシンプル
simple-git-hooks 最小構成。機能は限定的
.git/hooks直接 依存なし。チーム共有が面倒

lefthookを選ぶ理由は以下の通り。

観点 lefthook Husky
速度 高速(Go製) 普通
設定 YAMLで簡潔 複数ファイルが必要
lint-staged 内蔵 別途インストール
依存 単体で完結 lint-stagedが別途必要

環境

項目 バージョン
Node.js 20.x
lefthook 2.x
ESLint 9.x
Prettier 3.x
TypeScript 5.x

インストール

npm install -D lefthook prettier

lefthookをインストールしたら、Git hookを有効化する。

npx lefthook install

このコマンドで .git/hooks/ にスクリプトが生成される。


設定ファイル

プロジェクトルートに lefthook.yml を作成する。

# lefthook.yml

pre-commit:
  parallel: true
  commands:
    lint:
      glob: "*.{js,ts,jsx,tsx}"
      run: npx eslint {staged_files} --fix
      stage_fixed: true
    typecheck:
      run: npx tsc --noEmit
    format:
      glob: "*.{js,ts,jsx,tsx,json,css,md}"
      run: npx prettier --write {staged_files}
      stage_fixed: true

pre-push:
  commands:
    build:
      run: npm run build

設定の解説

項目 説明
parallel: true 各コマンドを並列実行。高速化に寄与
glob 対象ファイルのパターン。マッチしたファイルのみ処理
{staged_files} ステージングされたファイルのみを対象にする変数
stage_fixed: true 自動修正されたファイルを再ステージング

pre-commitで実行する内容

コマンド 目的
lint ESLintでコード品質をチェック。自動修正も行う
typecheck TypeScriptの型エラーをチェック
format Prettierでコードフォーマット

pre-pushで実行する内容

コマンド 目的
build ビルドが通るか確認。壊れたコードをpushしない

Prettier設定

.prettierrc を作成する。

{
  "semi": true,
  "singleQuote": false,
  "tabWidth": 2,
  "trailingComma": "es5",
  "printWidth": 80
}

.prettierignore も作成する。

node_modules
.next
out
build
storybook-static
*.log
.env*

package.jsonの設定

他の開発者がリポジトリをクローンしたときに自動でhookが有効になるよう、prepareスクリプトを追加する。

{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "lint": "eslint",
    "lint:fix": "eslint --fix",
    "format": "prettier --write .",
    "format:check": "prettier --check .",
    "typecheck": "tsc --noEmit",
    "prepare": "lefthook install"
  }
}

prepareはnpm installの後に自動実行される。これにより、チームメンバーがリポジトリをクローンしてnpm installするだけで、hookが有効になる。


動作確認

コミットしてみると、lefthookが動作する。

git add .
git commit -m "test commit"

以下のような出力が表示される。

╭───────────────────────────────────────╮
│ 🥊 lefthook v2.0.15  hook: pre-commit │
╰───────────────────────────────────────╯

  ────────────────────────────────────
summary: (done in 3.06 seconds)
✔️ format (1.16 seconds)
✔️ typecheck (2.10 seconds)
✔️ lint (3.01 seconds)

すべてのチェックが通ればコミットが完了する。失敗するとコミットがキャンセルされる。


エラー時の挙動

lintエラーがあると、以下のように表示される。

╭───────────────────────────────────────╮
│ 🥊 lefthook v2.0.15  hook: pre-commit │
╰───────────────────────────────────────╯

  ────────────────────────────────────
summary: (done in 2.50 seconds)
✔️ format (0.98 seconds)
✔️ typecheck (1.80 seconds)
❌ lint (2.50 seconds)

  src/app/page.tsx
    10:5  error  'unused' is defined but never used  @typescript-eslint/no-unused-vars

エラーを修正してから再度コミットする必要がある。


hookをスキップする方法

緊急時など、hookをスキップしたい場合は --no-verify オプションを使う。

git commit --no-verify -m "emergency fix"

ただし、これは最終手段である。チームで運用する場合は、hookをスキップする理由を明確にすべきである。


なぜpre-pushでビルド確認をするのか

pre-commitではなくpre-pushでビルド確認を行う理由は、速度と頻度のバランスである。

hook 頻度 許容時間
pre-commit 高い(1日に何度も) 数秒〜10秒程度
pre-push 低い(1日に数回) 数十秒〜数分

ビルドは時間がかかることが多い。毎コミットで実行すると開発体験が悪化する。pushの前に1回だけ確認すれば十分である。


CI/CDとの役割分担

pre-commit hookとCI/CDは補完関係にある。

項目 pre-commit hook CI/CD
実行場所 ローカル サーバー
目的 早期フィードバック 最終ゲートキーパー
スキップ可能 --no-verifyで可能 不可(設定による)
対象 ステージングされたファイル 全ファイル

pre-commit hookは「開発者への早期フィードバック」が目的である。CI/CDは「リポジトリへの最終的な品質保証」が目的である。

理想的な構成は以下の通り。

flowchart LR A["コード変更"] --> B["pre-commit
(lint, format, typecheck)"] B --> C["commit"] C --> D["pre-push
(build)"] D --> E["push"] E --> F["CI/CD
(lint, test, build, deploy)"]

まとめ

  • pre-commit hookは、コミット前に自動でコード品質をチェックする仕組み
  • lefthookはHuskyより高速で、設定がシンプル
  • lint-stagedの機能が内蔵されており、ステージングされたファイルのみを対象にできる
  • pre-commitでlint・format・typecheckを実行し、pre-pushでビルド確認を行う
  • CI/CDと組み合わせることで、多層的な品質保証が実現できる

用語

用語 説明
Git hook Gitの特定のイベント(commit, pushなど)で自動実行されるスクリプト
pre-commit コミット前に実行されるhook
pre-push プッシュ前に実行されるhook
lint コードの品質や一貫性をチェックするツール
format コードの書式を統一するツール
staged files git addでステージングされたファイル

Git #lefthook #pre-commit #開発環境 #コード品質

目次