ブランチとマージ
ブランチは履歴を枝分かれさせる仕組みで、本流に影響を与えずに新機能や修正を試せます。git branch で一覧や作成を行い、git switch(または git checkout)で作業対象を切り替えます。枝で仕上げた変更は git merge で元のブランチに取り込みます。いまどの枝にいるかは HEAD という印が指し示しており、切り替えると HEAD の指す先が動きます。
ブランチ(git-branch)は、履歴を枝分かれさせる仕組みです。本流(多くの場合 main という名前の枝)を壊さないまま、別の枝で新機能の開発や実験を進め、うまくいったら本流に合流させる——この合流がマージ(git-merge)です。なぜ枝を分けるのかというと、開発途中の不安定な状態を本流に混ぜずに済むからです。たとえば新機能を作っている最中に、本流に対して急ぎの不具合修正が必要になっても、枝が分かれていればお互いに干渉しません。Git のブランチは内部的には「あるコミットを指す軽い目印」にすぎないため、作るのも切り替えるのも一瞬で、気軽に何本でも分けられるのが大きな特徴です。
ブランチを作って移る
現在のブランチの一覧は git branch で確認します。実行すると枝の名前が並び、いま自分がいる枝には先頭に * が付きます。新しい枝を作ってそこへ移動するには git switch -c <名前> を使います。-c は create(作成)の意味で、たとえば git switch -c feature と打つと feature という枝が作られ、同時にそこへ移動します。移動後にもう一度 git branch を打つと、* が feature に移っているのが分かります。元の枝へ戻るときは -c を付けずに git switch main とします。なお、以前は同じことを git checkout -b feature と書いていました。今でも checkout は使えますが、「枝の切り替え」と「ファイルの復元」という別々の役割を1つに抱えていて紛らわしかったため、目的別に分かれた git switch が現在の推奨です。古い資料では checkout が出てくるので、読み替えられるようにしておくと安心です。
いま自分がどの枝にいるかは、HEAD(git-head)という印が指し示しています。HEAD は「現在の作業位置」を表す矢印で、ふだんは今いるブランチの先頭のコミットを指しています。git switch で枝を切り替えると、この HEAD の指す先が移動し、それに合わせて作業ツリーの中身も切り替えた枝の状態に入れ替わります。つまり枝を切り替えるとは、HEAD を別の枝へ向け直すことだと考えると、頭の中で整理しやすくなります。
マージで枝を合流させる
枝の上で git add と git commit を重ねて作業を仕上げたら、本流に戻ってから取り込みます。具体的な流れはこうです。feature 上で echo "feature work" > feature.txt のように作業し、git add feature.txt、git commit -m "Add feature file" でコミットします。そのうえで git switch main で本流へ移り、git merge feature と打って feature の成果を取り込みます。このとき、本流側に枝を分けたあとの新しいコミットが無ければ、Git は本流の目印を枝の先頭までスッと進めるだけで合流が完了します。これを fast-forward(早送り)と呼び、「Fast-forward」と表示され、新しいコミットは作られません。一方、本流と枝の両方がそれぞれ別々にコミットを進めていた場合は早送りできず、Git は両者を突き合わせて1つの「マージコミット」を新たに作ります。これは共通の祖先・本流の先端・枝の先端という3点を見比べて統合するため、3-way merge(3方向マージ)と呼ばれます。
コンフリクトの解決
マージで初学者が身構えるのがコンフリクト(衝突)です。これは、2つの枝で同じファイルの同じ行を別々の内容に書き換えていたときに起こります。Git はどちらを採用すべきか自分では判断できないので、勝手に決めずに印を付けて人間に委ねます。マージを実行すると「CONFLICT」と表示され、「fix conflicts and then commit the result(衝突を直してからコミットせよ)」という案内が出ます。衝突したファイルを開くと、Git が次のような印を書き込んでいます。<<<<<<< HEAD から ======= までが今いる枝側の内容、======= から >>>>>>> までが取り込もうとした枝側の内容です。
解決の手順はあわてなければ簡単です。エディタでそのファイルを開き、<<<<<<<・=======・>>>>>>> の3種類の印と、不要なほうの内容を削って、残したい最終形だけにします。あとは git add でそのファイルを載せ、git commit で確定すればマージ完了です。最後に git status を打ち、「nothing to commit, working tree clean」と出れば解決できています。ここで最も多い失敗が、======= などの印を消し忘れて、そのままコミットしてしまうことです。3種類の印は必ず全部消すこと、そして今どのファイルが衝突中かは git status が「Unmerged paths」として教えてくれること、この2点を覚えておけば落ち着いて対処できます。
実務での使いどころ
実務では、「1つの作業につき1本の枝」を基本にすると見通しが良くなります。新機能なら feature-login、不具合修正なら fix-crash のように、何の作業かが分かる名前で枝を切り、その枝で作業し終えたら本流へマージし、不要になった枝は片付ける、という流れを繰り返します。本流を常に「動く状態」に保ったまま、危なっかしい作業は枝の上で完結させられるのが、ブランチを使う最大の利点です。複数人で開発するときはこの恩恵がいっそう大きく、各自が自分の枝で並行して進め、できたものを順にマージしていくのが現代的な開発の基本形になっています。まずはひとりでも、機能ごとに枝を分けて作業する練習から始めると、マージとコンフリクトの感覚が自然に身につきます。