【Git Hooks】コミット時の品質チェックを仕組み化してみた

こんにちは。
今回は、Git Hooksによる、コミット時の品質チェックを仕組み化していきます。

Git Hooksは、コミットやプッシュ等Git操作前後に自動でスクリプトを実行できる仕組みです。
これにより、開発・デプロイで品質チェックの自動化が可能となり、人的ミスの予防やチームの運用効率化に繋がります。

Git Hooksの概要や使用例はこちらが見やすいです。 Git Hooks - atlassian

Git Hooksを使った品質チェック概要

筆者が構築したHugo自動デプロイシステム(ローカル→Github→S3)のうち、ローカルからGithubへのプッシュ時のコミット操作にて品質チェックを行っています。 開発デプロイ概要

実装したGit Hooksを用いた開発時の品質チェックは下記となります。
品質チェック

① デプロイファイルの品質チェック

② コミット文のテンプレ作成

③ コミットコメントの品質チェック

コミット時に、デプロイするファイルがルール通りになっているか、コミットコメントがルール通りか(可読性があるか)を判断します。
OKであればプッシュに移れます。

※なお、これから記載するGit Hooks内容はブログ用にぼかしたものとなります。あくまで参考までに。

実装方法

Git Hooksの有効化

プロジェクト上の「.git/hooks」フォルダにて、Git Hooksで使用するファイルが入っています。

ls ./.git/hooks

> applypatch-msg.sample  commit-msg.sample  fsmonitor-watchman.sample  post-update.sample  pre-applypatch.sample  pre-commit.sample  pre-merge-commit.sample  pre-push.sample  pre-rebase.sample  pre-receive.sample  prepare-commit-msg.sample  update.sample

今回使用する「pre-commit」、「prepare-commit-msg」、「commit-msg」を有効化するには、「.sample」拡張子を除いたファイルを複製します。

cd ./.git/hooks

#拡張子の無いファイルを作成(これによりHooksが有効化されます)
cp pre-commit.sample pre-commit
cp prepare-commit-msg.sample prepare-commit-msg
cp commit-msg.sample commit-msg

pre-commit

pre-commitは、コミット文の実行後、コミットコメントを入力する直前までの処理を自動化します。

#!/bin/sh

FILE="main.txt"

echo "pre-commit: ${FILE} に [HEAD] が含まれているか確認中…"
if ! grep -q "\[HEAD\]" "$FILE"; then
  echo "> ${FILE} に [HEAD] がありません。コミットを中止します"
  exit 1
fi

echo "> [HEAD] が存在 OK"
exit 0

品質確認対象の「main.txt」に対して、「HEAD」項目があるかを確認します。
ない場合は、「exit 1」によって、コミット処理が中断されます。

prepare-commit-msg

prepare-commit-msgは、コミットコメントを入力画面のテンプレートをカスタマイズします。

#!/bin/sh

TIMESTAMP=$(date "+%Y%m%d-%H%M%S")

NEW_MSG="${TIMESTAMP}_"

sed -i "1s/^/${NEW_MSG}/" "$1"

コミットコメントのテンプレートとして、タイムスタンプを接頭に自動付与しています。
開発者はこのタイムスタンプの直後にコミット内容を追記する形になります。

commit-msg

commit-msgでは、コミットコメント入力後からコミット完了までの間に処理を行います。

#!/bin/sh
MSG_FST_LINE=$(cat $1 | head -n1)
echo "commit-msg: コミットメッセージは「${MSG_FST_LINE}」から始まっています。"

if ! printf "%s" "$MSG_FST_LINE" | grep -qE "^[0-9]{8}-[0-9]{6}"; then
  echo "> メッセージはタイムスタンプ「yyyymmdd-hhmmss」から始めてください"
  exit 1
fi

echo "> メッセージ形式 OK"
echo "コミットが完了しました。※責任者へのコミット通知等はここで実施する"

ここでは、コミットメッセージ文が「タイムスタンプ_<内容>」というフォーマットになっているかを判定しています。
「$1」にてコミットメッセージを取得し、ルールに合っていない場合は、「exit 1」により、コミット処理を中断します。
参考として、「$1」にて取得されるコミットメッセージは「.git/COMMIT_EDITMSG」ファイルにて格納されています。

ちなみに、今回実装していませんが、コミット後にSMTPサーバ等を使用して管理者にコミット完了通知を送ることも可能です。

コミット実行シミュレーション

main.txtに[HEAD]がない場合(異常)

$ git commit
pre-commit: main.txt に [HEAD] が含まれているか確認中…

> main.txt に [HEAD] がありません。コミットを中止します

main.txtに[HEAD]がある場合(正常)

$ git commit
pre-commit: main.txt に [HEAD] が含まれているか確認中…

> [HEAD] が存在 OK

正常な場合は、コミットメッセージ文入力に繋がります。

コミットメッセージ画面

nanoやvi上に遷移します。 このタイムスタンプの後にコミット内容を記載します。

20250720-000000_ 
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# On branch master
# Changes to be committed:
#	modified:   main.txt
#

コミットメッセージにタイムスタンプがない(異常)

first-deploy...

のように、タイムスタンプが接頭に無い場合、

commit-msg: コミットメッセージは「first_commit」から始まっています。

> メッセージはタイムスタンプ「yyyymmdd-hhmmss」から始めてください

コミットメッセージにタイムスタンプがある(正常)

20250720-000000_ first-deploy...

のように、タイムスタンプが接頭にある場合、

commit-msg: コミットメッセージは「20250720-000000_first-commit」から始まっています。

> メッセージ形式 OK

コミットが完了しました。※責任者へのコミット通知等はここで実施する
[master xxxxxx] 20250720-000000_first-commit
 1 file changed, 1 insertion(+), 1 deletion(-)

無事にコミットが完了します。

おわりに

Git Hooksによる自動品質テストを行ってきました。
正常なプロダクトをデプロイするために、確認項目を照らし合わせておくのは重要です。
一方で、目視で確認するのも漏れがありやや不安ではありますので、諸々の確認をもっと自動化したいなと改めて思いました。

それでは。