概要
業務で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でリセットしてやり直すことが可能です。
どなたかの参考になれば幸いです。