Git でリモートに push 済みのコミットを amend したときの対応方法
Git でリモートに push した後のコミットを、ローカルで commit --amend
で変更してしまった場合の対応方法についてです。
凡ミスにより年に数回はこの状況に遭遇するので、やり方をまとめておきます。
対応オプション
対応方法のオプションがいくつかあります。
- a.
git push
に--force
(-f
)オプションをつけて無理やり push する - b. 対象のコミットを soft
reset
してからコミットし直す - c. リモートをマージしてコンフリクトを解消した新たなコミットを作る
これらのうち、オプション a は、リモートに変更が無いことを 100% 確信できる場合にかぎり使ってもよいような気もします。 ただ、万が一リポジトリを壊してしまった場合の手間が大変そうなので、個人的には現実的なオプションは b か c だと思います。 b と c の比較でいうと心理的な負担が少ないのは c の方なので、個人的には c を選んでいることが多いと記憶しています。
ということで、以下、 c の方法についてその流れをかんたんに説明します。
対応の流れ
全体の流れは、「リモートのブランチを改めてローカルで merge して、コンフリクトを解消した新たなコミットを作って、 push し直す」という流れになります。
以下サンプルコードです。
$ # push 済みのローカルのコミットを変更してしまった...
$ git commit --amend
$ # 齟齬があるため push は当然失敗する...
$ git push origin master
To ssh://[リモートリポジトリの URI]
! [rejected] master -> master (non-fast-forward)
error: failed to push some refs to 'ssh://[リモートリポジトリの URI]'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
$ # 以下 1-6 で対応
$ # 1. まずはリモートの HEAD を fetch する
$ git fetch origin master
$ # 2. (オプション)リモートとローカルのブランチに差分があることを確認する
$ git diff --shortstat master..origin/master
1 2 files changed, 79 insertions(+), 1 deletion(-)
$ # 3. リモートの( amend 前の)コードを merge する
$ git merge origin/master
Auto-merging [変更のあったファイル 1]
CONFLICT (content): Merge conflict in [変更のあったファイル 1]
Auto-merging [変更のあったファイル 2]
CONFLICT (content): Merge conflict in [変更のあったファイル 2]
Automatic merge failed; fix conflicts and then commit the result.
$ # 4. auto-merging がコンフリクトで失敗するので、コンフリクトをひとつずつ解消する
$ open [変更のあったファイル 1]
$ open [変更のあったファイル 2]
$ # 5. コンフリクトを解決したらその内容を新たにコミットする
$ git add [変更のあったファイル 1] [変更のあったファイル 2]
$ git commit -m '[コミットメッセージを適当に]'
$ # 6. 改めて push して終了
$ git push origin master
以上です。
軽微な変更を繰り返しているときについついやってしまうので、スムーズに対応できるようにしたいものです。