【Git初級】git rebaseでcommitの順番を入れ替えてconflictするとどうなるのか

記事タイトルとURLをコピーする

概要

業務でgit rebaseでcommitを整理する機会があり、
ふとcommitの順番入れ替えたらどうなるんだろ?と思ったので
実際に試した一連の流れとrebaseの基本についてご紹介です。

前提

ローカルブランチでの作業前提です。
リモートブランチに対するcommitの整理や作業は含みません。

先に結果

git rebaseで編集しようとした対象commitが全てなかったことにされ、より過去のcommitの状態になる でした。

git rebaseの基本

git rebaseはcommitの内容を整理できるコマンドです。
開発時はcommitの粒度や差分を意識しながら開発することが望ましいですが、
commitを忘れてしまったり、誤った内容をcommitをしてしまうことはままあると思います。

そんな時はrebaseを利用してcommitの履歴や内容を修正できます。
またレビューを依頼する際にも、レビュアーがレビューしやすいようにcommitを作り直すことができます。

git rebaseでできること

git rebaseでできることをいくつか列挙します

基本(初級)

  • commitの順番を入れ替える
  • commitをまとめる
  • 不要なcommitを削除する

その他

本記事では取り上げませんが、以下のような中級から上級の操作も可能です。

中級

  • コミットの修正・編集
  • リモートの最新コミットに追従する
  • コミットを分割する

上級

  • 別ブランチの変更を取り込む(マージと同様の操作)
  • git rebase --ontoを使った高度な操作
  • 複雑なコンフリクト解決

変更内容の確認

順番を入れ替える前に変更内容を確認します。

git logで変更履歴を確認

下が一番古いcommitで、上にいくにつれて新しいcommitとなります。

$ git log
commit afc77a1a8eccc187ff7729ef3fcfe3c1b32b0672
Author: Ryota Orito <orito@serverworks.co.jp>
Date:   Thu Oct 10 12:47:49 2024 +0900

    remove hoge

commit c22b8235b444f7cc85b76623d88867e70baec324
Author: Ryota Orito <orito@serverworks.co.jp>
Date:   Thu Oct 10 12:46:58 2024 +0900

    remove fuga

commit 5cac58ecd7978666dabde035c71c43597364612e
Author: Ryota Orito <orito@serverworks.co.jp>
Date:   Thu Oct 10 12:45:27 2024 +0900

    add fuga

commit 71815dbc069c61ebdb3dfdba2eb5012d964cd56e
Author: Ryota Orito <orito@serverworks.co.jp>
Date:   Thu Oct 10 12:44:47 2024 +0900

    add hoge

以下で、変更内容の概要の説明と合わせて差分をgit diffで確認します。

fugaを追記

1行目にhogeがある状態から、2行目にfugaを追記しました。

$ git diff 71815dbc069c61ebdb3dfdba2eb5012d964cd56e 5cac58ecd7978666dabde035c71c43597364612e
diff --git a/test b/test
index 2262de0..e42f4ce 100644
--- a/test
+++ b/test
@@ -1 +1,2 @@
 hoge
+fuga

fugaを削除

2行目にfugaがある状態から、そのfugaを削除しました。

$ git diff 5cac58ecd7978666dabde035c71c43597364612e c22b8235b444f7cc85b76623d88867e70baec324
diff --git a/test b/test
index e42f4ce..2262de0 100644
--- a/test
+++ b/test
@@ -1,2 +1 @@
 hoge
-fuga

hogeを削除

初めにあったhogeを、削除しました。

$ git diff c22b8235b444f7cc85b76623d88867e70baec324 afc77a1a8eccc187ff7729ef3fcfe3c1b32b0672
diff --git a/test b/test
index 2262de0..e69de29 100644
--- a/test
+++ b/test
@@ -1 +0,0 @@
-hoge

commitの順番を入れ替える

今回試す入れ替えは、
「fugaを追記→fugaを削除」
このcommitの順番を入れ替えて、
「fugaを削除→fugaを追記」
とします。

本来は追記した後にその追記したものを削除しているのですが、
順番が逆になると削除すべき対象がないことになり、実際にはありえない変更です。

git rebase

以下コマンドを打つことで、編集画面でcommit履歴を編集します。

$ git rebase -i HEAD~3

「HEAD~3」部分で整理したい対象のcommit数を指定します。

変更前

