merge、rebase実行時のコミットグラフのbefore&after

一ヶ月前にはじめてGitを使い始めた原始人として言わせてもらうと、正直、Gitは難しい。

なぜ難しいかというと、コマンドを実行して何が起きるのか、コマンドを実行したけど何が起きたのか、裏側が見えないから。ネットで調べたコマンドを実行するものの、いったい何が起きたのかよく分からず、しばしばパニックに陥っていた。

一ヶ月経った今振り返ると、Gitの入りとしてはまず「ブランチ」と呼ばれるポインタの操作に慣れることが先ではないかと感じた。あとは`git log --graph`の見方に慣れれば、独り立ちできる気がする。

そこで本記事では、merge/rebaseのコマンド実行前後でのコミットグラフを示してみた。ここに挙げたパターンで一通り練習すれば、Gitに対する恐怖感も薄れて、パズルを解くようなポインタ操作の楽しさに目覚めるかもしれない（僕はそれになった）。

#(1) No-FF マージ
`master`ブランチ（カレントブランチ）に、`parent`ブランチと`child`ブランチを合流させる。

```shell_session:git&nbsp;merge
git checkout master
git merge parent child
```

##before
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51871/5319b9e8-ef89-6726-dd6a-7a8acffd5915.png)

##after
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51871/da467526-a99b-2544-3baf-b13fb1fee219.png)

#(2) Fast Forwardマージ
```shell_session:git&nbsp;merge
git checkout master
git merge parent
```

## before
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51871/f9c324d7-221b-856d-acd6-263485453cae.png)

## after
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51871/89d52b63-6b54-b675-3b45-1777999e9f8d.png)

# (3) 基本的なリベース
```
git rebase master parent
```
または

```
git checkout parent
git rebase master
```

## before
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51871/3908948f-3c49-a179-8664-e2ed11bfb9a5.png)

## after
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51871/86e8daa7-a7c9-64a3-5c2c-1bad18e35acd.png)


#(4) 子連れブランチの子ブランチをスライスしてリベース

`master`ブランチから`child`ブランチを生やすつもりだったが、誤って`parent`ブランチから生やしてしまった。`master`ブランチに移植したいケースで使用する。

```shell_session:childブランチをparentブランチの派生元からスライスしてrebase
$ git rebase --onto master parent child
```

## before
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51871/9f28428e-8e42-f2ad-4680-5a55daa69aba.png)

##after
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51871/66f025f1-c662-9603-1f12-1587805a7910.png)


##(5) 子連れブランチの親ブランチをrebase
`--onto`をつけないとどうなるか？のifストーリーです。

```shell_session:
$ git rebase master parent
```

##before
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51871/9f28428e-8e42-f2ad-4680-5a55daa69aba.png)

##after
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51871/c62f2915-89c4-09ca-8252-681492db305e.png)


#(6) 子連れブランチの子ブランチをrebase
`--onto`をつけないとどうなるか？のifストーリーです。

```shell_session:
$ git rebase master child
```

##before
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51871/9f28428e-8e42-f2ad-4680-5a55daa69aba.png)

##after
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51871/b834adce-8a57-2083-f23c-74ce31f0bc7d.png)

#(7) ブランチを任意のコミットに移動
開発メンバーＡが`parent`を`master`にrebaseし、`origin/parent`にpushしたとする。
以前から`parent`ブランチで作業していた開発メンバーBが、`origin/parent`をfetchする。
すると、Ｂのローカルにある`parent`ブランチは、rebase前の古いブランチ（H）を指したままとなってしまう。

この時、単純に`parent`ブランチを`origin/parent`ブランチに移動したい。
もちろん、コミットは引き連れずに、ブランチのみを移動したい。
ブランチを再作成するという手もあるけど、以下のコマンドでも実現できる。

```shell-session
git rebase --onto origin/parent parent parent
```

##before

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51871/9d37f920-784a-f0a8-9b2e-e43ccb040add.png)

##after
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51871/7a310842-75cf-e8d1-9434-e1ae617f6bf7.png)


上では`parent`を`origin/parent`に移動させたが、移動先にSHA1-ハッシュ値を指定して、`parent`が任意のコミットを指すようにすることも可能である。

```shell-session
git rebase --onto SHA1-ハッシュ値 parent parent
```