前回はリモートリポジトリにローカルリポジトリの内容をpushするところまでを解説しました。
今回はいよいよ、ブランチについて解説していきます!
前回までの知識がある前提で話を進めますので、まだこれらを読んでない方は是非読んでください。
・なぜ僕らはGitでバージョン管理をするのか
・Gitを触り始めてからGitHubにpushするまでの流れを誰よりも丁寧に説明する
ここではコミットログの解説をするためにターミナルでログを出力します。めっちゃ見辛いログです。
最後にログを見やすくするためのツールを紹介するので、それまでは耐えてください。
ブランチとは?
ブランチという機能、Gitを触りたての頃は何が何だかよくわからないと思います。
端的に言うと「コミット(セーブポイント)の分岐を作る」機能です。その分岐を「ブランチ」と呼んでいます。
これにより、ブランチAでは機能Aの開発をしブランチBでは機能Bの開発をする、という住み分けが可能になります!
何が嬉しいのかは、これから詳しく説明する中で理解できると思います。
Gitはコミットの履歴を管理している
コミットは上書きされるものでなく、追加されるものです。
その追加の履歴をGitで管理しています。
ブランチを理解するにはまずこの概念を理解する必要があります!!
順に確認していきましょう!
コミットログを確認しよう
空のローカルリポジトリを新しく作ってください。(参考)
そしてファイルを作成し、コミットしてみましょう。
$ 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
ブランチだけが参照できることになります。
確認してみましょう。
$ git branch
master
* new_branch
$ ls // カレントディレクトリに存在するファイルを表示するコマンド
add_new_branch test test2 // add_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
を入力してエディタを閉じましょう。
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
と検索します。出ます。
インストールしましょう。
ソース管理タブのGitGraphっぽい右側のアイコンをクリックすると、ウィンドウにコミットログが表示されます。
この見やすさの違い、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
便利ツールの落とし穴
Git Graphは様々な機能を持っています。
マウスポチーでコミットの取り消しができたり、コミットの移動ができたりもします。
しかし!これを読んでいる皆さんはまだその機能を使わないでください!!
結局はどんな操作でも裏でGit Graphがコマンドを叩いているので、「この操作でどんなコマンドが実行されるのか」を理解していないと思わぬ事故に繋がります。
まずターミナルでどう操作すればいいかを理解してから、便利なツールを使いましょう!
本記事でクッソ見辛いgit log
をあえて使ったものその理由からです。
さいごに
ブランチの説明、プログラミング初学者に分かりやすく説明するのはめっちゃ難しいです。
僕も学びはじめの頃、色々な解説記事を見ましたが何が何だか分かりませんでした…
しかし、実際にブランチを切って触っていくうちに理解できました。
例によってこの記事は初学者向けに書いているので、正確でない部分もあります。
しかし最初はこの理解で十分ですので、気になったらその都度精査してみてください。
この記事がしっかりと解説してくれているので、より細かく知りたい方は是非参照してみてください。
図解! Gitのブランチ・ツリーをちゃんと読む
特にこのブランチという機能は実際に触らなければ、そして複数人開発をしなければ、必要性が分かりにくいものだと思います。
初学者にとっては非常にとっつきにくいものでしょう。
とりあえず何か開発するときは、機能ごとにブランチを切る習慣をつけておいて欲しい!
そうしてればそのうちコンフリクトが起こって解消方法に悩んだり、rebaseしたりcherry-pickしたくなる時が来るでしょう。
それらを一つ一つ乗り越えて徐々に理解が深まっていくものです。
さあ自分のリポジトリにブランチを作ってみよう!!!
よかったらTwitterもフォローしてね。怪しいアカウントじゃないよ。