git rebaseを勉強してみた


## はじめに
前回mergeをやってみました。今回はrebaseです。
前回と重複しますが、`git init`から始めます。

## テストリポジトリの作成
一気にいきます。

* `master`ブランチの作成
*  `feature/world`ブランチに分岐
* `world`メソッド追加しコミット
* `master`ブランチに戻り
* `hello`メソッドを追加しコミット

```java:Hello.java
class Hello {
    public static void main(String[] args) {
        System.out.println("hello");
    }
}
```
```.gitignore
*.class
```
```bash
$ git init ./
Initialized empty Git repository in /Users/kenta_suzuki/project/rebase/.git/

$ git add ./

$ git status
On branch master

Initial commit

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

        new file:   .gitignore
        new file:   Hello.java

$ git commit -m '初めてのコミット'
[master (root-commit) 9a69391] 初めてのコミット
 2 files changed, 8 insertions(+)
 create mode 100644 .gitignore
 create mode 100644 Hello.java

$ git branch
* master

$ git log --decorate=full
commit 9a693911726510a15e2c5276dc438eaacccb3106 (HEAD, refs/heads/master)
Author: kenta <kenta_suzuki@dwango.co.jp>
Date:   Wed Dec 11 22:22:47 2013 +0900

    初めてのコミット

$ git checkout -b feature/world master
Switched to a new branch 'feature/world'

$ git log --decorate=full
commit 9a693911726510a15e2c5276dc438eaacccb3106 (HEAD, refs/heads/feature/world)
Author: kenta <kenta_suzuki@dwango.co.jp>
Date:   Wed Dec 11 22:22:47 2013 +0900

    初めてのコミット

$ vim Hello.java
(ここで以下のdiffになるように修正)

$ git diff
diff --git a/Hello.java b/Hello.java
index 8bf82a8..eae3d39 100644
--- a/Hello.java
+++ b/Hello.java
@@ -2,5 +2,9 @@ class Hello {
     public static void main(String[] args) {
         System.out.println("hello");
     }
+
+    public static void world() {
+        System.out.println("world");
+    }
 }

$ git commit -a -m 'worldメソッドを追加'
[feature/world 3dfd7cf] worldメソッドを追加
 1 file changed, 4 insertions(+)

$ git log --decorate=full
commit 3dfd7cf5be7fe5f20880d31db3b926d092d3160e (HEAD, refs/heads/feature/world)
Author: kenta <kenta_suzuki@dwango.co.jp>
Date:   Wed Dec 11 23:19:09 2013 +0900

    worldメソッドを追加

commit 9a693911726510a15e2c5276dc438eaacccb3106
Author: kenta <kenta_suzuki@dwango.co.jp>
Date:   Wed Dec 11 22:22:47 2013 +0900

    初めてのコミット

$ git checkout master
Switched to branch 'master'

$ git log --decorate=full
commit 9a693911726510a15e2c5276dc438eaacccb3106 (HEAD, refs/heads/master)
Author: kenta <kenta_suzuki@dwango.co.jp>
Date:   Wed Dec 11 22:22:47 2013 +0900

    初めてのコミット

$ vim Hello.java
(ここで以下のdiffになるように修正)

$ git diff
diff --git a/Hello.java b/Hello.java
index 8bf82a8..1c9343b 100644
--- a/Hello.java
+++ b/Hello.java
@@ -2,5 +2,9 @@ class Hello {
     public static void main(String[] args) {
         System.out.println("hello");
     }
+
+    public static void hello() {
+        System.out.println("hello");
+    }
 }

$ git commit -a -m 'helloメソッドを追加'
[master afd434d] helloメソッドを追加
 1 file changed, 4 insertions(+)

$ git log --decorate=full
commit afd434d6e9ba7b1a86e8d870ab3e5ba9edb8fbf9 (HEAD, refs/heads/master)
Author: kenta <kenta_suzuki@dwango.co.jp>
Date:   Wed Dec 11 22:39:22 2013 +0900

    helloメソッドを追加

commit 9a693911726510a15e2c5276dc438eaacccb3106
Author: kenta <kenta_suzuki@dwango.co.jp>
Date:   Wed Dec 11 22:22:47 2013 +0900

    初めてのコミット
```

はー、長かった。早速rebase行ってみましょう。

