【Git】Git Hooksでできること
できること
Git公式にも記載されてますが、使えそうなものをピックアップします。
各種ざっくり何をするものかは下記にまとめます。
- commit系フック
- pre-commit
- コミットメッセージ入力前に実行される
- 主にテストの実行やコードフォーマッター等を行う
- 結果で0以外を返すとコミットをキャンセルできる
- prepare-commit-msg
- pre-commitの次に実行される
- 状況に応じたコミットメッセージを補完
- 固定文なら
commit.template設定でも可
- commit-msg
- コミットメッセージ入力後に実行される
- 主にコミットメッセージのチェック等を行う
- 結果で0以外を返すとコミットをキャンセルできる
- post-commit
- コミット完了後に実行される
- 主にビルドやコミットが成功した知等を行う
- pre-commit
- push/rebase/merge系フック
- pre-push
- プッシュ前に実行される
- セキュリティ対策等のブロック等を行う
- 結果で0以外を返すとプッシュをキャンセルできる
- pre-rebase
- リベース前に実行される
- リベースできるブランチを制御したりできる
- 結果で0以外を返すとリベースをキャンセルできる
- post-rebase
- リベース完了後に実行される
- ビルドやクリーン等を行う
- post-merge
- マージ完了後に実行される
- 依存関係インストール等を行う
- pre-push
- サーバーサイドフック
- pre-receive
- プッシュを受けた時に1度だけ実行される
- セキュリティ対策等のブロック等を行う
- 結果で0以外を返すとプッシュをキャンセルできる
- update
- プッシュを受けた時にブランチ毎に実行される
- セキュリティ対策等のブロック等を行う
- 結果で0以外を返すとプッシュをキャンセルできる
- post-receive
- プッシュ完了後に実行される
- CI/CDの実行等を行う
- pre-receive
使い方
各Gitリポジトリの.git/hooksの中にフック名のシェルスクリプトを配置すると動作します。
ただ.git/hooksはGit管理外のため、他の人には共有しにくいです。
そのため、ライブラリ等で共有する方法や設定で別フォルダを指定する方法があります。
husky等のライブラリは言語に依存するので、ここでは簡単な設定を紹介します。
Hooks共有方法
Hooksスクリプトを配置するフォルダ.githooksを作成します。
※フォルダ名は任意
そしてそのフォルダにHooksが配置されているという設定をします。
git config core.hooksPath .githooks
あとは.githooksをコミットして、各自コマンドをたたいてもらえれば反映されます
- フォルダ構成
各プロジェクトルート
┗.git
┃┗hooks
┃ ┣pre-commit.sample
┃ ┣...
┗.githooks
┣pre-commit
┣...
commit系フック
pre-commit(コミット前)
#!/bin/sh
npm test
例としては、コミットを行う前にテストの実行を行い、テストが通らなければコミットを受け付けないようにしたりします。
prepare-commit-msg(コミットメッセージ前)
#!/bin/sh
COMMIT_MSG_FILE=$1
BRANCH_NAME=$(git branch --show-current)
if [[ "$BRANCH_NAME" =~ ^hotfix/ ]]; then
OLD_MSG=$(cat "$COMMIT_MSG_FILE")
if [[ ! "$OLD_MSG" =~ ^\[緊急\] ]]; then
echo "[緊急] $OLD_MSG" > "$COMMIT_MSG_FILE"
fi
fi
例としては、hotfixブランチにコミットした際に、自動的に[緊急] という文字を先頭に付与するなど、動的にコミットのメッセージを書き換えます。
commit-msg(コミットメッセージ後)
#!/bin/sh
COMMIT_MSG=$(cat "$1")
if [ ${#COMMIT_MSG} -lt 10 ]; then
echo "コミットメッセージが短すぎます(10文字以上書いてください)"
exit 1
fi
例としては、「Rv指摘修正」みたいに雑にコミットメッセージを書かれないよう、ちゃんと説明させるよう文字数制限を設けたりします。
post-commit(コミット完了)
#!/bin/sh
docker-compose restart
例としては、コミットした状態の資材で再ビルドをかけ、問題ないかを確認する等に使用します。
push/rebase/merge系フック
pre-push
#!/bin/sh
read local_ref local_sha remote_ref remote_sha
PUSHING_FILES=$(git diff --name-only "$remote_sha" HEAD)
if echo "$PUSHING_FILES" | grep -E '(^|/)\.env$' >/dev/null 2>&1; then
echo ".envファイルはプッシュできません"
exit 1
fi
例としては、.envファイルの反映やAPI_KEYやSECRET_KEY等、セキュリティ問題につながるコミットをリモートに反映させないようにする防衛ラインとして使います。
pre-rebase
#!/bin/sh
BRANCH_NAME=$(git branch --show-current)
if [ "$BRANCH_NAME" = "main" ]; then
echo "mainブランチはリベースできません"
exit 1
fi
例としては、間違えたブランチで作業を行わないよう、リベースできるブランチを制限したりします。
post-rebase
#!/bin/sh
./gradlew clean --console=plain
例としては、リベースによる資材変化を反映するため、クリーンし直したりします。
post-merge
#!/bin/sh
npm install
例としては、他の方の依存関係の変更を自環境に反映すべく、再インストールを走らせる等に使います。
サーバーサイドフック
pre-receive
#!/bin/sh
read local_ref local_sha remote_ref remote_sha
PUSHING_FILES=$(git diff --name-only "$remote_sha" HEAD)
if echo "$PUSHING_FILES" | grep -E '(^|/)\.env$' >/dev/null 2>&1; then
echo ".envファイルはプッシュできません"
exit 1
fi
例としては、.envファイルの反映やAPI_KEYやSECRET_KEY等、セキュリティ問題につながるコミットをリモートに反映させないようにする最終防衛ラインとして使います。
※ローカルでの制限はスキップすることはできるので、最終ここで止められなければもう止めれません
update
プッシュされた複数のブランチでブランチごとに実行
#!/bin/sh
BRANCH_NAME=$1
if [ "$BRANCH_NAME" = "refs/heads/release" ]; then
echo "releaseブランチへの直接プッシュは制限されています。PRを作成してください。"
exit 1
fi
例としては、特定のブランチに直接プッシュできないように、プルリクエスト(マージリクエスト)でマージさせるように制限したりします。
post-receive
#!/bin/sh
USER_NAME="git-hook-user"
API_TOKEN="1234567890test"
while read oldrev newrev refname; do
if [ "$refname" = "refs/heads/main" ]; then
curl -X POST -L --post301 \
-u "$USER_NAME:$API_TOKEN" \
"http://jenkins-server:8080/job/app-test/build" > /dev/null 2>&1
fi
done
例としては、プッシュ完了後CI/CDを走らせるなどに使用します。
まとめ
簡単にGit Hooksでできることをまとめてみました。
存在は知っていましたが、具体的に何ができるかわかってなかったので、便利だとは思いました。
ただ、基本的にはローカルでの簡易的チェック等に使って、本格的なチェックはCI/CDに任せるほうが良いとは思います。
以上、ここまで見ていただきありがとうございます。
皆さまの快適な開発ライフに、ほんの少しでもお役に立てれば幸いです。