会社の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の部分を置換すればよい。
参考
- 「master への push を禁止するローカル git hook の正しい書き方」 http://thinca.hatenablog.com/entry/20150306/1425639218
- 「How do I prompt the user from within a commit-msg hook?」 http://stackoverflow.com/questions/3417896/how-do-i-prompt-the-user-from-within-a-commit-msg-hook
- 「たまに見かける[Y/n]での分岐処理のサンプル」 http://qiita.com/m0r1/items/d894e764cbc7d9c56c70
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