シフトレフト:なぜクラウドを待つのか?
多くの開発者は、CI/CDをGitHub ActionsやJenkinsのようなリモートサーバー上で実行される遠いプロセスだと考えています。コードをプッシュし、コーヒーを飲みながら、緑色のチェックマークが表示されるまで5分間待ちます。もし代わりに赤い「X」が表示されたら、コンテキストスイッチを行い、単純なタイポを修正して、サイクルを最初からやり直さなければなりません。このフィードバックループは、目に見えない生産性キラーです。
Git Hooksは、これらの不可欠なチェックをローカルマシンに移動させることで、この流れを逆転させます。これらは、コミットやプッシュなどのイベントの前後にGitが自動的に実行するシンプルなスクリプトです。セミコロンの付け忘れやユニットテストの失敗を手元のPCでキャッチすることで、チームをビルド失敗のストレスから救うことができます。基本的なpre-commitルーチンを導入するだけで、CIの失敗率を40%以上削減したチームも見てきました。
提出する前に自分の仕事を校正してくれるパーソナルアシスタントのようなものだと考えてください。些細な構文エラーが他の全員のパイプラインを止めてしまうような、気まずい瞬間を防いでくれます。
これらのフックはどこにあるのか?
すべてのGitリポジトリには、目立たない場所に自動化エンジンが組み込まれています。git initを実行すると、Gitは.git/hooksディレクトリを作成します。その中には、いくつかのテンプレートファイルが入っています。
cd .git/hooks
ls -l
pre-commit.sampleやpre-push.sampleといったファイルが表示されるはずです。これらは単なるシェルスクリプトです。有効にするには、.sample拡張子を削除し、ファイルに実行権限があることを確認するだけです。非常にシンプルです。
覚えておくべき2つのカテゴリがあります:
- クライアントサイド・フック: 自分のコンピュータで実行されます。リンター、フォーマッタ、高速なユニットテストに最適です。
- サーバーサイド・フック: リモートサーバー上で実行されます。ブランチの命名規則の強制や、デプロイ通知のトリガーに使用されます。
日々の業務の多くにおいて、pre-commitのようなクライアントサイド・フックは、最も早く投資対効果(ROI)を得られます。
最初のゲートキーパー(Pre-Commit)を作成する
コードが整理されていない場合にコミットをブロックするフックを作成してみましょう。これにより、リポジトリをクリーンに保り、全員が同じスタイルガイドに従うようになります。ここでは Node.js の例を使用しますが、Pythonのflake8やGoのgofmtに置き換えることも可能です。
まず、ファイルを作成し、適切な権限を付与します:
touch .git/hooks/pre-commit
chmod +x .git/hooks/pre-commit
ファイルに以下のロジックを追加します。これはGitに対して「リンターを実行し、問題が見つかったら即座にコミットを停止せよ」と指示するものです。
#!/bin/sh
echo "🔍 スタイルチェックを実行中..."
npm run lint
# 直前のコマンドの結果を取得
status=$?
if [ $status -ne 0 ]; then
echo "❌ リンターが失敗しました!コミットする前に上記のメッセージを確認して修正してください。"
exit 1
fi
echo "✅ スタイルに問題はありません。コミットを開始します。"
exit 0
これで、git commitと入力するたびにスクリプトが実行されます。コードが乱れている場合、Gitは操作をキャンセルします。CIサーバーから同じことを指摘されるまで数分待つのではなく、数秒でローカルで問題を修正せざるを得なくなります。
「自分のマシンでは動く」問題
標準の.git/hooksフォルダには大きな欠点があります。それは、Gitの管理対象外であることです。素晴らしいフックを作成しても、チームメイトがプロジェクトをクローンしたときには共有されません。これを解決するには、Husky(JavaScript用)やpre-commit framework(Pythonやマルチ言語プロジェクト用)などのツールを使用します。
Huskyを使用すると、バージョン管理に含まれる.huskyフォルダにフックを保存できます。セットアップは迅速です:
npx husky-init && npm install
npx husky add .husky/pre-commit "npm test"
これにより、チームのすべての開発者が同じチェックを実行するようになります。言い訳は通用しません。
Pre-Push:最終セーフティネット
リンターは高速ですが、小さな変更を保存するたびに10分かかる統合テストスイートを実行したくはないでしょう。そこでpre-pushフックの出番です。これはリモートサーバーにコードを送信しようとしたときにのみ実行されます。
#!/bin/sh
echo "🧪 プッシュ前にフルテストスイートを実行中..."
npm test
if [ $? -ne 0 ]; then
echo "❌ テストが失敗しました。メインブランチを保護するため、プッシュを中止しました。"
exit 1
fi
exit 0
自動化を分割し、コミット時にリンター、プッシュ時にテストを実行することで、共有コードベースを守りつつ、ローカルのワークフローの速さを維持できます。
トラブルシューティングとバイパス
フックが動作しない場合は、基本を確認してください。実行権限はありますか?chmod +x .git/hooks/pre-commitを実行しましょう。ファイル名は正確ですか?Gitはpre-commit.shを認識しません。また、フックは非対話型シェルで実行されることに注意してください。「command not found」エラーを避けるため、常に./node_modules/.bin/eslintのようなローカルパスを使用してください。
緊急のホットフィックス時など、ルールをバイパスする必要がある場合があります。その際はフラグを1つ追加するだけでフックをスキップできます:
git commit -m "Emergency fix" --no-verify
これは控えめに使用してください。もし毎日--no-verifyを使っているなら、テストが遅すぎるか、ルールが厳格すぎる可能性があります。優れたフックは、障害ではなく助けになるものであるべきです。
結論
自動化は大規模なクラウドサーバーのためだけのものではありません。それはあなたのキーボードから始まります。Git Hooksの設定に10分費やすだけで、毎月累計で何時間もの待ち時間を節約できます。まずはリンターから始め、次にシークレットスキャン(APIキーの流出防止)や自動フォーマットへと広げていきましょう。CIサーバー、そしてチームメイトもあなたに感謝するはずです。

