10
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

git rebaseとは・git rebaseの使い所・リセット方法

Last updated at Posted at 2020-07-22

git rebaseとは・git rebaseの使い所

Mergeとの共通点

二つのブランチの内容を一つのブランチにまとめるという点でマージと同様。

また、両者とも実行時にコンフリクトが生じる可能性がある。

Mergeとの違い

  • マージは二つのブランチを川の流れのように合流させる。特にひねりがなく直感的には最もわかりやすいと思う。
  • リベースはgitの歴史を書き換えて、二つのブランチが枝分かれし始めた地点(ベース)を最新の地点にまで移動させる事で、結果枝分かれした事実そのものをなかった事にするようなもの。

ケーススタディ

  • 支流の内容を本流に取り込みたい時(feature-XXXXX -> develop 等)
    • 例えば、feature-XXXXXでの開発が一段落し、レビューも完了したので本流となるdevelopブランチに取り込みたい時などに該当する。

-> この場合は本流(develop)に支流(feature-XXXXX)をマージして取り込む。
※ 本流(develop)を支流(feature-XXXXX)にリベースはしてはいけない。なぜならdevelopは複数の人が参照しているのに、履歴が書き変わってしまうからである。

  • 本流の内容を支流に取り込みたい時(develop -> feature-XXXXX 等)
    • 例えば、developにある重要な変更を今の作業ブランチ(feature-XXXXX)でも使いたいのでdevelopをfeature-XXXXXに取り込みたい時など。

-> 支流(feature-XXXXX)を本流(develop)上にリベースする。
-> developをfeature-XXXXにマージしてもいいが、そうするとコミット履歴で、コミットが時間順に並ぶのでfeature-XXXXXとdevelopの区別がなく分かりにくくなる。rebaseだと手間がかかりすぎる時などにするくらいか。

rebaseの手順

feature-XXXXブランチをdevelopブランチ上にリベースしたいとする。

0: 当たり前だが、リモートにdevelopブランチがある場合は、その最新の変更をローカルに持ってきておく事(origin はリモートのgitリポジトリの名前)。

git pull origin develop

1: feature-XXXXブランチを複製しておく。リベースは履歴を書き換えるため、失敗した時に元に戻すのが手間になってしまうため。なお、直す手順としては、git reflogを使うこともできるので絶対ではない。git reflogについては記事最下部参照

git checkout -b feature-XXXX-copy

2: feature-XXXXブランチにチェックアウトする。その後いきなりリベースしてもいいのだが、コミットを一つ一つdevelopブランチ上に重ねていく事になるため、何度もマージコンフリクトを解消しなくてはならず面倒くさいことが多い。そのため、まずrebase -iでfeature-XXXXブランチのコミットを一つにまとめる。

git checkout feature-XXXX
git rebase -i 5634f2e

5634f2eとは、feature-XXXXとdevelopブランチの共通点(分岐点)となっているコミットのハッシュ値。

3: するとviが起動し、以下のように表示される。

なおコミットの流れは5634f2e(developブランチとの分岐点) -> 3bf6995 -> 15717d1 -> 6a36aedの順となっている。

pick 3bf6995 Entity, Repositoryを改修した。
pick 15717d1 正しいアイコン画像を設定した。
pick 6a36aed 不要な記述を消した。

# Rebase 5634f2e..6a36aed onto 5634f2e (3 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


画面に記載してある通りだが、ここではまず3bf6995 -> 15717d1 -> 6a36aedの3つを一つにまとめて、developブランチとの分岐点である5634f2eからfeature-XXXXブランチにコミットが一つだけ残るようにしていく。

なお、やっぱり辞めたい場合は:q!でviを終了すれば、特に変更なくrebaseが終了する。

4: コミットをまとめる

gitではなくviの操作法になるが、aキー、iキーなどを押して編集モードに入る。
普通のテキストエディタのような感じで、文字列を下記のように変更する。

pick 3bf6995 Entity, Repositoryを改修した。
squash 15717d1 正しいアイコン画像を設定した。
squash 6a36aed 不要な記述を消した。

# Rebase 5634f2e..6a36aed onto 5634f2e (3 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

2行目・3行目の行頭を「squash」に変えたのがお分かりいただけるだろうか。これは、一つ目のコミット「3bf6995」はそのまま残し、「15717d1」「6a36aed」に含まれる変更を「3bf6995」に合体させることを意味する。

編集終了したら:wq!で保存してviを終了する。

すると、今度はコミットメッセージ編集画面へ行く。

# This is a combination of 3 commits.
# This is the 1st commit message:

Entity, Repositoryを改修した。

# This is the commit message #2:

正しいアイコン画像を設定した。

# This is the commit message #3:

不要な記述を消した。

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date:      Thu Jul 16 13:10:41 2020 +0900
#
# interactive rebase in progress; onto 5634f2e

一まとめにしたことがわかるようにメッセージを入力し、再び:wq!で閉じる。これでコミットのまとめが完了する。

5 developブランチ上にrebaseしていく

一まとめになったコミットをdevelopにリベースする。

git rebase develop

コンフリクトが生じた場合は、それを解消する。これでリベース終了となる。

rebase が完了したが、やっぱり元に戻す(追記 2020/10/16)

feature-XXXXのコピーのブランチを作っていた場合は、そのブランチを正とする形で元にもどすことができる。

コピーのブランチを作っていなかった場合でも、git reflogが使える。git reflogとは、HEADがどこを指していたかの記録をログとして残したもので、当然rebaseでHEADがどこに移動したかも記録に残っている。そのため、rebaseもリセットすることができる。

git checkout feature-XXXX
git reflog feature-XXXX

上のコマンドを打ち込むと、reflogが表示される。

<commid id> (HEAD -> feature-XXXX) feature-XXXX@{0}: rebase finished: refs/heads/feature-XXXX onto <commit id>
<commid id> feature-XXXX@{1}: <commit message>

ここでは、feature-XXXX@{0}がリベース完了時のログ、feature-XXXX@{1}がリベース前のログである。そのため、この場合は次のコマンドでリベースを元に戻すことができる。

git reset --hard feature-XXXX@{1}

マージコミットも含めてrebaseしたい

git rebase --rebase-merge upstream

参考 git rebase --rebase-margeについて

参考

git rebaseを初めて使った際のまとめ
Git rebaseの使い方
Linuxサーバー管理入門 - gitのrebaseは作業中のブランチにmasterブランチを取り込むためのよい手段 / Git
初心者でもわかる!リベースの使い方を解説します
誤ってリベースしてしまった Git のコミットを元に戻す方法
git rebase --rebase-margeについて

10
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?