初心者がしっかりと理解できるようにGitのブランチを説明する

[前回](https://qiita.com/gakisan8273/items/6ebaf9217d140ff1f031)はリモートリポジトリにローカルリポジトリの内容をpushするところまでを解説しました。
今回はいよいよ、**ブランチについて解説していきます！**

前回までの知識がある前提で話を進めますので、まだこれらを読んでない方は是非読んでください。

・[なぜ僕らはGitでバージョン管理をするのか](https://qiita.com/gakisan8273/items/d2d52a12ad553a82b94b)
・[Gitを触り始めてからGitHubにpushするまでの流れを誰よりも丁寧に説明する](https://qiita.com/gakisan8273/items/6ebaf9217d140ff1f031)

ここでは**コミットログ**の解説をするためにターミナルでログを出力します。**めっちゃ見辛いログ**です。
最後にログを見やすくするためのツールを紹介するので、それまでは耐えてください。

## ブランチとは？

ブランチという機能、Gitを触りたての頃は何が何だかよくわからないと思います。
端的に言うと「コミット（セーブポイント）の分岐を作る」機能です。その分岐を「ブランチ」と呼んでいます。
これにより、ブランチAでは機能Aの開発をしブランチBでは機能Bの開発をする、という住み分けが可能になります！

何が嬉しいのかは、これから詳しく説明する中で理解できると思います。

### Gitはコミットの履歴を管理している

コミットは上書きされるものでなく、追加されるものです。
その追加の履歴をGitで管理しています。
ブランチを理解するにはまずこの概念を理解する必要があります！！

順に確認していきましょう！

### コミットログを確認しよう

空のローカルリポジトリを新しく作ってください。（[参考](https://qiita.com/gakisan8273/items/6ebaf9217d140ff1f031#%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%AB%E3%83%AA%E3%83%9D%E3%82%B8%E3%83%88%E3%83%AA%E3%82%92%E4%BD%9C%E6%88%90%E3%81%97%E3%82%88%E3%81%86)）
そしてファイルを作成し、コミットしてみましょう。

```
$ mkdir (フォルダ名) // フォルダを新規作成する
$ cd (フォルダ名)    // カレントディレクトリを移動する
$ git init         // カレントディレクトリをGit管理する
$ touch test       // 'test'というファイルを新規作成する
$ git add test     // 'test'をステージする
$ git commit -m 'add test'  // 'add test'というコミットメッセージでコミットする
```

次に、コミットのログを確認してみましょう！そのコマンドは`git log`です。

```
$ git log

commit 33b53a587aa2d1f4a79d126de8d717e4bd97d563 (HEAD -> master)
Author: gakisan8273 <mint.daa.a2@gmail.com>
Date:   Tue Dec 8 01:21:59 2020 +0900

    add test
```

なんか出てきましたね。これがコミットログ（コミットの履歴）です。

読み方を少し解説します。

コミットには`ハッシュ`と言うものが割り当てられ、ハッシュとコミットは1対1で対応しています。ハッシュでコミットを識別します。先頭7桁で識別できるようです。今回特に重要ではないので、詳しくはググってください。
ログにはそのハッシュと、コミットしたユーザー名・コミットした時間・コミットメッセージが表示されています。

```:コミットログの説明
commit 33b53a587aa2d1f4a79d126de8d717e4bd97d563 (HEAD -> master) // ()内は後ほど解説します
// 33b53a587aa2d1f4a79d126de8d717e4bd97d563 がハッシュ（先頭の33b53a5だけで識別可能）

Author: gakisan8273  // コミットしたユーザー
Date:   Tue Dec 8 01:21:59 2020 +0900 // コミットした時間

    add test // コミットメッセージ
```

今は1回のみコミットをしたので、1コミットだけがログに表示されています。
それでは`test2`ファイルを新規作成しコミットして、ログを見てみましょう！

```
$ touch test2
$ git add test2
$ git commit -m 'add test2'
$ git log

commit d4de11a70e45c9d7c4481fd3b1aa1d10445d839b (HEAD -> master)
Author: gakisan8273 <mint.daa.a2@gmail.com>
Date:   Tue Dec 8 01:31:13 2020 +0900

    add test2

commit 33b53a587aa2d1f4a79d126de8d717e4bd97d563
Author: gakisan8273 <mint.daa.a2@gmail.com>
Date:   Tue Dec 8 01:21:59 2020 +0900

    add test
```

**ログが増えました！**やったね！
**最初のコミットは消えていません**。コミットは**上書きでなく追加される**ことが分かったかと思います。

コミット時間を見ればわかるように、新しいコミットが上に表示されています。

ここでハッシュの行だけを抜き出して表示してみます。

```:ログから抜粋
commit d4de11a70e45c9d7c4481fd3b1aa1d10445d839b (HEAD -> master) // (HEAD -> master)の位置が移動している！
commit 33b53a587aa2d1f4a79d126de8d717e4bd97d563  // d4de11aをコミットする前はここに(HEAD -> master)があった
```

`d4de11a`のコミットをしたら、`(HEAD -> master)`が`33b53a5`から`d4de11a`に移動してます！！

何が起こっているのでしょう？

### HEADは最新のコミットを指す

まず`HEAD`から説明しましょう。これは単純に最新のコミットを指しています。
最初のコミットの時点では、当然それが最新のコミットでした。なのでHEADがそれにあたります。
次に`test2`を追加するコミットをしたら、最新のコミットは変わりますよね。
なのでログの`HEAD`の位置も移動しています。

次にコミットするとき、`33b53a5`と`d4de11a`の間にコミットを追加することはできません。
なぜならば、`d4de11a`のコミットをした時点で、作業をする場所が最新の`d4de11a`に移動しているからです。
**コミットをすると履歴が追加され、常に最新のコミットを参照する**ことを覚えておいてください。

`(HEAD -> master)`の`HEAD`は何となく分かったかと思います。じゃあ`-> master`って何よ？に答えていきましょう！

### コミットログはブランチごとに存在する

ようやく出ました、ブランチという言葉。
ここまでの作業でブランチを作った記憶はありませんよね。しかし、Gitはデフォルトで`master`というブランチを1つだけ作っています。
これがいわゆるブランチの「本流」になります。

ローカルリポジトリにどんなブランチがあるかを`git branch`コマンドで確認しましょう。

```
$ git branch

* master // これがブランチ名 先頭の*は作業ブランチであることを示す
```

このように表示されましたね？現在は`master`ブランチ1つだけがあることが確認できました。
Gitの場合、必ず「作業ブランチ」というものを指定します。**その作業ブランチに対してコミットを実行しているのです。**
ブランチ名の先頭に`*`がついているのは、それが作業ブランチであることを示しています。
今はブランチが一つしかないので、自動的に`master`が作業ブランチになっています。

実は、`HEAD`が指しているブランチが作業ブランチになるのです。

`(HEAD -> master)`は`HEAD`が`master`を指しているので、

- 作業ブランチは`master`である

ということを表しています！！！！

## ブランチを作成してみよう（切ってみよう）

他のブランチがあるとどうなるか、確認してみましょう。
**ブランチを作成することを、ブランチを切るといいます。**何ででしょうね？

ブランチを切るコマンドは、`git branch (ブランチ名)`です。
`new_branch`という名前のブランチを切ってみましょう。

```
$ git branch new_branch
$ git branch

* master      // 作業ブランチはmasterのまま
  new_branch  // ブランチが作成された！！
```

この状態でログを見てみると…

```
$ git log

commit d4de11a70e45c9d7c4481fd3b1aa1d10445d839b (HEAD -> master, new_branch) // new_branchが追加された！！！！
Author: gakisan8273 <mint.daa.a2@gmail.com>
Date:   Tue Dec 8 01:31:13 2020 +0900

    add test2

commit 33b53a587aa2d1f4a79d126de8d717e4bd97d563
Author: gakisan8273 <mint.daa.a2@gmail.com>
Date:   Tue Dec 8 01:21:59 2020 +0900

    add test
```

`d4de11a`に`new_branch`が追加されました！！
`(HEAD -> master, new_branch)`の意味を解説しましょう！

作業ブランチは`master`（HEADが指しているから）ですね。そして同じコミットに`new_branch`もいるようです。
今は`master`と`new_branch`が同じコミットを指している同じ状態であると言えます。

ここでコミットを追加すると違いが見えてきます。

### ブランチを切った上でコミットしてみよう

今の作業ブランチは`master`のままです。
`add_master`ファイルを追加してコミットしてみましょう。

```
$ touch add_master
$ git add add_master
$ git commit -m 'add_master'
$ git log

commit debb8c883b12488593aed009d897300dc21f70d9 (HEAD -> master) // masterだけコミットが追加された
Author: gakisan8273 <mint.daa.a2@gmail.com>
Date:   Tue Dec 8 02:08:51 2020 +0900

    add_master

commit d4de11a70e45c9d7c4481fd3b1aa1d10445d839b (new_branch) // new_branchは変わってない
Author: gakisan8273 <mint.daa.a2@gmail.com>
Date:   Tue Dec 8 01:31:13 2020 +0900

    add test2

commit 33b53a587aa2d1f4a79d126de8d717e4bd97d563
Author: gakisan8273 <mint.daa.a2@gmail.com>
Date:   Tue Dec 8 01:21:59 2020 +0900

    add test
```

お分かりいただけただろうか。
作業ブランチである`master`はコミットが追加されたが、`new_branch`はそのままです。

もう少し分かりやすくするため、次は作業ブランチを`new_branch`に切り替えてコミットしてみましょう。

### 作業ブランチを切り替えてみよう

切り替えるコマンドは`git checkout (ブランチ名)`です。
そして`add_new_branch`ファイルを追加してコミットしてみましょう。

```
$ git checkout new_branch // 作業ブランチが切り替わる
$ git branch

  master
* new_branch // 作業ブランチが切り替わっている
```

```
$ touch add_new_branch
$ git add add_new_branch
$ git commit -m 'add_new_branch'
$ git log

commit 7df16ad90a5112d27bfa3d0e9487fb82591007e4 (HEAD -> new_branch) // d4de11aに追加されたコミット
Author: gakisan8273 <mint.daa.a2@gmail.com>
Date:   Tue Dec 8 02:14:26 2020 +0900

    add_new_branch

commit d4de11a70e45c9d7c4481fd3b1aa1d10445d839b // さっきまでnew_branchがいたコミット
Author: gakisan8273 <mint.daa.a2@gmail.com>
Date:   Tue Dec 8 01:31:13 2020 +0900

    add test2

commit 33b53a587aa2d1f4a79d126de8d717e4bd97d563
Author: gakisan8273 <mint.daa.a2@gmail.com>
Date:   Tue Dec 8 01:21:59 2020 +0900

    add test
```

`d4de11a`に`7df16ad`が追加されたことが分かります。
`master`が見当たりませんね？`git log`だけでは作業ブランチに関するログしか表示してくれません。

コマンドにオプションを足してみましょう。`git log --graph --all`を実行してください。
`--graph`はログをグラフで表示するオプション、`--all`は全てのブランチを表示するオプションです。

```
$ git log --graph --all // --graph グラフ表示する  --all 

* commit 7df16ad90a5112d27bfa3d0e9487fb82591007e4 (HEAD -> new_branch)
| Author: gakisan8273 <mint.daa.a2@gmail.com>
| Date:   Tue Dec 8 02:14:26 2020 +0900
|
|     add_new_branch
|
| * commit debb8c883b12488593aed009d897300dc21f70d9 (master)
|/  Author: gakisan8273 <mint.daa.a2@gmail.com>
|   Date:   Tue Dec 8 02:08:51 2020 +0900
|
|       add_master
|
* commit d4de11a70e45c9d7c4481fd3b1aa1d10445d839b  // このコミットからブランチが分かれている！！
| Author: gakisan8273 <mint.daa.a2@gmail.com>
| Date:   Tue Dec 8 01:31:13 2020 +0900
|
|     add test2
|
* commit 33b53a587aa2d1f4a79d126de8d717e4bd97d563
  Author: gakisan8273 <mint.daa.a2@gmail.com>
  Date:   Tue Dec 8 01:21:59 2020 +0900

      add test

```

左の縦線・斜め線がコミットの流れを表しています。雰囲気を感じ取ってください。

`d4de11a`を起点にして、`master`と`new_branch`が分かれていますね！！！
このように木の枝のように分かれるため`branch`と呼ばれています。

`debb8c8`は`master`だけが持つコミット
`7df16ad`は`new_branch`だけが持つコミット であることが伺えます。

つまり、**ブランチごとにコミットログが存在する**ということです！

また、`HEAD`が`master`から`new_branch`に移っていることが分かります。
**作業ブランチを切り替えることは、`HEAD`の位置を切り替えることと同じです。**

今は`add_master`ファイルは`master`ブランチだけが参照でき、`add_new_branch`ファイルは`new_branch`ブランチだけが参照できることになります。
確認してみましょう。


```:new_branchが作業ブランチ
$ git branch

  master
* new_branch

$ ls // カレントディレクトリに存在するファイルを表示するコマンド

add_new_branch test           test2 // add_masterはない
```

```:masterに作業ブランチを切り替える
$ git checkout master
$ git branch

* master
  new_branch

$ ls

add_master test       test2  // add_new_branchはない
```

それぞれの作業ブランチでコミットしたものしかないことが分かります。

### ブランチを統合しよう

実際にシステムを運用するときは本流である`master`ブランチを参照するでしょう。
`new_branch`で追加した`add_new_branch`ファイルを`master`に反映させる必要があります。

そのコマンドが、`git merge`！！！！
実行してみましょう！！

```
$ git branch

* master               // masterにブランチを統合したいので、作業ブランチをmasterにする
  new_branch

$ git merge new_branch // 作業ブランチに統合するブランチを指定する
```

`merge`すると、このようにコミットメッセージを入力するためにvimが起動します。
コミットメッセージを変更せずに、`:q`を入力してエディタを閉じましょう。

```:merge後にコミットメッセージを入力する
  1 Merge branch 'new_branch'  // ここがコミットメッセージ
  2 # Please enter a commit message to explain why this merge is necessary,
  3 # especially if it merges an updated upstream into a topic branch.
  4 #
  5 # Lines starting with '#' will be ignored, and an empty message aborts
  6 # the commit.
~
```

これで`master`に`new_branch`が統合されました。**このことを`マージ`と呼びます。**
`master`に何のファイルがあるか見てみましょう。

```
$ git branch

* master
  new_branch

$ ls

add_master     add_new_branch test           test2  // add_master, add_new_branch 両方ある！！
```

`master`で追加した`add_master`と`new_branch`で追加した`add_new_branch`の両方が`master`にあることが確認できます！
ブランチがマージ（統合）された、ということですね。

コミットログを見てみましょう。

```
$ git log --graph --all

*   commit 4010613273f3d1539a346f34562730e4510e9704 (HEAD -> master)
|\  Merge: debb8c8 7df16ad
| | Author: gakisan8273 <mint.daa.a2@gmail.com>
| | Date:   Tue Dec 8 12:14:33 2020 +0900
| |
| |     Merge branch 'new_branch'
| |
| * commit 7df16ad90a5112d27bfa3d0e9487fb82591007e4 (new_branch)
| | Author: gakisan8273 <mint.daa.a2@gmail.com>
| | Date:   Tue Dec 8 02:14:26 2020 +0900
| |
| |     add_new_branch
| |
* | commit debb8c883b12488593aed009d897300dc21f70d9
|/  Author: gakisan8273 <mint.daa.a2@gmail.com>
|   Date:   Tue Dec 8 02:08:51 2020 +0900
|
|       add_master
|
* commit d4de11a70e45c9d7c4481fd3b1aa1d10445d839b
| Author: gakisan8273 <mint.daa.a2@gmail.com>
| Date:   Tue Dec 8 01:31:13 2020 +0900
|
|     add test2
|
* commit 33b53a587aa2d1f4a79d126de8d717e4bd97d563
  Author: gakisan8273 <mint.daa.a2@gmail.com>
  Date:   Tue Dec 8 01:21:59 2020 +0900

      add test
```

`master`でマージをしたので、`マージコミット`というものが最新のコミット(`4010613`)として生まれます。
左の縦線が`7df16ad`（new_branchが参照してるコミット）から`4010613`（masterの最新コミット）に伸び、統合されています。


・・・だから何？なんでブランチが必要なの？`master`だけで作業すればマージする必要もなくていいじゃん！

と、思いますよね。ブランチがあると何が嬉しいのかを説明していきましょう！

## ブランチの嬉しさ

ブランチにより別機能開発を同時並行しやすくなります！！！！

ブランチが`master`一つしかない場合を想像してください。

---

> あなたは`master`ブランチで機能Aの開発をしています。いい感じに実装を進めていると上司から「急ぎで機能Bを実装してくれ！」と依頼が来ました。
機能Aの実装を中断するため、キリのいいところでコミットしました。機能Aは少しバグがあるものの、動いています。
そして機能Bの実装を開始します。
> 
機能Bの実装を無事終えてユーザーが使用を始めています。機能Aの実装に戻ることにしました。
ところが！**機能Aが全く動作しなくなっていました！！！原因は機能Bの実装であることは明らか**です。
修正するには機能Bで実装したところに手を入れるしかありません。
しかしそれをすると、今ユーザーが使っている機能Bが動かなくなってしまうかもしれません…困った…どうしよう…

---

機能ごとにブランチを分けた場合を考えてみましょう。

---

> あなたは機能Aの開発をするため、`master`ブランチから`function_a`ブランチを切り、そこで実装を進めていました。
上司から「急ぎで機能Bを実装してくれ！」と依頼が来ました。
機能Aの実装を中断するため、`function_a`ブランチでキリのいいところでコミットしました。機能Aは少しバグがあるものの、動いています。
そして機能Bの実装を開始するため、`master`ブランチから`function_b`ブランチを切りました。
> 
機能Bの実装を無事終えて、`function_b`を`master`ブランチにマージしました。ユーザーが使用を始めています。
機能Aの実装に戻るため、`function_a`ブランチに切り替えます。
**`function_a`と`function_b`は互いに独立している**ので、機能Aは中断した時と変わりありません。
そのまま`function_a`ブランチで機能Aの実装を終え、`master`にマージして無事リリースできました。

---

どうでしょう。嬉しさが少しは分かったのではないでしょうか？

とはいえ…ブランチは実際に開発で使わなければその恩恵が理解しにくいと思います！！！！
また一人で開発している分にはブランチを切らなくてもあまり不自由ありません！！！！（個人差があります）

しかしぜひ！！ブランチを使ってみて何ができるかを体感して欲しい！！！お願いします！！

## コミットログって見にくくない？？？

さて皆さん、ここまでコミットログをターミナルで表示して来たかと思います。
クッソ見辛いですよね？？？だから解説もしにくいし…

もっと見やすくする方法があるので、それを紹介します。

### VSCodeの拡張機能「Git Graph」を使おう！！！

まずVSCodeというエディタをインストールしてください。方法はググってください。
そしたらVSCodeを起動し、VSCode内の拡張機能で`git graph`と検索します。出ます。
インストールしましょう。

![スクリーンショット 2020-12-08 14.26.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/455830/1f1d9cd7-f44b-308c-b057-86706a51d15e.png)

ソース管理タブのGitGraphっぽい右側のアイコンをクリックすると、ウィンドウにコミットログが表示されます。

![スクリーンショット 2020-12-08 14.29.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/455830/20bcb6d1-e08e-9819-b5e4-46292ccd44ec.png)


この見やすさの違い、Git Graphを使わない理由がない！
Git Graphでもハッシュやコミットメッセージが見れるのは当然で、それに加えてコミット内容などまで見ることができます。
ターミナルの上位互換と考えて差し支えないです。

```
$ git log --graph --all

*   commit 4010613273f3d1539a346f34562730e4510e9704 (HEAD -> master)
|\  Merge: debb8c8 7df16ad
| | Author: gakisan8273 <mint.daa.a2@gmail.com>
| | Date:   Tue Dec 8 12:14:33 2020 +0900
| |
| |     Merge branch 'new_branch'
| |
| * commit 7df16ad90a5112d27bfa3d0e9487fb82591007e4 (new_branch)
| | Author: gakisan8273 <mint.daa.a2@gmail.com>
| | Date:   Tue Dec 8 02:14:26 2020 +0900
| |
| |     add_new_branch
| |
* | commit debb8c883b12488593aed009d897300dc21f70d9
|/  Author: gakisan8273 <mint.daa.a2@gmail.com>
|   Date:   Tue Dec 8 02:08:51 2020 +0900
|
|       add_master
|
* commit d4de11a70e45c9d7c4481fd3b1aa1d10445d839b
| Author: gakisan8273 <mint.daa.a2@gmail.com>
| Date:   Tue Dec 8 01:31:13 2020 +0900
|
|     add test2
|
* commit 33b53a587aa2d1f4a79d126de8d717e4bd97d563
  Author: gakisan8273 <mint.daa.a2@gmail.com>
  Date:   Tue Dec 8 01:21:59 2020 +0900

      add test
```

![スクリーンショット 2020-12-08 14.29.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/455830/16a942ee-db62-414c-e180-631eb8c27a4a.png)

### 便利ツールの落とし穴
Git Graphは様々な機能を持っています。
マウスポチーでコミットの取り消しができたり、コミットの移動ができたりもします。
しかし！これを読んでいる皆さんは**まだその機能を使わないでください！！**

結局は**どんな操作でも裏でGit Graphがコマンドを叩いている**ので、**「この操作でどんなコマンドが実行されるのか」を理解していないと思わぬ事故に繋がります。**

まずターミナルでどう操作すればいいかを理解してから、便利なツールを使いましょう！
本記事でクッソ見辛い`git log`をあえて使ったものその理由からです。

## さいごに

ブランチの説明、プログラミング初学者に分かりやすく説明するのはめっちゃ難しいです。
僕も学びはじめの頃、色々な解説記事を見ましたが何が何だか分かりませんでした…
しかし、実際にブランチを切って触っていくうちに理解できました。

例によってこの記事は初学者向けに書いているので、正確でない部分もあります。
しかし最初はこの理解で十分ですので、気になったらその都度精査してみてください。

この記事がしっかりと解説してくれているので、より細かく知りたい方は是非参照してみてください。
[図解！ Gitのブランチ・ツリーをちゃんと読む](https://qiita.com/jesus_isao/items/2a0495c973a4c911c2cc)

特にこのブランチという機能は実際に触らなければ、そして複数人開発をしなければ、必要性が分かりにくいものだと思います。
初学者にとっては非常にとっつきにくいものでしょう。

とりあえず何か開発するときは、機能ごとにブランチを切る習慣をつけておいて欲しい！
そうしてればそのうちコンフリクトが起こって解消方法に悩んだり、rebaseしたりcherry-pickしたくなる時が来るでしょう。
それらを一つ一つ乗り越えて徐々に理解が深まっていくものです。

さあ自分のリポジトリにブランチを作ってみよう！！！


よかったら[Twitter](http://twitter.com/gakisan8273)もフォローしてね。怪しいアカウントじゃないよ。