git push –force and how to deal with it
間違ったgitコマンドがあなたのプロジェクトのレポに大混乱をもたらした状況に遭遇したことがありますか? 人は間違いを犯すものであり、時にはその間違いがあなたのチームの時間を何時間も費やしてしまうこともあります。 このチュートリアルでは、不運な git push --force
からすばやく回復する方法を紹介します。
過信しすぎないようにしましょう。 遅かれ早かれ、これは起こることです。 同じ git リポジトリで複数のリモートで作業している間に、最終的に git push --force
が master
(または、決していじってはいけない別の重要なブランチ) に入ってしまいます。
これは、たとえば、アプリケーションを構築して展開するために別々の git リモートを使っている Deis や Heroku で展開しているときに起こるかもしれません。 長い一日の仕事の後、いつもの git push --force deis master
ではなく git push --force
を実行することは信じられないほど簡単です。 瞬く間に、あなたのチームメイトは最新の仕事をすべて失ってしまいました。
しかし、ある優秀なガイドが教えてくれたように、Don’t Panic!
最善のケースは、同じコードで作業している他の誰かが、あなたがそれを壊す直前に
master
の最新バージョンをプルしたことです。
幸運にも、その人のローカル リポジトリにはコミットの完全な履歴があり、あなたの間違いは新しいコードで上書きされ、何も失われることはないでしょう。 しかし、それほど幸運でない場合はどうでしょうか。 では、続きを読んでください!
ケース 1: 間違いの前に master にプッシュした最後の人だった
良い知らせです!
ケース 1: 間違いの前に master にプッシュした最後の人だった。 あなたの目の前に、ミスを元に戻すのに必要なものがすべて揃っています。 ただ、端末を閉じたり、消去したりしないでください。 まず、チームのチャットに入り、あなたの罪を告白してください。
シェルの git push --force
コマンドの出力で、次のような行を探します:
+ deadbeef...f00f00ba master -> master (forced update)
最初の記号群 (コミットの SHA プレフィックスみたいなもの) が解決のカギとなります。 deadbeef
はダメージを与える直前の master
への最後の良いコミットです。
ですから、必要なのは… このコミットを master
ブランチに強制的に押し戻すことです (毒をもって毒を制す!)。 あなたは今日を救いました。 6272>
ケース 2: 自分が失敗する前に、誰かが master を変更していた場合
つまり、あなたが git push --force
する直前に、誰かが大量の pull request を閉じ、master
はあなたのローカルコピーとは全く違うものになってしまったのです。 ローカルに最近のコミットがないため、git push --force sha1:master
を実行することはできません (git fetch
を実行しても、それらはもうどのブランチにも属していないため、取得することはできません)。
GitHub が到達不可能なコミットを即座に削除しないことは、私たちにとって大きなメリットとなります。 もちろん、それらを取得することはできませんが、回避策があります。
これは、リポジトリを「監視」している場合にのみ動作することに注意してください。 フィードを開き、次のようなものを探します。
an hour agoUsername pushed to master at org/repo - deadbeef Implement foo - deadf00d Fix bar
これでできました。
- URL
https://github.com/org/repo/tree/deadbeef
を作成し、deadbeef
は破損したブランチへの直近の良いコミットのハッシュです。 - GitHub のウェブ UI でブランチ/タグ切り替えを開きます。
- 新しい一時ブランチの名前を作成する (例.g.,
master-before-force-push
); - [ブランチの作成] をクリックします。
これで、不足しているコミットをすべて取得できます:
$ git fetchFrom github.com:org/repo * master-before-force-push -> origin/master-before-force-push
これで、問題は前の例で説明したものに減りました。
$ git push --force origin origin/master-before-force-push:master
まだ自分の作業が master
にある必要があるなら、その上にリベースすればよい:
$ git rebase origin/master
How to avoid such disaster future
-
GitHubとGitLabには「保護ブランチ」という機能があります。”
master
,develop
,stable
などの重要なブランチを保護ブランチとしてマークすると、誰もそこに強制的にプッシュすることができなくなります。詳細は GitHub のドキュメントをご覧ください。
-
--force
オプションの代わりに、--force-with-lease
を使ってください。 これは、あなたが作業している間に誰かが同じブランチにプッシュした (そして何も変更をプルしていない) 場合、プッシュ操作を停止します。アトラシアンのこの記事を参照してください。
-
誤って破壊的な行動をしないように、
git push --force
を使用するコマンドのエイリアスを作成する:# ~/.gitconfig deploy = "!git push --force deis \"$(git rev-parse --abbrev-ref HEAD):master\""
エイリアスについては ProGit の章をお読みください。
git checkout -b experiments
はあなたの親友です。
Pro Tip: git push
には多くのオプションがあります。 --force
と --all
は特によく合います。 このコンボは、数ヶ月間活動しなかった後、プロジェクトに復帰する際に使用できます。 特別に冒険したい気分の時は試してみてください!
。
Leave a Reply