Git Hooks プレコミット、プレプッシュ、そして悪質なコードをドアの前に止めること
pre-commit、commit-msg、pre-push ホックは、git がコミットを記録またはプッシュする前に実行されるシェルスクリプトです。これらを設定して、チェックの失敗、不適切なコミットメッセージ、漏洩したシークレットを検出する方法を紹介します。実際の例を含んでいます。
Git は、ワークフローの特定のポイントで実行されるシェルスクリプトとしてホックを提供しています。ほとんどのリポジトリには、無活性の状態で存在するホックがあります。 .git/hooks/ as .sample これらのホックはファイルに保存されています。ほとんどの開発者は、破損したコミットや漏洩したAPIキーが発生するまで、それらを無視しています。
ここでは、すべてのプロジェクトに接続すべき3つのホックを紹介します。 pre-commit, commit-msgと、 pre-pushそれぞれが異なるタイプの誤りを検出します。それぞれは、今日すぐに貼り付けて使えるシェルスクリプトです。
ホックが存在する場所
すべてのGitリポジトリには、 .git/hooks/ ディレクトリがあります。実行 ls .git/hooks/ すると、サンプルファイルが表示されます。Gitは、 .sample のサフィックスを持つものを無視します。ホックを有効にするには、サフィックスを削除し、実行可能にします。
cp .git/hooks/pre-commit.sample .git/hooks/pre-commit
chmod +x .git/hooks/pre-commit
契約はシンプルです:0を返すとGitは続行します。非ゼロを返すとGitは中止され、stderrに書かれた内容が表示されます。
pre-commit:最も価値の高いホック
pre-commitは、 git commit を入力した後で、コミットオブジェクトが書き込まれる前に実行されます。コミットメッセージはまだ書かれていないため、見ることはできません。その代わりに、ステージされたファイルを検査し、何かが間違っているように見える場合は拒否します。 できますが、結果は予測不可能で、誰かが泣くことになるでしょう。 重要な点:
を使用して、実際にステージされたファイルだけを取得できます。毎回コミット時に全体のプロジェクトをlintするのは遅く、あなたが導入しなかった問題を表面化します。 git diff --cached --name-only Lintの例(ESLint)
フラグは削除されたファイルをスキップします — 削除したものをlintしようとするのは無意味です。
#!/bin/sh
# Lint only staged JS files
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep '\.js$')
if [ -z "$STAGED_FILES" ]; then
exit 0
fi
echo "Running ESLint on staged files..."
echo "$STAGED_FILES" | xargs ./node_modules/.bin/eslint
if [ $? -ne 0 ]; then
echo "ESLint failed. Fix errors before committing."
exit 1
fi
exit 0
の --diff-filter=ACM 秘密のスキャン例
明確なパターンスキャンにより、明らかな誤り(ハードコードされたAPIキー、誤ってコミットされた設定ファイル内のパスワード)を検出します。
トイプロジェクトを超える場合は、専用のスキャナーと組み合わせてください。
#!/bin/sh
# Block commits with obvious secrets
PATTERNS="(AWS_SECRET|api_key\s*=|password\s*=|PRIVATE KEY)"
if git diff --cached | grep -qiP "$PATTERNS"; then
echo "Potential secret detected in staged changes. Aborting commit."
exit 1
fi
exit 0
detect-secrets はYelpから提供されており、既存のフラグ付き文字列がすべてのコミットをブロックしないように、ベースラインファイルを維持します。 trufflehog は、過去の履歴をスキャンするか、CIで実行するのに適しています。 commit-msg:メッセージフォーマットを強制
このホックは1つの引数を受け取ります:ドラフトコミットメッセージを含む一時ファイルのパス。それを読み、検証し、拒否する場合は1を返します。ファイルは書き込み可能なので、メッセージを正常化する代わりに拒否することもできますが、最初のときには人々に驚きます。
強制する
Conventional Commits フォーマットは最も一般的な用途です。報酬は自動化された変更ログ、読みやすい出力、およびコミットタイプを解析してリリースを決定できるCIパイプラインです。 これは、形式が正しいが意味がないメッセージ(例: git log )を検出できません。これは文化の問題であり、ツールの問題ではありません。
#!/bin/sh
COMMIT_MSG_FILE=$1
COMMIT_MSG=$(cat "$COMMIT_MSG_FILE")
# type(scope): description — scope is optional
PATTERN="^(feat|fix|chore|docs|style|refactor|test|perf|ci|build|revert)(\(.+\))?: .{1,72}"
if ! echo "$COMMIT_MSG" | grep -qP "$PATTERN"; then
echo ""
echo "Invalid commit message. Use Conventional Commits format:"
echo " type(scope): short description"
echo ""
echo "Valid types: feat, fix, chore, docs, style, refactor, test, perf, ci, build, revert"
echo "Example: feat(auth): add OAuth2 login flow"
echo ""
echo "Your message: $COMMIT_MSG"
exit 1
fi
exit 0
pre-push:originまでの最後のゲート fix: fix thingspre-pushは、
が呼び出された後で、データがリモートに送信される前に実行されます。標準入力からリモート名とURLを受け取ります。ここにテストが属すべきです — ライント(pre-commitで実行)ではなく、実際のテストで動作を検証します。
一つの真実:もしテストセットが60~90秒以上かかる場合、人々は git push を使用します。ここでは、高速なユニットテストだけを実行してください。統合テストやE2EテストはCIで実行し、遅いことが許容されるべきです。遅いほどスキップされるホックは、ホックがないよりも悪です。
#!/bin/sh
echo "Running tests before push..."
npm test
if [ $? -ne 0 ]; then
echo "Tests failed. Push aborted."
exit 1
fi
exit 0
ホックを回避する方法 — そしてそれが適切な場合 --no-verifyどちらのフラグも存在する理由があります。壊れたホックがホットフィックスをブロックすることは、チーム全体がGitホックという概念に反対することにつながります。正当な理由がある場合にのみ
を使用してください:関連ないファイルでホックが誤作動する場合、または修正が重要でゲートより優先される緊急事態。
git commit --no-verify
git push --no-verify
頻繁にそれを使用している場合は、ホックの調整が必要です。最も一般的な原因は、遅い実行、変更されていないファイルで失敗、またはまだ整理していないパターンマッチングの誤検出です。 --no-verify チームと共有するホック
は各クローンに局所的です — リポジトリにコミットされないよう意図されています。ホックを定着させるための2つのアプローチがあります:
オプション1:core.hooksPath
.git/hooks/ ホックをコミットされたディレクトリ(例:
)に保存し、Gitにその場所を指します:
新しいクローンに自動化するため、 .githooks/に
git config core.hooksPath .githooks
スクリプトを追加します。npmは自動的に prepare を実行します。 package.json スクリプトを実行可能にし、コミットして、誰もがクローンし、 npm install:
{
"scripts": {
"prepare": "git config core.hooksPath .githooks"
}
}
を実行するとホックが自動的に設定されます。 npm install オプション2:Husky
Husky
はJavaScript/Nodeプロジェクトの標準的な選択です。それは、 の接続を自動的に処理し、各ホックに core.hooksPath に個別のファイルを提供します。 .husky/:
npx husky init
その後、ホックをシンプルなシェルスクリプトとして追加します:
echo "npm test" > .husky/pre-push
chmod +x .husky/pre-push
Husky 9(2024年初頭にリリース)は、JSON構成を完全に廃止し、bare shell scriptsに移行しました。新しいセットアップではv4/v8よりもシンプルですが、Husky 4から移行する場合、公式の移行ガイドが過小評価している破壊的な変更があります — 旧 .huskyrc フォーマットはまったく機能しなくなります。既存のリポジトリをアップグレードする場合は、時間を確保してください。
非JavaScriptリポジトリは、 core.hooksPath アプローチの方が適しています。ホック管理のためにNodeのデプロイを導入する必要はありません。
ホックが実行される前に差分を確認する
git diff --cached は、ターミナルでステージされた変更を表示します。2つのバージョンの設定ファイルを比較するか、複数編集で実際の変更を確認する場合、視覚的な差分はスキャンを速くします。 IO Tools’ Text Diff は、2つのバージョンを貼り付けて、正確に変更された内容を確認できるようにします — コミット前にホックが実行される前に何が入っているかを確認するのに役立ちます。
Gitホックは、あなたの既存ワークフローに完全に存在する自動化ツールの一つです — CIアカウント、追加サービス、コストなし。linting失敗を拒否するpre-commitホックは、あなたが書いたシェルスクリプトとまったく同じ信頼性を持ちます。これは機能です:1分以内に読む、デバッグし、変更できます。上記の3つのホックを接続すれば、「ローカルで動く」から「メインで動く」までの最も一般的なギャップを閉じます。
恵 スコアボードが到着しました!
スコアボード ゲームを追跡する楽しい方法です。すべてのデータはブラウザに保存されます。さらに多くの機能がまもなく登場します!
