はじめに
「コードレビューでフォーマットの指摘ばかり受ける」「リント警告のあるコードがそのままコミットされてしまう」といった課題を抱えているチームは多いのではないでしょうか。
Git Hooksは、コミットやプッシュなどのGit操作をトリガーとしてスクリプトを自動実行する仕組みです。この機能を活用すれば、コミット前に自動でコードフォーマットを適用したり、リンターを実行してエラーがあればコミットを中止したりできます。
本記事では、Git Hooksの基本的な仕組みから、huskyとlint-stagedを使った実践的な自動チェック環境の構築方法まで解説します。この記事を読み終えると、以下のことができるようになります。
- Git Hooksの種類と役割を理解できる
- pre-commit、commit-msg、pre-pushフックを設定できる
- huskyを使ってチーム全体でGit Hooksを共有できる
- lint-stagedでステージされたファイルのみを対象に自動チェックを実行できる
- ESLintやPrettierと連携した自動フォーマット環境を構築できる
実行環境と前提条件
本記事の内容は、以下の環境で動作確認を行っています。
| 項目 | 要件 |
|---|---|
| Git | 2.40以上 |
| Node.js | 18以上(LTS推奨) |
| OS | Windows 10/11、macOS 12以上、Ubuntu 22.04以上 |
| ターミナル | コマンドプロンプト、PowerShell、Terminal.app、bash等 |
| エディタ | VS Code推奨 |
前提条件として、以下の知識があることを想定しています。
- コマンドライン操作の基礎知識(
cd、ls/dir、mkdir等) - テキストエディタの基本操作
Git Hooksとは
Git Hooksは、Gitの特定のアクション(コミット、プッシュなど)が実行される際に自動的にスクリプトを実行する仕組みです。Gitリポジトリの.git/hooks/ディレクトリに配置されたスクリプトが、対応するGitコマンドの実行時にトリガーされます。
Git Hooksの特徴
Git Hooksには以下の特徴があります。
- 自動実行: 手動操作なしで、Gitコマンドの前後に処理を挿入できます
- ローカル実行: フックはクライアント側で実行されるため、サーバーへの負荷がありません
- カスタマイズ可能: シェルスクリプトやNode.jsなど、任意の言語でフックを記述できます
- 中断可能: フックが非ゼロの終了コードを返すと、対応するGit操作を中止できます
クライアントサイドフックの種類
Gitには13種類のクライアントサイドフックが用意されています。本記事では、特に利用頻度の高い3つのフックに焦点を当てます。
| フック名 | 実行タイミング | 主な用途 |
|---|---|---|
pre-commit |
コミット作成前 | コードフォーマット、リント、テスト実行 |
commit-msg |
コミットメッセージ入力後 | コミットメッセージの検証 |
pre-push |
プッシュ前 | テスト実行、ビルド検証 |
その他のフックには、prepare-commit-msg(コミットメッセージのテンプレート生成)、post-commit(コミット後の通知)、pre-rebase(リベース前のチェック)などがあります。
Git Hooksの基本的な設定方法
まずは、huskyを使わずにGit Hooksを直接設定する方法を確認しましょう。
フックファイルの配置場所
Git Hooksは、リポジトリの.git/hooks/ディレクトリに配置します。新しいリポジトリを初期化すると、サンプルファイルが自動的に作成されます。
|
|
pre-commitフックの作成
pre-commitフックは、git commitコマンドの実行直前にトリガーされます。このフックが非ゼロの終了コードを返すと、コミットは中止されます。
|
|
Windowsの場合、Git Bashを使用するか、以下のようにPowerShellでファイルを作成します。
|
|
commit-msgフックの作成
commit-msgフックは、コミットメッセージが入力された後に実行されます。コミットメッセージの形式を検証するのに使用します。
|
|
pre-pushフックの作成
pre-pushフックは、git pushコマンドの実行前にトリガーされます。プッシュ前のテスト実行などに使用します。
|
|
Git Hooksを直接設定する場合の課題
.git/hooks/ディレクトリにフックを直接配置する方法には、以下の課題があります。
- バージョン管理されない:
.git/ディレクトリはGitの管理対象外のため、チームメンバーと共有できません - 手動セットアップが必要: 新しいメンバーは手動でフックをコピーする必要があります
- 環境依存: シェルスクリプトはWindowsとUnix系で互換性の問題が生じることがあります
これらの課題を解決するために、huskyというツールが広く使われています。
huskyによるGit Hooksの管理
huskyは、Git Hooksをnpmパッケージとして管理し、チーム全体で共有するためのツールです。Gitのcore.hooksPath機能を活用して、プロジェクトディレクトリ内のフックファイルを使用します。
huskyの特徴
huskyには以下の特徴があります。
- 軽量: gzip圧縮で約2KBと非常に軽量
- 高速: 約1ミリ秒で実行される高いパフォーマンス
- クロスプラットフォーム: Windows、macOS、Linuxで動作
- バージョン管理可能:
.husky/ディレクトリはGitで管理できる - ゼロ依存: 外部パッケージへの依存がない
huskyのインストールと初期設定
huskyをプロジェクトに導入する手順を説明します。
|
|
husky initコマンドを実行すると、以下の処理が自動的に行われます。
.husky/ディレクトリの作成.husky/pre-commitファイルの作成(デフォルトでnpm testを実行)package.jsonのprepareスクリプトにhuskyを追加
実行後のディレクトリ構造は以下のようになります。
プロジェクト/
├── .husky/
│ └── pre-commit # pre-commitフックスクリプト
├── package.json # prepareスクリプトが追加される
└── ...
huskyのpre-commitフック設定
husky initで作成された.husky/pre-commitファイルを編集して、任意の処理を実行できます。
|
|
フックを追加する場合は、.husky/ディレクトリに対応するフック名のファイルを作成します。
|
|
Windowsの場合は以下のようにします。
|
|
huskyフックの動作確認
フックが正しく設定されたか確認するには、実際にコミットを試みます。
|
|
期待される結果として、.husky/pre-commitに記述したコマンドが実行されます。コマンドが失敗すると、コミットは中止されます。
huskyフックのスキップ方法
緊急時にフックをスキップしたい場合は、--no-verify(または-n)オプションを使用します。
|
|
環境変数HUSKY=0を設定することで、一時的にすべてのフックを無効化することも可能です。
|
|
CI/Docker環境でのhusky設定
CI環境やDockerコンテナではGit Hooksが不要な場合があります。HUSKY=0環境変数を設定することで、フックのインストールと実行をスキップできます。
|
|
また、本番環境(NODE_ENV=production)や依存関係のみをインストールする場合に対応するため、prepareスクリプトを以下のように修正することも有効です。
|
|
lint-stagedによるステージファイルの自動チェック
lint-stagedは、Gitでステージされたファイルのみを対象にリンターやフォーマッターを実行するツールです。プロジェクト全体ではなく、変更されたファイルのみを対象とすることで、処理時間を大幅に短縮できます。
lint-stagedの特徴
lint-stagedには以下の特徴があります。
- 高速: ステージされたファイルのみを対象とするため、処理が高速
- 柔軟な設定: globパターンでファイルをフィルタリング可能
- 複数コマンド実行: 1つのファイルタイプに対して複数のコマンドを順次実行可能
- 自動ステージング: フォーマット後の変更を自動的にステージに追加
lint-stagedのインストール
lint-stagedをプロジェクトにインストールします。
|
|
lint-stagedの設定方法
lint-stagedの設定は、package.json内に記述するか、専用の設定ファイルを作成します。
package.jsonでの設定
|
|
専用設定ファイルでの設定
.lintstagedrc.jsonファイルを作成して設定することも可能です。
|
|
ESモジュール形式で記述する場合は、lint-staged.config.mjsを使用します。
|
|
huskyとlint-stagedの連携
huskyとlint-stagedを連携させて、コミット時に自動でリント・フォーマットを実行する設定を行います。
|
|
これにより、git commit実行時に以下の処理が自動的に行われます。
- ステージされたファイルの一覧を取得
- globパターンにマッチするファイルを抽出
- 設定されたコマンドを順次実行(ESLint、Prettier等)
- コマンドが成功すれば、変更を自動的にステージに追加
- いずれかのコマンドが失敗すれば、コミットを中止
lint-stagedの設定パターン
lint-stagedの設定パターンをいくつか紹介します。
基本的なJavaScript/TypeScriptプロジェクト
|
|
型チェックを含む設定
TypeScriptの型チェックは、個別のファイルではなくプロジェクト全体で行う必要があります。以下のように設定します。
|
|
ファイルパスに基づく除外設定
特定のディレクトリを除外する場合は、globパターンの否定(!)を使用します。
|
|
lint-stagedの実行結果
lint-stagedが正常に動作すると、以下のような出力が表示されます。
✔ Backed up original state in git stash
❯ Running tasks for staged files...
❯ package.json — 3 files
❯ *.{js,jsx,ts,tsx} — 2 files
✔ eslint --fix
✔ prettier --write
❯ *.{json,md} — 1 file
✔ prettier --write
✔ Applying modifications from tasks...
✔ Cleaning up temporary files...
エラーが発生した場合は、該当するコマンドの出力が表示され、コミットは中止されます。
✖ eslint --fix:
/path/to/file.js
1:10 error 'unused' is defined but never used no-unused-vars
✖ 1 problem (1 error, 0 warnings)
実践的なGit Hooks設定例
ここでは、実際のプロジェクトで使える具体的な設定例を紹介します。
基本的なNode.jsプロジェクトの設定
新規プロジェクトでhusky + lint-staged + ESLint + Prettierを設定する手順です。
|
|
package.jsonに以下の設定を追加します。
|
|
Conventional Commitsと組み合わせた設定
commitlintと組み合わせて、コミットメッセージの形式も検証する設定です。
|
|
この設定により、以下のようなConventional Commits形式のメッセージのみが許可されます。
feat: ユーザー認証機能を追加
fix: ログイン時のエラーハンドリングを修正
docs: READMEにインストール手順を追記
pre-pushでテストを実行する設定
プッシュ前にテストを実行して、テストが失敗したらプッシュを中止する設定です。
|
|
ブランチ名に基づくフックの制御
特定のブランチへのプッシュ時のみテストを実行する設定です。
|
|
Git Hooks設定時の注意点とベストプラクティス
Git Hooksを効果的に活用するための注意点とベストプラクティスを紹介します。
パフォーマンスへの配慮
pre-commitフックで重い処理を実行すると、コミットのたびに待ち時間が発生します。以下の点に注意してください。
- lint-stagedを活用: プロジェクト全体ではなく、ステージされたファイルのみを対象にする
- キャッシュを活用: ESLintの
--cacheオプションなど、キャッシュ機能を有効にする - 重い処理はpre-pushへ: フルテストやビルドはpre-pushフックに移動する
|
|
エラーメッセージの改善
フックが失敗した際に、開発者が原因を素早く特定できるよう、明確なエラーメッセージを出力しましょう。
|
|
チーム導入時の段階的アプローチ
既存プロジェクトにGit Hooksを導入する際は、段階的に進めることをお勧めします。
- 警告のみ: 最初はエラーを出さず、警告のみを表示する
- 段階的に厳格化: 徐々にルールを厳格化していく
- ドキュメント整備: チームメンバー向けにセットアップ手順を文書化する
|
|
トラブルシューティング
Git Hooks設定時によくある問題と解決策を紹介します。
フックが実行されない
|
|
Windows環境での改行コード問題
Windowsでフックが実行されない場合、改行コードが原因の可能性があります。
|
|
Node.jsバージョンマネージャー使用時の問題
nvm、fnmなどのバージョンマネージャーを使用している場合、GUIクライアントからのコミット時にNode.jsが見つからないことがあります。~/.config/husky/init.shにバージョンマネージャーの初期化処理を追加してください。
|
|
まとめ
本記事では、Git Hooksを活用したコミット前の自動チェック環境の構築方法について解説しました。
Git Hooksの主要なポイントは以下の通りです。
- pre-commit: コミット前にコードフォーマット・リントを実行
- commit-msg: コミットメッセージの形式を検証
- pre-push: プッシュ前にテスト・ビルドを実行
- husky: Git Hooksをチーム全体で共有するためのツール
- lint-staged: ステージされたファイルのみを対象に高速チェックを実行
Git Hooksとhusky、lint-stagedを組み合わせることで、コード品質を自動的に維持し、レビュー負荷を軽減できます。まずは基本的なpre-commitフックから始めて、徐々に設定を拡充していくことをお勧めします。