git rebase -i <コミットID> で履歴をいじる際にコンフリクトが発生することがある。この時、コンフリクトの解消の仕方次第では、コミットが消えることがある、というのが今回の話題。
今回取り上げる題材は以下。
$ cat test.txt 111 222 333 444
$ git log --oneline 6c0d1f1 (HEAD -> master) add 444 7e2024d add 333 338ac95 add 222 7a366fb add 111
上記において、「338ac95 add 222」のコミットと「6c0d1f1 add 444」のコミットを纏めてみる。
まずは、上記の状態にするための前準備。
$ git init Initialized empty Git repository in xxxxx $ touch test.txt $ echo 111 >> test.txt $ git add test.txt $ git commit -m "add 111" [master (root-commit) 7a366fb] add 111 1 file changed, 1 insertion(+) create mode 100644 test.txt $ echo 222 >> test.txt $ git add test.txt $ git commit -m "add 222" [master 338ac95] add 222 1 file changed, 1 insertion(+) $ echo 333 >> test.txt $ git add test.txt $ git commit -m "add 333" [master 7e2024d] add 333 1 file changed, 1 insertion(+) $ echo 444 >> test.txt $ git add test.txt $ git commit -m "add 444" [master 6c0d1f1] add 444 1 file changed, 1 insertion(+)
ここで、222 を追加した時のコミットと 444 を追加した時のコミットを纏めるために、以下のように git rebase -i を実行する。git rebase -i で指定するコミットIDは、纏めたいコミットの1個前のコミットの ID であることに注意。
$ git rebase -i 7a366fb
上記を実行すると、以下が開く。
pick 338ac95 add 222 pick 7e2024d add 333 pick 6c0d1f1 add 444
これを以下のように変更する。
pick 338ac95 add 222 s 6c0d1f1 add 444 pick 7e2024d add 333
「38ac95 add 222」のコミットに、「6c0d1f1 add 444」のコミットを squash して統合している。
すると、以下のようにコンフリクトが発生する。
Auto-merging test.txt CONFLICT (content): Merge conflict in test.txt error: could not apply 6c0d1f1... add 444 hint: Resolve all conflicts manually, mark them as resolved with hint: "git add/rm <conflicted_files>", then run "git rebase --continue". hint: You can instead skip this commit: run "git rebase --skip". hint: To abort and get back to the state before "git rebase", run "git rebase --abort". Could not apply 6c0d1f1... add 444
対象のファイル test.txt の中身は以下になっている。
$ cat test.txt 111 222 <<<<<<< HEAD ======= 333 444 >>>>>>> 6c0d1f1 (add 444)
コンフリクトを解消するため、これを以下のように編集する。
$ cat test.txt 111 222 444
ここで「333」の行を残すと、rebase終了後に「7e2024d add 333」のコミットが消える。 (test.txt の最終的な内容は同じにはなるが。)
おそらく、「333」を残すと、git 的には「7e2024d add 333」のコミットは不要と判断するのだろう。なので、rebase する際は、今適用を試みているコミット適用後、ファイルがどんな状態になるべきか、を考える必要がある。
test.txt の編集後、rebase を継続する。
$ git add test.txt $ git rebase --continue [detached HEAD eb59bb4] add 222 & 444 Date: Wed Apr 6 21:29:12 2022 +0900 1 file changed, 2 insertions(+) Auto-merging test.txt CONFLICT (content): Merge conflict in test.txt error: could not apply 7e2024d... add 333 hint: Resolve all conflicts manually, mark them as resolved with hint: "git add/rm <conflicted_files>", then run "git rebase --continue". hint: You can instead skip this commit: run "git rebase --skip". hint: To abort and get back to the state before "git rebase", run "git rebase --abort". Could not apply 7e2024d... add 333
すると、上記のように、再度コンフリクトが発生するので、以下のように解消する。
$ cat test.txt 111 222 <<<<<<< HEAD 444 ======= 333 >>>>>>> 7e2024d (add 333) $ cat test.txt 111 222 333 444
ここも、前に適用したコミット (add 222 & 444) の後、このコミット (add 333) を適用すると、ファイルがコミット適用後にどのような状態になるべきかを考える必要がある。
test.txt の編集後、rebase を継続する。
$ git add test.txt $ git rebase --continue [detached HEAD 976efc5] add 333 1 file changed, 1 insertion(+) Successfully rebased and updated refs/heads/master.
以上で rebase は完了した。ここで rebase 結果の確認を行う。
$ cat test.txt 111 222 333 444 $ git log --oneline 976efc5 (HEAD -> master) add 333 eb59bb4 add 222 & 444 7a366fb add 111 $ git diff 7a366fb eb59bb4 diff --git a/test.txt b/test.txt index 58c9bdf..65672a7 100644 --- a/test.txt +++ b/test.txt @@ -1 +1,3 @@ 111 +222 +444 $ git diff eb59bb4 976efc5 diff --git a/test.txt b/test.txt index 65672a7..337d413 100644 --- a/test.txt +++ b/test.txt @@ -1,3 +1,4 @@ 111 222 +333 444
上記の通り、意図した通りの test.txt およびコミットログになっている。
途中でも述べた通り、git rebase -i でコミット履歴をいじる時にコンフリクトしたら、今適用しようとしているコミットが適用された後、対象のファイルがどのようになっているべきかを考えながら、コンフリクト対象のファイルの修正を行う必要がある。