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

以上です。

軽微な変更を繰り返しているときについついやってしまうので、スムーズに対応できるようにしたいものです。