Just do IT

思うは招く

git rebase -i の使い方と手順

git rebase -i で何ができるの?

  • 複数のコミットを1つにまとめられる
  • コミットの履歴を変更できる

-i は --interactive の略で、「(CLIと)対話的に rebase をできる」といった感じ。

なんのために使うの?

  • 「コミット細かくしすぎたからまとめたい(慎重にいきすぎた!)」
  • 「コミットログをもうちょっとまとめてきれいにしたい!」

てなとき。

少々クセはあるものの、使い慣れたらとても便利。

git rebase -i 手順例

rebase -iを実行するため、適当なディレクトリとファイルを作成する。その後git initし、コミットを重ねる。(コピペしやすいようにシェルの$は抜いています)

とりあえず以下コマンドをすべてコピペしてターミナルで実行しましょう。

mkdir git-rebase-i
cd git-rebase-i
git init
echo "Python" > sample.txt
git add .
git commit -m "commit 1"
echo "Java" >> sample.txt
git add .
git commit -m "commit 2"
echo "Go" >> sample.txt
git add .
git commit -m "commit 3"
echo "Javascript" >> sample.txt
git add .
git commit -m "commit 4"
echo "Ruby" >> sample.txt
git add .
git commit -m "commit 5"

いちおうファイルの中身を確認しておく。

cat sample.txt

Python
Java
Go
Javascript
Ruby

コミットログを確認する。

git log --graph --oneline

* a3764df (HEAD -> master) commit 5
* 4eea250 commit 4
* 890a236 commit 3
* 5bea072 commit 2
* bd2030a commit 1

今回は、コミット4と5をまとめてみる。ここで rebase -i を使うのだが、コミット3のハッシュを指定する点に注意する。

#コミット3を指定している
git rebase -i 890a236

すると、次のようにエディタが開く。

  1 pick 4eea250 commit 4
  2 pick a3764df commit 5
  3 
  4 # Rebase 890a236..a3764df onto 890a236 (2 commands)
  5 #
  6 # Commands:
  7 # p, pick <commit> = use commit
  8 # r, reword <commit> = use commit, but edit the commit message
  9 # e, edit <commit> = use commit, but stop for amending
 10 # s, squash <commit> = use commit, but meld into previous commit
 11 # f, fixup <commit> = like "squash", but discard this commit's log message
 12 # x, exec <command> = run command (the rest of the line) using shell
 13 # b, break = stop here (continue rebase later with 'git rebase --continue')
 14 # d, drop <commit> = remove commit
 15 # l, label <label> = label current HEAD with a name
 16 # t, reset <label> = reset HEAD to a label
 17 # m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
 18 # .       create a merge commit using the original merge commit's
 19 # .       message (or the oneline, if no original merge commit was
 20 # .       specified). Use -c <commit> to reword the commit message.
 21 #
 22 # These lines can be re-ordered; they are executed from top to bottom.
 23 #
 24 # If you remove a line here THAT COMMIT WILL BE LOST.
 25 #
 26 # However, if you remove everything, the rebase will be aborted.
 27 #
 28 # Note that empty commits are commented out
~

今回は4と5をまとめたいので、2行目(コミット5)の先頭のpicksquashに変更する。※sだけでもOK。

1 pick 4eea250 commit 4
2 squash 3764df commit 5

コミットメッセージを書くようにエディタが再び開くので、適当にメッセージをつける。

#コミットメッセージを書く  
rebase test

#ここから
1 # This is a combination of 2 commits.
2 # This is the 1st commit message:
3 
4 commit 4
5 
6 # This is the commit message #2:
7 
8 commit 5
9 
#ここまでは削除してOK

10 # Please enter the commit message for your changes. Lines starting
11 # with '#' will be ignored, and an empty message aborts the commit.
12 #
13 # Date:      Sun Aug 9 09:04:30 2020 +0900
~

Successfully rebased がでるはず。