```bash
$ git rebase feature/world
First, rewinding head to replay your work on top of it...
Applying: helloメソッドを追加
Using index info to reconstruct a base tree...
M       Hello.java
Falling back to patching base and 3-way merge...
Auto-merging Hello.java
CONFLICT (content): Merge conflict in Hello.java
Failed to merge in the changes.
Patch failed at 0001 helloメソッドを追加
The copy of the patch that failed is found in:
   /Users/kenta_suzuki/project/rebase/.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".

$ git status
rebase in progress; onto 3dfd7cf
You are currently rebasing branch 'master' on '3dfd7cf'.
  (fix conflicts and then run "git rebase --continue")
  (use "git rebase --skip" to skip this patch)
  (use "git rebase --abort" to check out the original branch)

Unmerged paths:
  (use "git reset HEAD <file>..." to unstage)
  (use "git add <file>..." to mark resolution)

        both modified:      Hello.java

no changes added to commit (use "git add" and/or "git commit -a")

$ vim Hello.java
(コリジョンしているので修正する)

$ git diff
diff --cc Hello.java
index eae3d39,1c9343b..0000000
--- a/Hello.java
+++ b/Hello.java
@@@ -3,8 -3,8 +3,12 @@@ class Hello 
          System.out.println("hello");
      }
  
+     public static void hello() {
+         System.out.println("hello");
+     }
++
 +    public static void world() {
 +        System.out.println("world");
 +    }
  }

$ git branch -a
* (no branch, rebasing master)
  feature/world
  master

$ git status
rebase in progress; onto 3dfd7cf
You are currently rebasing branch 'master' on '3dfd7cf'.
  (fix conflicts and then run "git rebase --continue")
  (use "git rebase --skip" to skip this patch)
  (use "git rebase --abort" to check out the original branch)

Unmerged paths:
  (use "git reset HEAD <file>..." to unstage)
  (use "git add <file>..." to mark resolution)

        both modified:      Hello.java

no changes added to commit (use "git add" and/or "git commit -a")

$ git add ./

$ git rebase --continue
Applying: helloメソッドを追加

$ git log --decorate=full
commit 4cb8b98dbd79de7e9be6c067f90dd223bb4cab7e (HEAD, refs/heads/master)
Author: kenta <kenta_suzuki@dwango.co.jp>
Date:   Wed Dec 11 22:39:22 2013 +0900

    helloメソッドを追加

commit 3dfd7cf5be7fe5f20880d31db3b926d092d3160e (refs/heads/feature/world)
Author: kenta <kenta_suzuki@dwango.co.jp>
Date:   Wed Dec 11 23:19:09 2013 +0900

    worldメソッドを追加

commit 9a693911726510a15e2c5276dc438eaacccb3106
Author: kenta <kenta_suzuki@dwango.co.jp>
Date:   Wed Dec 11 22:22:47 2013 +0900

    初めてのコミット
```

```java:Hello.java(コリジョンを起こしたファイル)
class Hello {
    public static void main(String[] args) {
        System.out.println("hello");
    }

<<<<<<< HEAD
    public static void world() {
        System.out.println("world");
=======
    public static void hello() {
        System.out.println("hello");
>>>>>>> helloメソッドを追加
    }
}
```

```mergeの場合
commit 2889d24c5422fd145946ebd771aac193df7a3bb5 (HEAD, refs/heads/master)
Merge: ea93e48 08ffb74
Author: kenta <kenta_suzuki@dwango.co.jp>
Date:   Wed Dec 11 09:57:19 2013 +0900

    worldメソッドをマージ

commit ea93e4833c20246ea80d72761feab523c45ee8be
Author: kenta <kenta_suzuki@dwango.co.jp>
Date:   Wed Dec 11 09:29:25 2013 +0900

    helloメソッドを追加

commit 08ffb7444eafe390ea5ce8582b6c2ec0f2dd8a3f (refs/heads/feature/world)
Author: kenta <kenta_suzuki@dwango.co.jp>
Date:   Wed Dec 11 09:20:56 2013 +0900

    worldメソッドを追加

commit 67c809018dd292c5c84d957d0ae6c5eb03622dcd
Author: kenta <kenta_suzuki@dwango.co.jp>
Date:   Tue Dec 10 22:29:07 2013 +0900

    初めてのコミット
```


```rebaseの場合
commit 4cb8b98dbd79de7e9be6c067f90dd223bb4cab7e (HEAD, refs/heads/master)
Author: kenta <kenta_suzuki@dwango.co.jp>
Date:   Wed Dec 11 22:39:22 2013 +0900

    helloメソッドを追加

commit 3dfd7cf5be7fe5f20880d31db3b926d092d3160e (refs/heads/feature/world)
Author: kenta <kenta_suzuki@dwango.co.jp>
Date:   Wed Dec 11 23:19:09 2013 +0900

    worldメソッドを追加

commit 9a693911726510a15e2c5276dc438eaacccb3106
Author: kenta <kenta_suzuki@dwango.co.jp>
Date:   Wed Dec 11 22:22:47 2013 +0900

    初めてのコミット
```

* merge
 * コミットが時系列に並んでいる
 * 分岐した時点からの差分がコミットログとして残っている
* rebase
 * 分岐後のmasterのコミットを取り込んだ後の差分が残る

どちらにも利点があるし欠点があるのでしょう。
ローカルで一時的な修正をコミットしたとき、修正自体が間違ってて後で直した場合、意味のあるコミットにまとめるため`rebase`する。
masterにマージする際は`merge`を使って分岐時点からの差分を詳細に残す。

というような使い方でいいような気がしてきた。
もっと、深く踏み込んで、「○○の時は`merge`で△△の時は`rebase`だよねー」とかっていえるように、勉強続けます。

次回ももうちょい mergeとrebaseについて考察していきます。