git rebase -i を使用する目的とその結果、方法について


2021/04/21
コメントを頂き、内容を修正しました。
この記事はgit rebaseの中でも、git rebase -iについて紹介していきます。

0. はじめに

この記事ではgit rebase -iの目的とその結果、方法を記述していきます。また、その中でも特にeditに関する内容に触れていきます。

この記事は、私がリベースを行った際に、その結果がイメージできなかったのでまとめておこうと思いました。なのでgit rebase -iの結果について、どう変化するのか、を伝えられればいいなと思います。

1. "git rebase -i"を行う目的

git rebase -iの目的は過去の改竄を行うことです。

私がgit rebase -iを行う必要性が生じたのは、「ファイル内にEメールアドレスを直接記述」し、その内容をコミットしたからです。そのミスには暫くしてから気づき、過去の改竄が必要になりました。

ちなみに、変更の差分はgit diffを用いて確認できます。それにより、過去の変更履歴も確認が可能です。それゆえ「ファイル内にEメールアドレスを直接記述」していない過去に変更する必要があり、git rebase -iを行いました。

2. "git rebase -i"の結果

まず初めに、git rebaseで何が起こるか確認します。git rebase後でも、改竄を加えた部分以外は同じです。しかし、コミット履歴が変更されます。

以下にgit rebase -iの前後のログの例を示します。

下の例では、新しく'test_branch'を用意し、commit[5555555]の内容をeditしています。

before

ターミナル
git log —-oneline

7777777 (HEAD -> develop_origin, origin/develop_origin)This is commit E
6666666 This is commit D
5555555 (third-branch)This is commit C
4444444 This is 3rd commit B
3333333 (second-branch)This is commit A
2222222 This is 1st commit
1111111 (origin/master, master) Initialize repository

After

ターミナル
git log —-oneline

ccccccc (HEAD -> test_branch)This is commit E
bbbbbbb This is commit D
aaaaaaa This is commit C rebased!!
4444444 This is 3rd commit B
3333333 (second-branch)This is commit A
2222222 This is 1st commit
1111111 (origin/master, master) Initialize repository

3. "git rebase -i"の方法

ここでは、リベースの中でも、editの方法を解説します。ちなみに、私は以下の記事を参考にリベースさせて頂きました。とても分かりやすいので、おすすめです。

Git のコミット履歴を大胆に書き換えるなら git rebase -i がオススメ

リベースでeditするステップは以下の5つです。

1) リベースを行う ( git rebase -i [コミット番号]
2) 改竄したいコミット番号を指定する ( pickedit
3) 過去を改竄する
4) コミットし直す ( git commit —amend
5) 現在に戻ってくる ( git rebase continue

以下、詳細の操作について説明していきます。ちなみに例では、2章で用いたコードを用います。

1) リベースを行う

まず、リベースのの基本的な使い方として git rebase -i <after-this-commit> という構文で行います。このコードをするとViエディタが起動します。

ターミナル
git rebase -i <after-this-commit>
# ex)
git rebase -i 4444444444444..
Viエディタ
pick 6666666 This is commit D
pick 5555555  This is commit C

# Rebase 4444444..5555555 onto 4444444 (2 commands)
#
# 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.
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.

<after-this-commit>には、コミット番号を指定します。このコミット番号によりリベースする範囲を決定します。具体的には、指定したコミット番号より一つ後ろのコミット番号から、HEADまでの間の内容をリベースすることが出来ます。

例では4444444のコミットを指定している為それ以降でHEADまでのコミットがリベース可能範囲です。
つまり、66666665555555がリベース可能になります。

2) 改竄したいコミット番号を指定する

次にViエディタで、改竄したいコミットを指定します。その方法は、改竄したいコミットの横にあるpickedit変更します。そしてViエディタを:wqで保存します。

Viエディタ
edit 5555555  This is commit C
pick 6666666 This is commit D

# Rebase 4444444..6666666 onto 4444444 (2 commands)
#
# Commands:
# .
#  省略
# .
# However, if you remove everything, the rebase will be aborted.

2個のコミットから1番上を選択すると以下のようなターミナルに変更されます。

ちなみに、この時点でリベースをせずに中止するコマンドがあります。以下のコマンドです。

このコマンドを実行することで、リベースを行う前の状態へ戻す事が可能です

git rebase --abort

ちなみにここでは過去の改竄の為editを用いていますが、リベースには他にもコマンドがあり、目的に応じたコマンドをここでは選択します。

3) 過去を改竄する

ここでは改竄したい過去の内容を変更します。自分の場合は、Eメールアドレスを直接記述していたので、その変更を削除します。

ターミナル
:~/myapp (test_branch|REBASE 1/2)$ git diff
diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb
--- a/config/initializers/devise.rb
+++ b/config/initializers/devise.rb
@@ -24,7 +24,7 @@ Devise.setup do |config|
   # with default "from" parameter.
-  config.mailer_sender = '[email protected]'
+  config.mailer_sender = Settings.google_account[:email]

   # Configure the class responsible to send e-mails.

4) コミットし直す

変更をステージングし、コミットし直します。
注意点として、ここではコミットのやり直しを意味する—amendオプションを付随させます。

git ci --amend

5) 現在に戻ってくる

目的通りに過去を改竄できたらリベースは終了です。リベース完了を意味する以下のコマンドを実行します。

git rebase --continue

先程の変更で、その後の変更にコンフリクトが生じていない場合は、リベース成功です。

コンフリクトが生じている場合には、コンフリクトを解消し、もう一度上記のコマンドを実行すればリベース完了です。リベース後はコミット履歴が変更されます。

ターミナル
git log —-oneline

ccccccc (HEAD -> test_branch)This is commit E
bbbbbbb This is commit D
aaaaaaa This is commit C rebased!!
4444444 This is 3rd commit B
3333333 (second-branch)This is commit A
2222222 This is 1st commit
1111111 (origin/master, master) Initialize repository

4. おわりに

最後まで、読んで頂きありがとうございました!

まだまだ学習中なので、間違っている部分などコメントなどして頂けると嬉しいです!

余談ですが...

私がリベースを行う必要があったのは、Githubでpublicにしたいリポジトリに裸のEメールアドレスをpushしたからです。セキュリティ的に脆弱になってしまう為、リベースを行いました。大変だったぜ。次から気をつけなければ、
リポジトリをpublicにする為には、リベースだけでなくリポジトリを一新する必要がありました。なぜかというと、リベースでは、改竄前のコミット履歴も残っている為、履歴を辿ればEメールアドレスを確認できてしまうからです。

参考