pick 5cac58e add fuga           //fugaを追記 ← これと
pick c22b823 remove fuga    //fugaを削除 ← これを入れ替える
pick afc77a1 remove hoge      //hogeを削除

ちなみに、git rebaseの編集画面上はgit logの出力結果とは逆で、
下が最新で上に行くにつれて古いcommitです。

変更後

pick c22b823 remove fuga    //fugaを削除
pick 5cac58e add fuga           //fugaを追記
pick afc77a1 remove hoge      //hogeを削除

編集を終えたら保存して画面を閉じます。

保存後、結果

The previous cherry-pick is now empty, possibly due to conflict resolution.
If you wish to commit it anyway, use:

    git commit --allow-empty

Otherwise, please use 'git rebase --skip'
interactive rebase in progress; onto 71815db
Last command done (1 command done):
   pick c22b823 remove fuga
Next commands to do (2 remaining commands):
   pick 5cac58e add fuga
   pick afc77a1 remove hoge
  (use "git rebase --edit-todo" to view and edit)
You are currently rebasing branch 'main' on '71815db'.
  (all conflicts fixed: run "git rebase --continue")

nothing to commit, working tree clean
Could not apply c22b823... remove fuga

何やらエラーっぽいものが表示されました。

和訳

以前のチェリーピックは現在空です。おそらく競合解決が原因です。
それでもコミットしたい場合は、次を使用します:

git commit --allow-empty

それ以外の場合は、「git rebase --skip」を使用してください
対話型リベースが進行中です。71815db へ
最後に実行したコマンド (1 つのコマンドが完了):
pick c22b823 remove fuga
次に実行するコマンド (残り 2 つのコマンド):
pick 5cac58e add fuga
pick afc77a1 remove hoge
(表示および編集するには、「git rebase --edit-todo」を使用します)
現在、ブランチ「main」を「71815db」にリベースしています。
(すべての競合が修正されました: 「git rebase --continue」を実行)

コミットするものはありません。作業ツリーはクリーンです
c22b823 を適用できませんでした... fuga を削除

どうやらコンフリクト(競合)していると判定され、commitの編集がうまくいかなかったようです。

git logの結果

3つ分のcommitが全てなかったことにされ、より過去の「add hoge」した状態へとなりました。

$ git log
commit 71815dbc069c61ebdb3dfdba2eb5012d964cd56e (HEAD)
Author: Ryota Orito <orito@serverworks.co.jp>
Date:   Thu Oct 10 12:44:47 2024 +0900

    add hoge

ファイルの内容

最新のcommitがなかったことにされたため、hogeは削除されていない状態になりました。

$ cat test
hoge

結果、commitとファイル内容のいずれも一番初めにcommitした状態になりました。
順番を入れ替えた結果競合となるような場合は、rebaseで指定したcommitは全てなかったこととして整理されるようです。

rebaseを取り消してなかったことにする

本来はある程度競合が発生しないことを見越して順番を入れ替えると思います。
現状の結果は意図しないもののはずなので、戻してrebaseをやり直したいケースが想定されます。

--abortオプションで戻すことが可能なので実施してみます。

$ git rebase --abort

戻ったことを確認

$ git log
commit afc77a1a8eccc187ff7729ef3fcfe3c1b32b0672 (HEAD -> main)
Author: Ryota Orito <orito@serverworks.co.jp>
Date:   Thu Oct 10 12:47:49 2024 +0900

    remove hoge

commit c22b8235b444f7cc85b76623d88867e70baec324
Author: Ryota Orito <orito@serverworks.co.jp>
Date:   Thu Oct 10 12:46:58 2024 +0900

    remove fuga

commit 5cac58ecd7978666dabde035c71c43597364612e
Author: Ryota Orito <orito@serverworks.co.jp>
Date:   Thu Oct 10 12:45:27 2024 +0900

    add fuga

commit 71815dbc069c61ebdb3dfdba2eb5012d964cd56e
Author: Ryota Orito <orito@serverworks.co.jp>
Date:   Thu Oct 10 12:44:47 2024 +0900

    add hoge

最後に

git rebaseでcommitの順番を入れ替えたり、競合が発生するような操作をした場合は、
git rebase --abortでリセットしてやり直すことが可能です。

どなたかの参考になれば幸いです。

折戸 亮太(執筆記事の一覧)

2021年10月1日入社
クラウドインテグレーション部技術1課

屋根裏エンジニア