Huskyとlint-stagedでコミット前のフォーマット崩れと構文エラーを防ぐ環境構築
目次
開閉
「PR(プルリクエスト)の変更差分を開いたら、半分がインデントや改行の修正だけだった……」
チーム開発において、コードの記述スタイルやフォーマットの表記揺れはレビューの集中力を削ぎ、本来議論すべきロジックの確認を遅らせる原因になります。どれほど注意を払っていても、個人のエディタ設定の違いや保存時フォーマットの漏れによって、不揃いなコードがリポジトリに紛れ込んでしまうのは珍しくありません。
今回は、Gitのコミット直前に自動でフォーマッターやリンターを割り込ませる Husky + lint-staged の導入手順を解説します。「ステージングされた変更ファイルだけ」を対象に自動修正するため、コミットのテンポを損なわずに安定したコード品質を維持できます。
検証環境と使用ツール
本記事で解説する構成と動作確認バージョンは以下の通りです。
- Node.js: v20.x LTS / v22.x
- Husky: v9.1.x(Husky 公式ドキュメント)
- lint-staged: v15.2.x(lint-staged 公式リポジトリ)
- Prettier: v3.x
- ESLint: v9.x(Flat Config対応)
※Huskyはv9以降で設計が大幅に簡素化され、従来の .husky/_/husky.sh といったランタイムスクリプトの管理が不要になりました。
なぜ「CI環境でのチェック」だけでは不十分なのか?
GitHub ActionsなどのCIで npm run lint やテストを実行してエラーを弾く運用も一般的です。しかし、CIでエラーが出ると「コミット push → 数分後にCI失敗通知 → ローカルで修正 → 再度コミット push」という無駄な待ち時間と往復が発生してしまいます。
手元のローカル環境で git commit を実行したその瞬間に自動修正・構文チェックを行うことで、不完全なコードがリポジトリへ混入するのを未然に防ぐことができます。
Huskyとlint-stagedの協調動作
全ファイルを対象に毎回チェックを実行すると、プロジェクトの成長に伴ってコミットにかかる時間が延びてしまいます。lint-staged を組み合わせることで、「今回コミット対象としてステージングされたファイル」のみを高速に処理できます。
graph TD
A["エンジニアが git commit を実行"] --> B["Husky の pre-commit フックが発火"]
B --> C["lint-staged 起動"]
C --> D["ステージングされたファイル (.js/.ts/.json等) を抽出"]
D --> E["Prettier によるコード自動フォーマット"]
E --> F["ESLint による構文・規約チェック"]
F --> G{"エラーや修正不可能な違反はあるか?"}
G -- "問題なし (または自動修正完了)" --> H["コミット成功・リポジトリ保存"]
G -- "致命的エラーあり" --> I["コミット中断 & ターミナルへ詳細出力"]導入・設定手順(モダンJS/TS環境対応)
TypeScript / JavaScript プロジェクトにおける導入ステップです。
1. パッケージのインストール
開発依存(devDependencies)として必要なパッケージを追加します。
npm install -D husky lint-staged prettier eslint2. Huskyの初期化
以下のコマンドを実行すると、リポジトリ内に .husky/ ディレクトリが生成され、Gitフックが有効化されます。
npx husky init
実行後、package.json の scripts に "prepare": "husky" が自動追記されます。これにより、他の開発者がリポジトリをクローンして npm install を実行した際にも、自動的にGitフックが有効化されます。
3. .husky/pre-commit の編集
自動生成された .husky/pre-commit ファイルを開き、実行コマンドを npx lint-staged に書き換えます。
npx lint-staged4. package.json に lint-staged のルールを設定
コミット対象の拡張子に応じて実行するコマンドを指定します。
{
"name": "my-project",
"version": "1.0.0",
"scripts": {
"prepare": "husky"
},
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
"prettier --write",
"eslint --fix"
],
"*.{json,css,scss,md}": [
"prettier --write"
]
}
}実機での動作確認とターミナル出力ログ
設定が完了したら、実際にステージングしてコミットを試してみましょう。
正常系:自動修正とコミット成功
コードを修正してステージングし、コミットを実行すると、lint-staged が対象ファイルを抽出して自動整形を行います。
$ git add src/components/UserProfile.tsx
$ git commit -m "feat: ユーザープロファイル表示コンポーネントを追加"
✔ Preparing lint-staged...
✔ Running tasks for staged files...
❯ src/components/UserProfile.tsx — 1 file
✔ prettier --write
✔ eslint --fix
✔ Applying modifications to index...
✔ Cleaning up temporary files...
[main a1b2c3d] feat: ユーザープロファイル表示コンポーネントを追加
1 file changed, 38 insertions(+)
PrettierやESLintの --fix によって自動修正されたコード差分は、lint-staged が自動でGitのインデックス(ステージング)に再反映してコミットに含めてくれます。手動で再度 git add し直す必要はありません。
異常系:自動修正不可能なエラーでコミットがブロックされる場合
型エラーや未定義変数の参照など、自動修正できない重大なエラーが残っている場合は、コミット処理が安全に中断されます。
$ git commit -m "fix: データ変換処理の修正"
✔ Preparing lint-staged...
❯ Running tasks for staged files...
❯ src/utils/format.ts — 1 file
✔ prettier --write
✖ eslint --fix [FAILED]
✖ eslint --fix:
/path/to/project/src/utils/format.ts
14:7 error 'transformedData' is assigned a value but never used @typescript-eslint/no-unused-vars
✖ 1 problem (1 error, 0 warnings)
husky - pre-commit script failed (code 1)
ターミナル上に問題のファイルと行番号、違反内容が明確に出力され、コミットは作成されません。エラーを解消して再度コミットを実行すれば、正常に完了します。
現場でハマりやすい注意点とOS差異
実務でクロスプラットフォーム開発を行う際、いくつか知っておくべきポイントがあります。
Windows環境における改行コード(CRLF)問題
筆者は業務でMacBook Pro、自宅でWindowsマシンを併用していますが、WindowsでGitフックを扱う際に最も遭遇しやすいのが「改行コードの混入」です。
Windows環境でエディタやGitの自動変換(core.autocrlf)によって .husky/pre-commit の改行コードが CRLF(\r\n)になってしまうと、macOS / Linux や CI環境、WSLでコミットを実行した際に以下のエラーが発生することがあります。
/bin/sh^M: bad interpreter: No such file or directory
husky - pre-commit script failed (code 127)
これを防ぐため、プロジェクトルートの .gitattributes ファイルに以下の設定を追加し、フック用スクリプトの改行コードを常に LF で固定しておくことを推奨します。
# Huskyフックスクリプトの改行コードをLFに固定
.husky/* text eol=lf緊急時のフック回避オプション(--no-verify)の運用
作業途中のコードを一時的に別ブランチへ退避(WIPコミット)したい場合など、どうしてもリンターチェックをスキップしたいケースがあります。その際は --no-verify(または -n)フラグを付与することでフックをバイパスできます。
git commit -m "WIP: 作業途中の一時退避" --no-verify
ただし、これを常用するとCIでテストが落ちたりフォーマット崩れが本番コードに混ざったりするため、「一時退避用ブランチでの作業に限定する」といったチーム内での運用ルールを決めておくことが大切です。
導入によって得られる実務メリット
- レビューでの形式的指摘の削減 インデントのズレやセミコロンの有無といった表記上の問題に関する指摘がほぼゼロになり、設計やビジネスロジックの議論にレビュー時間を集中できます。
- フォーマット修正コミットの撲滅 「Fix format」「Re-format」のような無駄なコミット履歴がリポジトリに残らず、コミットログが綺麗に保たれます。
- 作業途中の差分保護
lint-stagedはステージングされていない未追跡の変更差分を安全に一時退避(stash)した上で検証を行うため、git add -pなどで部分的にコミットしたい場合でも安全に動作します。
まとめ:スタイルの担保はツールに任せる
コードのフォーマットや構文規約を人間同士でチェックし合うのは、精神的にも時間的にもコストが高い作業です。
Husky と lint-staged を組み合わせることで、開発者は実装そのものに集中しつつ、リポジトリの健全性を自動的に維持できます。初期セットアップも短時間で完了するため、プロジェクトの立ち上げ時にあらかじめ組み込んでおくことをおすすめします。
コミット前の自動検証と合わせて、コミット履歴自体を綺麗に整えてレビュー負荷を下げるGitのテクニックについては以下の記事でまとめています。