LoginSignup
11
10

More than 3 years have passed since last update.

GitHubのマージとリベースについて

Last updated at Posted at 2016-12-28

絶賛 Git 勉強中でして、自分向けのメモ書きとしてマージとリベースの違いを調べて整理してみました。

GitHubにはほかのブランチの更新分を自分のブランチに取り込む際、git merge/git rebaseの二つのコマンドがありますが、その違いを整理してみました。

やったこと

devブランチから派生した dev_#50, dev_#60があって並行で開発していたとして、dev_#60 がさきにdevにマージされたとします。dev_#50の開発者は、書き換えられたdevの更新分を取り込んだうえで、さらにdevへ自分の更新分をマージしてもらいたいわけですが、devの更新分を「マージ」で取り込んだ場合と「リベース」で取り込んだ場合で、どうなるかって比較をしてみました。

臨場感(?)を出すため、マージする時に修正をコンフリクトするようにしてあります。

Calc.java
public class Calc{
  public double execute(int source){
    return source ;
  }

}

こんなソースに、

dev_#60で修正

Calc.java
public class Calc{
  public double execute(int source){
   // 消費税対応1.05倍 #60 2016/12/26
   return source * 1.05;
  }

}

こんな修正や

dev_#50で修正

Calc.java
public class Calc{
  public double execute(int source){
   /* 消費税対応1.08倍 #50 2016/12/26 */
   return source * 1.08;
 }

}

こんな修正を入れてコンフリクトさせます。

繰り返しですが、dev_#60分はdevに取込済みで、それをふまえてdev_#50の更新をdevへ取り込むケースを考えます。

初期設定

mkdir sample && cd $_
git init

Calc.javaを作成し、コミットします

git add Calc.java  && git commit -m 'initial'

利用するブランチを作成します。

git checkout -b dev && git checkout -b dev_#50 && git checkout -b dev_#60

まずdev_#60でソースを修正し、コミットとdevへのマージを行います

git commit -a -m '消費税対応1.05倍 #60 2016/12/26'
git checkout dev
git merge --no-ff dev_#60

つづいて、dev_#50でソースを修正し、コミットまでしておきます。

git checkout dev_#50
ここでコード修正。
git commit -a -m '消費税対応1.08倍 #50 2016/12/26'

ここまでで、dev,dev_#60,dev_#50 の状態は下記のようになりました。

before.png

マージ

まずは、普通にマージします。

$ git checkout dev_#50
$ git merge dev

このとき、競合が起きますが、落ち着いて修正を行い、

$ git add Calc.java
$ git commit -m 'merge commit'

でマージ完了です。さらに、dev側にマージします

$ git checkout dev
$ git merge --no-ff dev_#50

さて、このマージが完了したdevですが、

$ git checkout dev_#50
$ git merge dev

このマージはすでにdev_#50で修正されたところに dev分(すなわちdev_#60の修正)をマージしています。 そしてそれがdevへマージされているのがわかります。

merge.png

これはこれでOKなんですが、devからみると、dev_#60でのマージ履歴はいらない情報だったりしますね。

リベース

そこでリベースです。

$ git checkout dev_#50
$ git rebase dev

このとき競合がでてなんかごっちゃごちゃ言われますが、落ち着いて修正を行い、

$ git add Calc.java
$ git rebase --continue

ってやってリベースのcontinueを選びます。これでリベース完了です。リベースの考えかたに従い、まずdev_#50のコミットがいったん待避され、devの修正が取り込まれて、さらにdev_#50の新規コミットが行われます。当然、もとのdev_#50のコミットとは別のコミットですね。

ちなみに、rebase の競合をキレイにするのっていろいろめんどくさく、その手順は

git rebaseでのブランチ融合でコンフリクト解消

に丁寧にまとめてありました。感謝します!

さて、さらにdev側にマージします

$ git checkout dev
$ git merge --no-ff dev_#50

今回はマージでなくてリベースを行ったので、devに取り込んだもの(すなわちdev_#60の修正)のつぎに、dev_#50の修正がマージされました。dev_#50が「dev_#60を取り込む前のdev」からブランチした事実は'なかったこと'になってます。

rebase.png

まとめ

マージは、文字通りのマージで、devの修正をdev_#50の「直近状態」にマージしました。最終的には、その事実も含めてdevにマージされていきました。

リベースは文字通り、re-baseすることで、dev_#60を取り込んだdevをベースに、dev_#50の更新分がコミットされ、そしてdevにマージされていきました。

今回みたいなdevを中心にチケット毎のブランチで開発するようなケースだと、devでの更新分を取り込むようなケースでは、リベースをするのが正しそうですね。。。

関連リンク

11
10
1

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
11
10