[初心者向け] git rebaseを使ってみる

## 前置き
git rebaseコマンドについて学んだのまとめます。ものすごく単純な例で説明します。

## git rebaseは何ができる？
以下の２つのことができます。

1. コミットをつなげ直すこと
2. コミットをまとめる
   
まずは、「1.コミットをつなげ直すこと」について記載します。

## 実例(コミットをつなげ直す)
以下の例で説明します。

- 開発者がAさん、Bさんの2名いるとします。
- test.txtという空のファイルがあります。これがmasterブランチとします。
- 開発のゴールは、test.txtに"a","b","c"という文字を追加したファイルを作ることとします。
- Aさん、Bさんで作業を以下のように分担します。
  - Aさんには"a"を追加してもらう
  - Bさんには"b","c"を追加してもらう
- AさんはブランチAを切り、test.txtに"a"という文字を追加しました。  
- BさんはブランチBを切り、test.txtに"b"という文字を追加しました。
- Bさんは"c"を追加する前にAさんの作業内容を取込みたいとします。  

ここでBさんはAさんの作業内容取込に、mergeとrebaseの2つの手段がとれます。
以下の実例でmergeする場合と、rebaseする場合の両方やってみます。

### 準備
空のファイルtest.txtがあるmasterブランチの状態まで準備します。

```bash
$ mkdir test 
$ cd test 
$ git init
$ touch test.txt
$ git add test.txt
$ git commit -m 'initial commit'
```
### Aさんの作業
"a"という文字を追加します

```bash
$ git checkout -b branchA
$ echo a >> test.txt
$ git add test.txt
$ git commit -m 'add a'
```

### Bさんの作業
"b"という文字を追加します

```bash
$ git checkout master
$ git checkout -b branchB
$ echo b >> test.txt
$ git add test.txt
$ git commit -m 'add b'
```

### BさんがAさんの作業内容を取込(rebase Version)
```bash
# rebaseします。(branchBにいる状態で、branchAを取込)
$ git rebase branchA
# conflictするので解消します
$ cat test.txt
<<<<<<< HEAD
a
=======
b
>>>>>>> 4d86c92... add b
# 解消後
cat test.txt
a
b
# rebase続行
$ git add test.txt
$ git rebase --continue # エディタが開いてコミットコメントの編集画面になりますが、そのまま保存して続けます
# コミットログ確認
$ git log --oneline --graph
* f68bdb7 (HEAD -> branchB) add b
* d17bed1 (branchA) add a
* a1d7f67 (master) initial commit
```
git logを見ると、mergeと違ってコミット履歴が一直線であることがわかりやすいですね。

### BさんがAさんの作業内容を取込(merge Version)
mergeとの違いも気になるかと思いますので、mergeバージョンと比較してみます。

```bash
# マージ
$ git merge branchA # conflictするので解消します。
$ git add test.txt
$ git commit -m 'merged branchA'
# コミットログ確認
$ git log --oneline --graph
*   ff731a9 (HEAD -> branchB) merged branchA
|\
| * e2915b7 (branchA) add a
* | 63fff00 add b
|/
* b9ef1dd (master) initial commit
```
git logを見ると、コミット履歴が一直線ではありません。mergeなので当然ですね。

### まとめ
上記の「BさんがAさんの作業内容を取込」のrebaseバージョンとmergeバージョンのコミットログを
確認するとわかるように、rebaseはmergeと違って、過去のコミットを今のブランチにつなげ直す
ことができます。

## 実例(コミットをまとめる)
次はコミットをまとめてみます。作業者はさきほどと異なり、Aさん1人とします。

- test.txtに"a"を追加してコミット。(commitA)
- test.txtに"b"を追加してコミット。(commitB)
- test.txtに"c"を追加してコミット。(commitC)

ここで、commitBとcommitCをまとめてしまいたいとします。

### 準備
```bash
$ mkdir test 
$ cd test 
$ git init
$ touch test.txt
$ git add test.txt
$ git commit -m 'initial commit'

$ echo a >> test.txt
$ git add test.txt
$ git commit -m 'add a'

$ echo b >> test.txt
$ git add test.txt
$ git commit -m 'add b'

$ echo c >> test.txt
$ git add test.txt
$ git commit -m 'add c'

$ git log --oneline --graph
* 1f9a66d (HEAD -> master) add c
* bc48053 add b
* f8625d9 add a
* 239ee02 initial commit
```

コミットをまとめるときはrebaseのiオプションを指定します。
引数には、まとめたいコミットの1つ前のコミットIDを指定します。
ここでは、commitBとcommitCをまとめたいので、commitBの1つ前のcommitAのコミットIDを指定します。

```bash
$ git rebase -i f8625d9
```

上記コマンドを打つと、エディタが開きます。

```
pick bc48053 add b
pick 1f9a66d add c

# Rebase f8625d9..1f9a66d onto f8625d9 (2 commands)
（以下割愛)
```

まとめたいcommitBとcommitCが表示されています。一番上のコミットは統合元のコミットになるのでいじらず、
その下のコミットの「pick」を「squash」(統合)に変更します。

```
pick bc48053 add b
squash 1f9a66d add c

# Rebase f8625d9..1f9a66d onto f8625d9 (2 commands)
（以下割愛)
```

保存すると、続いてコミットメッセージの編集画面になります。

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

add b

# This is the commit message #2:

add c

# Please enter the commit message for your changes. Lines starting
(以下割愛)
```

「add b」のメッセージに「add c」のメッセージをまとめます。

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

add b and c

# This is the commit message #2:


# Please enter the commit message for your changes. Lines starting
(以下割愛)
```

コミットログを確認してみます。

```bash
$ git log --oneline --graph
* 4139507 (HEAD -> master) add b and c
* f8625d9 add a
* 239ee02 initial commit
```

commitBとcommitCがまとまりました。

### まとめ
コミットを細かくしすぎた場合は、`git rebase -i` でコミットをある程度まとめると
コミットログが見やすくなりますね。

今回は以上です。