gitのpre-push hookでmasterブランチにpushする際にプロンプトで確認するようにする


会社のGitを使っているときに、自分のブランチで作業しているつもりが間違ってmasterブランチで作業しており、気づかずにpushしそうになって肝を冷やしたことがあるので、masterにpushする際はプロンプトで確認するようにした。

環境

  • Mac OS X Yosemite 10.10.5
  • Git 2.11.1

gitテンプレートディレクトリを作成

特定のレポジトリではなく、PC上で扱う全てのレポジトリのコミットをhookするため、グローバルの.gitテンプレートディレクトリを準備する。
(なお、特定のレポジトリでだけhookしたい場合は、以下で作るpre-pushファイルをレポジトリの.git/hooks/におけばよい)

mkdir -p ~/.git_template/hooks

.gitのテンプレートに.git_templateを指定

git config --global init.templatedir ~/.git_template/

これで新たにgitレポジトリを作ったりcloneすると.git_templateディレクトリの設定が有効になる。

hookファイル作成

vi ~/.git_template/hooks/pre-push

内容は以下のようにする。

#!/bin/bash

while read local_ref local_sha1 remote_ref remote_sha1
do
  if [[ "${remote_ref##refs/heads/}" = "master" ]]; then
    echo "Warning: push to remote master, continue? [y/N]"

    exec < /dev/tty
    read ANSWER

    case $ANSWER in
      "Y" | "y" | "yes" | "Yes" | "YES" ) echo "OK. push start.";;
      * ) echo "push failed.";exit 1;;
    esac
    exit 0
  fi
done

gitのhookは普通にはインタラクティブなことができないらしく、readが使えなかった。
exec < /dev/tty
を追加することでreadができるようになる。

hookファイルのパーミッション変更

パーミッションを変えて実行可能にする
これをしないとhookされない。

chmod +x ~/.git_template/hooks/pre-push

結果

以上の設定をすると、masterブランチにpushする際に

Warning: push to remote master, continue? [y/N]

と訊かれるようになる。
Y, y, yes, Yes, YESと入れるとpushされ、それ以外だとpushが失敗するようになる。
masterでなく、他のブランチをhookしたい場合はpre-hookファイルのmasterの部分を置換すればよい。

参考

2018/03/18追記

複数ブランチに対応。
例えばmasterとdevelopブランチにpushする前にチェックしたい場合は以下のようにすればよい。

#!/bin/bash

while read local_ref local_sha1 remote_ref remote_sha1
do
  for branch in "master" "develop"; do
    if [[ "${remote_ref##refs/heads/}" = "${branch}" ]]; then
      echo "Warning: push to remote ${branch}, continue? [y/N]"

      exec < /dev/tty
      read ANSWER

      case $ANSWER in
        "Y" | "y" | "yes" | "Yes" | "YES" ) echo "OK. push start.";;
        * ) echo "push failed.";exit 1;;
      esac
      exit 0
    fi
  done
done