【GitHubまとめ第2回】ブランチ・マージ・リベース・コンフリクト

必須スキルとなっているgit・gitHubの基礎についてまとめました。今回は「ブランチ」・「マージ」・「リベース」・「コンフリクト」を記述しています。初学者向けの内容です。コマンドはコピペしやすいように、$をあえてつけていません。

全3回に渡って、下記の計画で進めています。
【計画】
第1回目 git基礎コマンド (https://qiita.com/tatsuya_1995/items/b0747759630b6c230684)
<font color="red">第2回目 ブランチ・マージ・リベース・コンフリクト （今回）</font>
第3回目 プルリクエスト (https://qiita.com/tatsuya_1995/items/6d48b7ba8487fe38bbf8)

※沢山出回っている記事ですので、あくまでも自分用メモです。

##ブランチ

分岐することで、並行して複数機能を開発するときに使う仕組み。
コミットを指し示したポインタのこと。

###ブランチを新規追加

```
git branch <ブランチ名>
```



###ブランチの一覧を表示する

```
git branch
git branch -a //全てのブランチを表示する
```

`-a`をオプションでつけると追跡ブランチも表示される。
![git branch.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/969534/2e3e0126-7232-0871-f15a-aaa80221573f.png)

##ブランチを切り替える

HEADが指し示すブランチ名を切り替える。

```
git checkout <既存ブランチ名>
git checkout -b <新規ブランチ名>  //ブランチを新規作成して切り替える
```
>HEAD:
今作業しているブランチを指し示したポインタのこと。

##ブランチ名を変更

今自分が作業しているブランチの名前を変更することができる。

```
git branch -m <ブランチ名>
```

##ブランチを削除

注意：現在自分がいるブランチ（カレント）は削除できないため、`git checkout <他のブランチ名>`で移動してから削除。

該当ブランチの変更分がmasterブランチへmergeされていないときは削除されない。

```
git branch -d <ブランチ名>
```

該当ブランチの変更分がmasterにmergeされていなくても強制削除する。

```
git branch -D <ブランチ名>
```
##ブランチの命名規則

Gitにはブランチモデルという運用方法のガイドラインがあり、名前の付け方、いつ作成し、いつマージするか等に標準指針がある。有名なブランチモデルのうちの`git-flow`では下記のようになる。

###中央リポジトリ(GitHubなど)
#### master　
現在の製品のメインブランチ。originに常に存在。git-flowではmasterブランチに直接コミットすることはなく、マージを行うだけのブランチになる。
#### develop　
次回リリースの開発用。originに常に存在。リリース時にmasterへマージする。

###開発者リポジトリ
#### feature　
新機能開発中に使う開発者用のブランチ。Issueの作業をするときに、developから分岐して、Issueの作業が完了したらdevelopへマージしたら削除する。例：feature/123 (123はIssue番号)
#### release 
次回リリースが近くなったら、developから分岐して、developとmasterへマージする。リリース担当者用のブランチ、リリースしたら削除する。例：release/1.2
#### hotfix 
現在の製品バージョンのバグフィックス用。masterから分岐して、masterとdevelopへマージする。マージしたら削除する。例：hotfix/123 (123はIssue番号)


git-flowの詳細：
https://tracpath.com/bootcamp/learning_git_git_flow.html
https://www.atmarkit.co.jp/ait/articles/1311/18/news017.html

##ブランチの種類

①ローカルブランチ
②追跡ブランチ(リモートトラッキングブランチ)
③リモートブランチ

###①ローカルブランチ

ローカルリポジトリにあるブランチのこと。`git branch`コマンドをオプションなしで実行した時に表示されるもので、一番初めは「master」という名前のローカルブランチしか存在しない。`git checkout <リポジトリ名>`を実行すると<リポジトリ名>のローカルリポジトリを作成し、移動することができる。

###②追跡ブランチ（リモートトラッキングブランチ）

`git banch -a`というコマンドを打った時に「remotes/origin/master」というブランチ名が表示される。これが追跡ブランチの名前であり、リモートブランチではない。
<font color="red";>追跡ブランチはローカルリポジトリにあるブランチ。</font>
追跡ブランチはリモートリポジトリのリモートブランチを追跡している。
また。図では追跡ブランチ「origin/master」をローカルリポジトリの「master」が追跡している。「origin/master」ブランチはローカルの「master」ブランチの<font color="red">上流ブランチ</font>という。

###③リモートブランチ

リモートリポジトリにあるブランチ。このブランチだけは自分のローカルPCにはない。


![branch.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/969534/0899afff-d952-38db-3e47-edf309058673.png)


##ブランチの統合

①マージ(merge)
②リベース(rebase)
の大分類があり、どちらを使うかで統合後のブランチの履歴が異なる。

##①マージ(merge)する

```
git merge <ブランチ名>
```

###fast-forward(早送り)マージ
下図のようにmasterブランチからfeatureブランチが分岐していた場合。featureブランチを修正後、masterブランチにマージする時、masterブランチの状態が以前から変更されていなければ、簡単にマージを行うことができる。これをfast-forward(早送り)マージと呼ぶ。

![fastmerge1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/969534/6916f9bb-6cbc-e0c1-444d-9f88a8cf12d2.png)

featureブランチの履歴はmasterブランチの履歴を全て含んでいるため、masterブランチは単純に移動するだけで、featureブランチの内容を取り込むことができる。

![fastmerge2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/969534/92a1fcb3-cbdf-b9a2-bc5d-affc5ad5a3d1.png)


###Non-fast-forward(早送りでない)マージ

masterブランチの履歴がfeatureブランチを分岐させた時より、進んでいた場合。この場合はmasterブランチの変更内容とfeatureブランチの変更内容を一つに統合する必要がある。そのため、両方の変更を取り込んだマージコミットが作成される。masterブランチの先頭はそのコミットに移動する。

![non-fast.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/969534/6129f4a6-0a18-2c05-4a6e-dd03eac262e5.png)

マージの実行時に、fast-forwardとNon-fast-forwardをオプションで指示することもできる。
fast-forwardでマージすると履歴が残らないため、基本的には<font color="red">Non-fastforwardでマージする方が望ましい</font>。らしいです。

####fast-forwardでマージ

```
git merge --no-ff <マージするブランチ>
```

####Non-fast-forwardでマージ

```
git merge ーーff <マージするブランチ>
```

参考：マージの挙動
https://backlog.com/ja/git-tutorial/stepup/04/
https://qiita.com/tkek321/items/8134467a7ae606199554


##②リベース(rebase)する

###別々のブランチで開発していたコミットを繋げ直す

```
git rebase <つなぐ元にするブランチ名>
```

作業が完了したブランチを分岐元のブランチに統合する。更新履歴が一直線になり、履歴を追う時に見やすい。
![スクリーンショット 2021-01-16 12.54.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/969534/b596abe2-e4aa-4fa4-b7cc-a503be1171e1.png)


###複数のコミットを１コミットにまとめる

注意：リモートに一度pushしたものをまとめると、他の作業者が迷子になる可能性があるため、このコマンドを実行するのはローカルのみが望ましい。

```
git rebase -i <ひとまとめにするする地点の一つ前のコミットID>
```
![merge.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/969534/da1af62d-a777-881b-4b88-199ff1d87cf5.png)

コミットIDは`git log`コマンドで確認可能。
参考：https://qiita.com/tatsuya_1995/items/b0747759630b6c230684#%E5%A4%89%E6%9B%B4%E3%81%AE%E5%B1%A5%E6%AD%B4%E3%82%92%E7%A2%BA%E8%AA%8D

##コンフリクトとは

複数人で同じファイルの
同じ箇所を別々に変更して統合した際に、どれを優先すべきか判断できなくなること。

↓`git merge`しようとしたらコンフリクトが発生して、マージできなかった例
![conflict.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/969534/fc869375-84fd-bd29-d367-6383d2146bdd.png)

`git status`で確認したとき`both modified`と表示される。両方が変更されたの意味。→コンフリクトした。
![gitstatus 2021-01-14 10.59.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/969534/aef808a1-e4eb-719e-a0dc-e6d2ee576cbe.png)

##コンフリクト解消方法

①コンフリクトするとテキストエディタにこのような表示がされるため、必要な箇所だけ残して、不要な箇所は削除する。
![conflict2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/969534/734918de-cfc0-547b-bad7-96f74fecb806.png)

②テキストエディタで編集しただけではstatusに変化はない。ここからステージに追加、コミットする。
![gitstatus 2021-01-14 10.59.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/969534/aef808a1-e4eb-719e-a0dc-e6d2ee576cbe.png)

#最後に
今回はgitのブランチ・マージ・リベース・コンフリクトについてまとめました。次回はプルリクエスト等についてまとめます。
（もしこの記事に誤りがありましたらご教授いただけると幸いです。）

(追記：2021/1/17)大変分かりやすい説明資料を見つけたので貼っておきます。
https://www.slideshare.net/kotas/git-15276118