search
LoginSignup
157

More than 5 years have passed since last update.

posted at

updated at

GitHub上の大事な中央ブランチをgit push --forceの恐怖から守るgit hookスクリプト

つい先日、GitHubで管理していたテスト用中央ブランチに、チームメンバーが誤ってgit push --forceしてしまい、
一部の歴史が消失するという事件が起きました。

ぎゃあああ!なんばしよっとね!うっかりでしたじゃ済まんばい!
とか思っていたらJenkinsの開発者みたいなスゴい人でもやらかしちゃうみたいです。

Jenkinsの開発者、間違えて一ヶ月前のローカルレポジトリをgit push --forceしてしまう
http://cpplover.blogspot.jp/2013/11/jenkinsgit-push-force.html

スゴい人でもやらかすんだから、平民の我々もそのうちやらかすに違いない。
緊急バグ修正などで慌てていたら尚更ですね。(というか自分が一番やりかねない)
というわけで、何とか仕組みの上で防くことができればと思って仕掛けることにしました。


以下のスクリプトを、.git/hooks/pre-pushというファイル名で保存。
push直前に起動し、大事なブランチへgit push --forceしそうであればエラーを返して食い止めてくれます。

#!/bin/sh

# 守りたいbranch名を定義
PROTECTED_BRANCHES=( trunk master )

CURRENT_BRANCH=$(git symbolic-ref HEAD | sed -e 's,.*/\(.*\),\1,')

PUSH_COMMAND=$(ps -ocommand= -p $PPID)

IS_DESTRUCTIVE='force|delete|\-f'

WILL_REMOVE_PROTECTED_BRANCH=':'$PROTECTED_BRANCH

for i in "${PROTECTED_BRANCHES[@]}"
do

    PROTECTED_BRANCH=$i

    # エラーメッセージを定義
    MESSAGE="$PROTECTED_BRANCH には $PUSH_COMMAND してはダメです!先にgit fetch && git merge origin $PROTECTED_BRANCH すること。by pre-push hook"

    if [[ $PUSH_COMMAND =~ $IS_DESTRUCTIVE ]] && [ $CURRENT_BRANCH = $PROTECTED_BRANCH ]; then
      echo $MESSAGE
      exit 1
    fi

    if [[ $PUSH_COMMAND =~ $IS_DESTRUCTIVE ]] && [[ $PUSH_COMMAND =~ $PROTECTED_BRANCH ]]; then
      echo $MESSAGE
      exit 1
    fi

    if [[ $PUSH_COMMAND =~ $WILL_REMOVE_PROTECTED_BRANCH ]]; then
      echo $MESSAGE
      exit 1
    fi

done

exit 0

参考
https://gist.github.com/pixelhandler/5718585
自前の開発環境に合わせて少々書き換えました。


本当はサーバサイドフックを利用して、特定ブランチへの破壊的なpushであれば云々、みたいな処理にしたかったのですが、
GitHub上で実現する方法がよくわからず、やむなくpre-pushを利用しました。
クライアントサイドフックなので、中央ブランチを完璧に守るためには、開発者全員の環境に仕掛ける必要があります。

あと、pre-pushはgitのバージョンによっては動かないそうです。
1.8.2以上であれば動作するはずです。(1.8.3環境で確認済み)

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
157