git rebaseで、コミットの順番を入れ替える!

公開:2020/11/07
更新:2020/11/14
7 min読了の目安(約6800字TECH技術記事

git rebase でコミットの順番を入れ替える!

タイトルにもある通り、

コミットの順番を入れ替えたい!

という時にはrebaseを使うと可能になります!
(rebaseは出来ることがありすぎるので、今回は入れ替えだけです)

説明用に、以下のように編集し、コミットしています。

1回目のコミット

1回目のコミット

2回目のコミット

1回目のコミット
2回目のコミット

3回目のコミット

1回目のコミット
2回目のコミット
3回目のコミット

4回目のコミット(今までの内容は削除しました)

4回目のコミット

5回目のコミット

4回目のコミット
5回目のコミット

この様にファイルを5回編集し5回コミットしました。

次に

$ git log --oneline

上記のコマンドを使用してコミットログを表示します。
その結果が以下になります。

02b6a6a (HEAD -> aho) 5回目のコミット
a772dcc 4回目のコミット
1f4e715 3回目のコミット ←消したいコミット
7e8a71e 2回目のコミット
8146b44 1回目のコミット

5回コミットしていることが確認できますね。

最後にコミットしたのが
02b6a6a (HEAD -> aho) 5回目のコミット
こちらになので現在のファイルの状態は↓になります。

4回目のコミット
5回目のコミット

今回は3回目のコミットを最新の状態にする。
という事をやっていきます。

どういうことかというと、
今は5回目のコミットが最新の状態になっていますが

3回目のコミット

1回目のコミット
2回目のコミット
3回目のコミット

ファイルは↑の状態に、

ログは↓の状態にしたい。ということです。

$ git log --oneline
1f4e715 3回目のコミット
915e642 5回目のコミット
1093030 4回目のコミット
7e8a71e 2回目のコミット
8146b44 1回目のコミット

実行手順 git rebase -i コミットID

まずは以下のコマンドを実行します

$ git rebase -i コミットID

[コミットID]に指定したコミット以降を編集できるようになります。
今回は、3回目のコミットを最新の状態にしたい!ということなので、
2回目のコミットIDを記述しています。

$ git rebase -i 7e8a71e

実行後の表示がこちら。

pick 1f4e715 3回目のコミット
pick a772dcc 4回目のコミット
pick 02b6a6a 5回目のコミット

Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# .       create a merge commit using the original merge commit's
# .       message (or the oneline, if no original merge commit was
# .       specified). Use -c <commit> to reword the commit message.
#

Commands:以下にいろいろなrebaseの使い方が表示されていますが,
今回は順番を入れ替えるだけなので、なにも使いません。

3回目のコミットを最新にするということなので、
一番最後に持ってきます。("I"を入力するとvimがINSERTモードになり入力できる様になります。)

pick a772dcc 4回目のコミット
pick 02b6a6a 5回目のコミット
pick 1f4e715 3回目のコミット

こんな感じに変更後保存します。

保存方法はINSERTモードを終了し(キーボードの"esc"ボタンを押してから、":wq"と入力して"enterボタン"。)

今回だと、3回目のコミットを最後に変更したので、
2回目のコミットの次が4回目のコミットになるわけです。

そうすると、2回目のコミットと、4回目のコミットで同じ部分を編集しているので、コンフリクトが起こります。

Auto-merging hogehoge
CONFLICT (content): Merge conflict in hogehoge
error: could not apply 1093030... 4回目のコミット
Resolve all conflicts manually, mark them as resolved with
"git add/rm <conflicted_files>", then run "git rebase --continue".
You can instead skip this commit: run "git rebase --skip".
To abort and get back to the state before "git rebase", run "git rebase --abort".
Could not apply 1093030... 4回目のコミット

↑ターミナル上の表示

2回目のコミットを優先するんか、4回目のコミットを優先するんか、どっちも反映するんかどれにするねん。

という様な内容ですね。

エディター上の表示↓

<<<<<<< HEAD
1回目のコミット
2回目のコミット

=======
4回目のコミット(今まで作成したものは削除)
>>>>>>> 1093030... 4回目のコミット

正直、最新を3回目のコミットにするので
何でもいいっちゃ何でもいいのですが、
今回は順番通りに4回目を採用することにします。

注意!ここで2回目のコミットを選ぶと4回目のコミットは消えます!

色々試していて気付きました。笑
まあ、4回目のコミットを採用しないのなら別にいらないよね。という事だと思います。笑

厳密にはコミットメッセージ(内容は何もない)は残すか、コミットを消すかの操作を任意で行うことができます。

残す場合は

$ git commit --allow-empty

消す場合は

$ git rebase --skip

コマンドを実行します。
(全部実行時のターミナルに書いてます)

作業に戻ります。
コンフリクトを解消した後、以下のコマンドで状態を確認してみます。

$ git status

実行後の表示がこちら。

interactive rebase in progress; onto 7e8a71e
Last command done (1 command done):
   pick 1093030 4回目のコミット
Next commands to do (2 remaining commands):
   pick 915e642 5回目のコミット
   pick 1f4e715 3回目のコミット
  (use "git rebase --edit-todo" to view and edit)
You are currently rebasing branch 'aho' on '7e8a71e'.
  (fix conflicts and then run "git rebase --continue")
  (use "git rebase --skip" to skip this patch)
  (use "git rebase --abort" to check out the original branch)

Unmerged paths:
  (use "git restore --staged <file>..." to unstage)
  (use "git add <file>..." to mark resolution)
	both modified:   hogehoge

no changes added to commit (use "git add" and/or "git commit -a")

いろいろ書いてますが今回はこちら。

(fix conflicts and then run "git rebase --continue")

コンフリクトを解消したら

$ git rebase --continue

してねと書いてあるので実行します。

$ git add 〇〇

が事前に必要です。

実行結果がこちら。

4回目のコミット

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# interactive rebase in progress; onto 7e8a71e
# Last command done (1 command done):
#    pick 1093030 4回目のコミット
# Next commands to do (2 remaining commands):
#    pick 915e642 5回目のコミット
#    pick 1f4e715 3回目のコミット
# You are currently rebasing branch 'aho' on '7e8a71e'.
#
# Changes to be committed:
#       modified:   hogehoge

ここでコミットメッセージを変更したければできます。

("I"を入力するとvimがINSERTモードになり入力できる様になります。)
今回は変更せずにいきます。

そうすると、またコンフリクトがおきます。

$ git rebase --continue                                                                                                  日 11/ 1 05:35:41 2020
[detached HEAD edfea2c] 4回目のコミット
 1 file changed, 1 insertion(+), 2 deletions(-)
Auto-merging hogehoge
CONFLICT (content): Merge conflict in hogehoge
error: could not apply 1f4e715... 3回目のコミット
Resolve all conflicts manually, mark them as resolved with
"git add/rm <conflicted_files>", then run "git rebase --continue".
You can instead skip this commit: run "git rebase --skip".
To abort and get back to the state before "git rebase", run "git rebase --abort".
Could not apply 1f4e715... 3回目のコミット

4回目のコミットの次は5回目のコミットですが、
4回目と5回目のコミットは同じ箇所を変更していないので
コンフリクトが起きず通過してます。

なので実質5回目のコミットと3回目のコミットがコンフリクトが起きているということです。

ログを確認してみると

2d1d08f (HEAD) 5回目のコミット
edfea2c 4回目のコミット
7e8a71e 2回目のコミット
8146b44 1回目のコミット

現在は5回目のコミットにいることが確認できますね。
エディター上では下記の様になっています。

<<<<<<< HEAD
4回目のコミット(今まで作成したものは削除)
5回目のコミット
=======
1回目のコミット
2回目のコミット
3回目のコミット
>>>>>>> 1f4e715... 3回目のコミット

最新の状態を3回目のコミットにすることが目的だったので、
エディター上で3回目のコミットを反映すると完成です。

一応ログを確認。

$ git log --oneline
1f4e715 3回目のコミット
915e642 5回目のコミット
1093030 4回目のコミット
7e8a71e 2回目のコミット
8146b44 1回目のコミット
 

できてますね!!

今回はコミット履歴や、内容を消さない方向で進めていましたが
別に消してもいいから3回目のコミットを最新にしたい。
ということなら

3回目のコミットを最新にする=4、5回目のコミットはいらないので
削除して、実行しても同じ結果になります。

$ git rebase -i 7e8a71e

を実行して、pickd(drop)に変更します。
d(drop)は削除です。

pick 1f4e715 3回目のコミット
d a772dcc 4回目のコミット
d 02b6a6a 5回目のコミット

変更したら:wqで保存してログを確認します

$ git log --oneline


1f4e715 (HEAD -> aho) 3回目のコミット
7e8a71e 2回目のコミット
8146b44 1回目のコミット

こんな感じになっていれば完成です!

他にもrebaseはいろいろできて、超便利です!
ただ、便利が故に理解せずに使うと痛い目をみます。

この時はまだ、rebaseの恐ろしさを知りませんでした。。。。。。。
その時の恐怖体験はまた別の記事で。。。。。。

思い出すだけでも胃が痛い。笑