+ 作るログイン
図を読み込んでいます…
1 / 7
動きでわかる Webとデータの仕組み / 全10章

Git:枝が増えると、何が動くのか

発行
アニメモ公式
版
第1版
改訂
コマ
全7

コミットとブランチ参照を分けて描き、分岐、fast-forward、2親のマージ、競合解消の意味を理解する。

コミットと、それを指す名前を分ける

Gitのコミットはスナップショットと親への参照などを持つ、履歴の記録です。図のBはAを親に持っています。灰色の矢印は、新しい記録から親へ向けて描いています。 時間が進む向きとは逆なので注意してください。

ブランチ main は、先端のコミットBを指す参照です。通常のブランチ上で作業しているとき、HEADは現在のブランチを指します。ここではdetached HEADは扱いません。

A、Bなどは説明用の短い名前で、実際のコミットIDではありません。Pro Git:ブランチの基本

  • 07 / WEB SYSTEMS
  • 1 / 7
  • コミットは履歴。ブランチは先端を指す名前
  • HEAD → main
  • main
  • A
  • B
  • A・Bは説明用のコミット名
  • 灰色の矢印は、コミットから親へ向いている。

名前を増やしても、履歴を全部複製するわけではない

git switch -c feature で新しいブランチを作って切り替えた場面です。mainとfeatureの二つが、同じBを指しています。HEADはfeatureを指すようになります。

図で増えたのは参照であり、AとBの別コピーがもう一組できたわけではありません。履歴の同じ部分を複数の参照からたどれます。

本文中のコマンドは説明用です。教材を作るために、あなたの作業ブランチを変更するコマンドを実行したわけではありません。

  • 07 / WEB SYSTEMS
  • 2 / 7
  • ブランチを作ると、名前が一つ増える
  • HEAD → feature
  • main
  • A
  • B
  • git switch -c feature
  • feature
  • 同じBを、mainとfeatureの二つの参照が指せる。

新しいコミットに、今のブランチだけが進む

feature上で変更をコミットし、新しい記録Cができました。Cの親はBです。featureはCを指すようになり、mainはBのままです。

ブランチは、積み重ねた変更そのものの名前というより、履歴の先端を指す名前です。図の緑の参照が動き、過去のコミットは同じ場所に残ることに注目してください。

通常のコミットを作った場合、親のBを書き換えてCに変えるのではなく、Bを親に持つ別のコミットが作られます。履歴を書き換える操作は、この作品では扱いません。

  • 07 / WEB SYSTEMS
  • 3 / 7
  • featureで記録すると、その先端が進む
  • feature
  • C
  • main
  • A
  • B
  • HEAD → feature
  • CはBを親に持つ。mainはBにとどまる。

mainが遅れているだけなら、先端を進められる

mainへ切り替えて git merge feature を行う場面です。mainのBがfeatureのCの祖先で、分岐した別の変更がないなら、fast-forwardできます。

この場合はmainをCへ進めるだけで、新しいマージコミットは必要ありません。featureもCを指しています。ここでは、fast-forwardを許す通常の設定を前提とします。

「マージしたら必ず二つの親を持つ記録が増える」とは限りません。統合先が、相手の履歴上に既に含まれているかが分かれ目です。Pro Git:基本的なマージ

  • 07 / WEB SYSTEMS
  • 4 / 7
  • 枝分かれしていなければ、先端を進めるだけ
  • main
  • HEAD → main
  • C
  • feature
  • A
  • B
  • mainをCへ進める
  • fast-forwardでは、新しいマージコミットを作らない。

今度は、双方に別のコミットがある場合

前のfast-forwardとは別の経路を考えます。Bで分岐した後、featureでCを作る一方、mainでもDを作った状態です。Bは共通の祖先ですが、CとDは互いの祖先ではありません。

この状態でmainをただCへ移すと、main側のDを統合したことにはなりません。両方の変更を反映した結果を作る必要があります。

図では、同じBから二本の履歴が伸びています。別のブランチ名があること自体と、コミットの履歴が実際に分岐していることは区別してください。

  • 07 / WEB SYSTEMS
  • 5 / 7
  • 別の分岐:mainにも、新しい記録ができた
  • feature
  • HEAD → main
  • C
  • A
  • B
  • main
  • D
  • 共通の祖先は B
  • 共通の祖先Bから、CとDへ別々に進んだ場合を考える。

統合結果と、二つの親を記録する

main上でfeatureを通常のマージにより統合します。Gitは共通の祖先Bと、それぞれの先端を基に変更を統合し、結果を新しいマージコミットMとして記録します。

MはDとCを親に持ち、mainはMを指します。featureはCのままです。以前のコミットが一つへ潰される操作ではありません。ここではsquashやrebaseによる統合とは区別しています。

図の二本の親への矢印は、どの履歴を統合したかの情報です。内容が自動で統合できた場合の、マージ完了後の状態を示しています。

  • 07 / WEB SYSTEMS
  • 6 / 7
  • 通常のマージで、二つの親を持つMができる
  • feature
  • HEAD → main
  • C
  • main
  • A
  • B
  • M
  • D
  • Mの親は C と D
  • 分岐した履歴を残し、統合後のスナップショットを記録する。

同じ場所の変更は、自動で選んでくれる?

自動で統合できない場合があります。例えば、共通の文を片方で「購入する」、もう片方で「予約する」に変え、Gitが両方を統合できなければ競合になります。

作業者が意図を確認して内容を解決し、解決済みのファイルをステージしてコミットします。同じ行を触ったら常に競合する、と機械的に決まるわけでもありません。

コミットは記録、ブランチは参照、マージは履歴と内容の統合。 どれが動くのかを分けて見ると、ブランチ図が操作の説明として読めるようになります。Pro Git:マージ競合

  • 07 / WEB SYSTEMS
  • 7 / 7
  • 確認:同じ場所を変えたら、勝手に選ばれる?
  • main側の変更
  • feature側の変更
  • 表示文を「購入する」に変更
  • 同じ箇所を「予約する」に変更
  • 意図を確認 → 解決 → commit
  • 自動統合できない競合は、内容を解決してから記録する。

0 件のコメント

読み込み中…

権利侵害・不適切な内容の連絡: [email protected]