[detached HEAD d37bfd3] rebase test
 Date: Sun Aug 9 09:04:30 2020 +0900
 1 file changed, 2 insertions(+)
Successfully rebased and updated refs/heads/master.

ログを確認してみよう。

$ git log --graph --oneline
#4と5が合体している
* d37bfd3 (HEAD -> master) rebase test
* 414f7bc commit 3
* a46265f commit 2
* fed9aef commit 1

ファイルを確認してみると、内容自体は変更されていない。rebase -i は成功している。

cat sample.txt 
Python
Java
Go
Javascript
Ruby

応用編

次はもうちょっと実践的にしてみる。挙動をわかりやすくするため、今使っていたディレクトリを削除し、また同じ準備をする。

cd ..
rm -rf git-rebase-i
mkdir git-rebase-i
cd git-rebase-i
git init
echo "Python" > sample.txt
git add .
git commit -m "commit 1"
echo "Java" >> sample.txt
git add .
git commit -m "commit 2"
echo "Go" >> sample.txt
git add .
git commit -m "commit 3"
echo "Javascript" >> sample.txt
git add .
git commit -m "commit 4"
echo "Ruby" >> sample.txt
git add .
git commit -m "commit 5"
$ git log --graph --oneline
* 0731f42 (HEAD -> master) commit 5
* a8e0dd3 commit 4
* deb6b4e commit 3
* 0f3b62e commit 2
* aa6bf82 commit 1

今回はつぎのようにコミットをまとめてみる。

  • 2と3をまとめる
  • 4と5をまとめる
#コミット1を指定する
$ git rebase -i aa6bf82

エディタが開く。

1 pick 0f3b62e commit 2
2 pick deb6b4e commit 3
3 pick a8e0dd3 commit 4
4 pick 0731f42 commit 5
5 
6 # Rebase aa6bf82..0731f42 onto aa6bf82 (4 commands)
7 #
8 # Commands:
9 # p, pick <commit> = use commi
~

2行目と、4行目の先頭にあるpickを削除し、squashを意味する「s」を記入する。

1 pick 0f3b62e commit 2
2 s deb6b4e commit 3
3 pick a8e0dd3 commit 4
4 s 0731f42 commit 5

この場合、コミットをまとめる作業が2回発生するので、コミットメッセージを書くエディタも2回開く。

1 2&3 #記入
2 
3 # This is a combination of 2 commits.
4 # This is the 1st commit message:
5 
6 commit 2
7 
8 # This is the commit message #2:
9 
10 commit 3
1 4&5 #記入
2 
3 # This is a combination of 2 commits.
4 # This is the 1st commit message:
5 
6 commit 4
7 
8 # This is the commit message #2:
9 
10 commit 5

保存、終了する。そしてログを確認すると・・・

$ git log --graph --oneline
* 1ca741d (HEAD -> master) 4&5
* b1aecb9 2&3
* aa6bf82 commit 1

結果:

  • コミット4と5が合体した
  • コミット2と3が合体した

これで複数のコミットの固まりをつくることができた。こちらのほうがより実践的かもしれない。

push するときは

今回の作業をするとコミットハッシュが変わるため、普通にpushしてもエラーが出る。

そのため、--force-with-lease origin オプションをつけてpushする。

git push --force-with-lease origin "branch" 

rebase -i を中止したい

CLIにブランチ名を表示するよう設定している場合、rebase の実行中は(master|REBASE-i)と表示される。

rebase を中止するにはgit rebase --abortを実行する。

:~/dev/git-rebase-i (master|REBASE-i)
$ git rebase --abort
↓
:~/dev/git-rebase-i (master)

感想

これで「あかん、コミット乱発しすぎた・・・」なんてことを心配する必要はなくなりますね👍

参考

今回使った squash 以外にも edit などいろんな方法があるのですが、以下の記事が学習に有効でした。感謝🙏