【Git】ブランチの定義を考え直す

ブランチの概念を考え直す前に、まずは一般的な定義を確認します。

ブランチとは、履歴の流れを分岐して記録していくためのものです。

サル先生のGit入門

ブランチ(branch)は、1つのプロジェクトから分岐させることにより、プロジェクト本体に影響を与えずに開発を行える機能のことを言います。

SAMURAI ENGINEER

このようにブランチは、「分岐された一連の開発の履歴」として説明されがちです。

そして、この説明は以下のことを暗示しているのだと考えられます。

  1. ブランチは一連の履歴を含んでおり、かなり重いオブジェクトである

  2. 「ブランチを切る」という表現のように、ブランチは独立した直線的な開発の流れである

1の誤解に対して

各ブランチは先端のコミットのSHA1ハッシュで完全に定義されます。

これは以下のコマンドを打てばすぐに確認できます。

git log --oneline

出力結果の黄色の部分がSHA1ハッシュであり、このハッシュは最新コミットの内容の内容はもちろん、その親コミットの内容にも基づいているので過去の履歴も含んでいることになります。

したがって、ブランチは非常に軽いオブジェクトなのです。

2.の誤解に対して

こちらには反例を挙げたいと思います。
例えば"main"と"test"の二つのブランチがあるとします。

  A-----C----E ("main")
   \
    B-----D-----F ("test")

A, C, Eは "main" であり、A, B, D, Fは "test" であることが分かるでしょう。
そして、それぞれの先端は E と F です。

さて、ここで以下のように merge を行うとどうでしょう。

git checkout main # "main"に切り替える
git merge test # "test"をmergeして取り込む

結果は次のようになります。

  A-----C----E----G ("main")
   \             /
    B-----D-----F ("test")

それぞれのブランチでコミットを続けると、

  A-----C----E----G---H ("main")
   \             /
    B-----D-----F----I ("test")

こうなります。つまり、A, B, C, D, E, F, G, Hが main になり、他方 test はA, B, D, F, Iによって構成されることになります。
※merge したことによって、コミットGが生成されたことにも注意しましょう。

ではここで、main ブランチを「独立した直線的」ものとして考えるとどうでしょうか。

main ブランチ(H のSHA1ハッシュ)は B, D, F まで含んでいるため、これは「独立した直線的」とは言えません。

むしろmainブランチは、有向非循環グラフとして考えるべきです。

一番右が有向非巡回グラフ

まとめ


総括すると、ブランチとは、

特定のコミットとその祖先となる全てのコミットを総称した名前

と言うのが妥当かと思います。

「履歴を含んだ重いオブジェクト」や「直線的」などというのは厳密には違うということでした。


参考文献


以上。


この記事が気に入ったらサポートをしてみませんか?