Git 複数のgithookを呼び出して,用途別に切り分けてみた


githookとは

gitのコマンドを叩いた時に走ってくれるshell.
commit前に中身をチェックしたりpush前にブランチをチェックしたりと自動化しておきたいことをまとめることができる.
これを設定しておくだけで,単純な手違いは減らせる.

スクリプトは.git/hooksの中にサンプルがあるため,それを参考に書きます.

しかし,各動きに反応するスクリプトは一つなので(多分),用途が増える度に継ぎ足ししていく形になる...
これだと使いまわすときに不要なチェックなどが入る可能性があるため,用途別にスクリプトを切り分けて,使いまわせるようにしたいと思いました.

やったこと

割と単純だが,ベースのスクリプトが複数のチェック用のスクリプトを呼び出す形にしてみました.

.git/hooksの構造を以下のようにしています.

.git/hooks/
...
├── pre-push # push前に呼び出されるスクリプト
├── ban-to-master-pre-push # masterへのpush禁止
├── build-test-pre-push # push前にビルドテストをする
...

配置した後は必ず実行権限を与えるようにしましょう.
chmod +x .git/hooks/pre-push
chmod +x .git/hooks/ban-to-master-pre-push
chmod +x .git/hooks/build-test-pre-push

例えばpushをする前に呼び出されるpre-pushの場合,

#!bin/sh

# .git/hooks内の[用途名]-pre-pushを全て呼び出して処理
for f in $(ls .git/hooks | grep -E "[-]pre-push$"); do
    sh .git/hooks/${f}
    # 実行した結果が異常な場合は止める
    result="$?"
    if [ "${result}" != 0 ]; then
        exit "${result}"
    fi
done

呼び出す順番が気になる場合は,lsで一覧を取ってくるため,ファイル名の頭に呼び出す数値を振っておくのもありだと思います.

masterへのpushを禁止する処理

#!bin/sh

while read local_ref local_sha remote_ref remote_sha; do
    # masterへのpushを禁止
    if [ "${remote_ref}" =~ ^.*/(master)$ ]; then
        echo "${remote_ref}には直接push禁止!"
        exit 1
    fi
done

exit 0

こんな感じで用途ごとにスクリプトを分けることで,案件ごとに必要なチェックだけを入れることができるようになりました.

さらに別案

やったことで書いた方法だと.git/hooksが散らかる気がするため,処理タイミング別のフォルダに入れて,呼び出す側のファイルパスを変更したらすっきりするかもしれません.

.git/hooks/
...
├── pre-push # push前に呼び出されるスクリプト
└── pre-push.d # pre-pushで呼び出すスクリプトまとめ
    ├── ban-to-master # masterへのpush禁止
    └── build-test # push前にビルドテストをする
...

pre-pushを変更

#!bin/sh

# .git/hooks内の[用途名]-pre-pushを全て呼び出して処理
for f in $(ls .git/hooks/pre-push.d); do
    sh .git/hooks/pre-push.d/${f}
    # 実行した結果が異常な場合は止める
    result="$?"
    if [ "${result}" != 0 ]; then
        exit "${result}"
    fi
done