git push -fでやらかした話し
ついにやってしまった
git push -fで大事なブランチを上書きしてしまったのです。
他の人がローカルのmasterブランチを思いっきりforce pushしてしまったことは何度か見かけたことはありました。
まさか自分が似たようなことをやらかしてしまうなんて・・・
force pushの悲劇はエンジニア人生で一度はやらかしてしまうものなのかもしれないです。
普段のブランチ運用
普段のブランチ運用はdevelopブランチをベースにタスク毎にブランチを切り、問題がなければdevelopにマージ、というシンプルな運用をしていました。
背景
ある機能の全面リプレイスを行う、というプロジェクトに参加していました。
今回のリプレイスプロジェクトは事情があって少しずつ改善->リリースが出来ない性質のものであった為、developとは別の専用のベースブランチが作成されました。
ここでは仮にreplaceブランチとしておきます。
事の経緯
このプロジェクトを開始して数ヶ月たったある日、いつものようにreplaceからブランチを切って作業し、いざpushしてPullRequestを作成したところ、ほんのちょっとだけコンフリクトが発生していました。
これ自体はよくあることなのでreplaceブランチを最新化しようとreplaceブランチに移動し、git pullと打ち込もうとした所、コマンド履歴にあったgit push -fを叩いてしまったのです!
(この時はなぜか、git pull --rebase origin replaceと打ち込まなかった)。
すぐにやらかしをslackで開発リーダーに報告し、他のメンバーへも周知しました。
幸いにも最新のコミットから数件遅れていたことがすぐに判明し、数件分を再度pushしてもらうことで事なきを得ました。
平謝りしたのは言うまでもありません。
やらかした時の背中の汗は今でも忘れられません。
ということで今後、背中に汗をかかない為に以下のことを行いました。
対策1 githubでブランチをprotectedに設定する
これが王道です。
保護されたブランチを設定する
もちろん全員がリポジトリの設定を変更できるわけではないと思いますので、そこは相談してみると良いのではないかと思います。
これはgithubでの話しですが、gitlabとかbitbucketでも似たような設定はある気がします。
対策2 git push -fの代わりに--force-with-leaseを使う
これは個々人でやれる対策になります。
push -fを使わないという対策です。
この--force-with-leaseオプションはpushの際にローカルよりリモートの日付の方が新しい場合pushが失敗する、というものです。
今回のミスはこれで防げたと思います。
自分自身は以下のaliasを設定しました。
git config --global alias.pushf "push --force-with-lease"
対策3 git hooksで対策する
これも個々人でやれる対策になります。
git hookを利用して特定のブランチに対して、そもそもpushさせない設定を追加するという対策になります。
具体的には以下のようなhookを追加しました。
下のスクリプトではmasterとdevelopへpushをかけるとCan not push to <ブランチ名>というエラーが表示されるようになります。
開発状況によって、not_allowed_branches部分を改造していけば良いと思います。
.git/hooks/pre-push
not_allowed_braches=("master" "develop")
while read local_ref local_sha remote_ref remote_sha
do
for branch in ${not_allowed_braches[@]}
do
if [[ "$remote_ref" =~ ^.*/($branch)$ ]]; then
echo "Can not push to $remote_ref !!!"
exit 1
fi
done
done
exit 0
最後に
この不幸を少しでも減らせたらと思い、記述しました。
背中に汗をかく前に設定してみてはどうでしょうか?
Discussion