Edited at

git rebaseを初めて使った際のまとめ

More than 1 year has passed since last update.


環境

とくになし


はじめに

今までrebaseを使ったことが無かったのですが、コードレビューを依頼した際に「マージコミットが邪魔で見づらい…」と言われてしましました。「ログを綺麗にするため」にrebaseについて学んだことのまとめです。

まず、ログがどのように綺麗になるのかを以下に説明します。


mergeを使った場合のログ(あまり綺麗ではないログ)

例えば下図のようなブランチが存在し、自分が今featureにいるとします。この状況でbugfixが入った最新のdevelopを取り込みたいと考えているとします。



マージを使って取り込みます。



無事取り込むことができました。しかし「git log」をしてみると時系列順に並ぶためfeatureのコミットが飛び飛びになってしまい、すごく見づらくなっています。


rebaseを使った場合のログ

最初の状況は先程と同じです。



rebaseを使って取り込んでみましょう。



無事取り込むことができました。ログを見ると綺麗にまとまっています。



これならレビューもしやすい!


先にまとめ

# featureブランチで以下を行う

# mergeと違って作業ブランチにて行うので注意

# まずコミットをまとめる
git rebase -i 派生元コミット

# rebaseを行う
git rebase develop


解説


git rebaseが行っていること

新しい派生元に1つずつcherry-pickしているイメージです。

# featureブランチにて

git rebase develop



「A''」がコンフリクトしなければ続けて「B''」...



というような処理が全コミット分行われます。気をつけるべきは履歴が書き換わってしまうことです。

rebase後のコミットも「A''」や「B''」と表記していますが、コミットハッシュが変わってしまっているので、全くの別コミットになります。

既にpush済なら「-f」をつけないとpushできません。しかし、これは他の人に影響を及ぼす危険な操作なので決して人が利用しているブランチに同意も取らずに行ってはいけません。

http://qiita.com/ppworks/items/94c0107d98e55f903ea9


rebaseの途中でコンフリクトしたら...



途中でrebaseが止まり、解決を促すメッセージが表示されます。

$ git rebase develop

First, rewinding head to replay your work on top of it...
Applying: List化
Using index info to reconstruct a base tree...
M git.txt
Falling back to patching base and 3-way merge...
Auto-merging git.txt
CONFLICT (content): Merge conflict in git.txt
Failed to merge in the changes.
Patch failed at 0001 List化
The copy of the patch that failed is found in:
/Users/ma-sato/Documents/gitSample/.git/rebase-apply/patch

When you have resolved this problem, run "git rebase --continue".
If you prefer to skip this patch, run "git rebase --skip" instead.
To check out the original branch and stop rebasing, run "git rebase --abort".

メッセージの下の方に書いていますが、選択肢は「続ける」「飛ばす」「止める」の3つあります。

「飛ばす」に関しては使う場面に遭遇したことが無いので、「続ける」と「止める」についてだけ解説します。


「続ける」場合

git rebase --continue

コンフリクトを解決し、対象のファイルがaddされているのを確認した後に上記を実行します。commitする代わりに実行する感覚です。引き続きrebaseが実行されます。


「止める」場合

git rebase --abort

rebaseを行う前の状態に戻します。途中まで行っていたrebaseが全て無かったことになります。


先にコミットをまとめる

git rebase -i 派生元コミット

rebaseは1コミットずつ作業を行っていくので同じような箇所を何度も修正したコミットがあった場合、連続でコンフリクトが発生して、かなり面倒です。そこで先にコミットまとめておきます。下図のイメージになるようまとめてみます。

$ git rebase -i 4dbbac3

pick b72d8f5 List化   # A'' に該当
s 96ff85c 説明追加    # B'' に該当
s 5d7361a インデント追加  # C'' に該当

# Rebase 4dbbac3..5d7361a onto 4dbbac3 (3 command(s))
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
#
# 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.
#
# Note that empty commits are commented out

まとめたいコミットの先頭の「pick」を「s」に変えた後に「:wq」で保存して編集を終わります。

すると次はコミットメッセージを編集する画面が立ち上がります。

# This is a combination of 3 commits.

# The first commit's message is:
List化

# This is the 2nd commit message:

説明追加

# This is the 3rd commit message:

インデント追加

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date: Sun Jul 30 11:23:28 2017 +0900
#
# rebase in progress; onto 4dbbac3
# You are currently editing a commit while rebasing branch 'develop' on '4dbbac3'.
#
# Changes to be committed:
# modified: git.txt
#

squashした全コミット文のメッセージが並んでいるので適したメッセージをつけて再び「:wq」で保存して編集を終わります。

今回は1コミットにまとめてしまっていますが、あくまでログが見やすくなるように適宜まとめていきます。

このあとにrebaseすればコンフリクトの解決も必要最低限で済むので楽ちんです。


さいごに

最低限使うにあたって必要なことをまとめました。まだまだ触れていないオプションがあるので、触り次第まとめていきたいです。

▽追記:d(drop)を使った際のお話

https://qiita.com/panti310/items/0af4de5378a1ea4af4d7