Gitのブランチとマージの基礎知識

皆さん、こんにちは。技術開発グループのn-ozawanです。
ムール貝は水質が悪化するとすぐに殻を閉じる習性があります。その習性を利用してムール貝に慣性測定ユニットを取り付け、水質状況を遠隔で検知するシステムが開発されています。これもIoTですね。

Gitを運用していると避けて通れないのがマージです。作業者は作業用のブランチを作成して修正を行い、その結果をmasterブランチへマージします。今回はGitの初心者向けに、ブランチの作成からマージまでの一連の流れから、Gitで何が起きているのかを確認していきたいと思います。

作業用ブランチの作成とマージ

はじめに

masterブランチから作業用ブランチを作成して修正を行い、masterブランチへマージをする流れを確認します。確認する前に、以前のおさらいを含めて、いくつか整理したいと思います。

Gitはオブジェクトの集合体であり、コミットもオブジェクトで管理しています。コミットオブジェクトはparentで以前のコミットオブジェクトを指し示すことにより、Gitはコミット履歴を保持します。

上の図はそのコミット履歴を表現しています。C01が過去に行ったコミットで、C03が最新のコミットになります。時系列としてはC01C02C03ですので、矢印の方向が逆だと思いますが、コミットオブジェクトの指し示す方向がC03C02C01となりますので、上の図のようにしています。

上の図にあるmasterは「masterブランチの先頭のコミットオブジェクトを示すポインタ」となります。HEADは「現在作業しているブランチを示すポインタ」であり、masterブランチで作業をしていることを表しています。この後の確認で、これらポイントがどう移り変わるのかも注目してください。

作業用ブランチの作成

では早速ブランチを作成してみましょう。ブランチを作成しただけではコミットオブジェクトは生成されず、C03を指し示すworking-branchというポインタが作成されます。

$ git branch working-branch

現在、HEADはmasterブランチを指しています。作業用ブランチで作業するには、作業用ブランチであるworking-branchブランチに切り替える必要があります。

$ git checkout working-branch

なお、masterworking-branchなどのポイントがどのコミットオブジェクトを示しているのかは、git show-refで確認することが出来ます。また、HEADがどのブランチを示しているのかは、git branchで確認できます。

$ git show-ref
409446556d6dc118d564002718234c47c2178353 refs/heads/master
409446556d6dc118d564002718234c47c2178353 refs/heads/working-branch

$ git branch
  master
* working-branch

作業用ブランチの修正

ファイルを修正してコミットします。

$ git add -A
$ git commit -m "作業用ブランチで修正した。"

C04コミットオブジェクトが生成され、working-branchHEADC04を示すように移動します。この状態のままmasterブランチを修正すると以下のようになります。

masterへのマージ

working-branchブランチの修正分をmasterブランチにマージします。working-branchからmasterへマージするには、masterブランチにcheckoutしてから、git mergeコマンドを実行します。

$ git checkout master
$ git merge working-branch

マージが行われるとコミットオブジェクトが生成されます。このコミットオブジェクトは「マージコミット」と呼ばれており、2つのparentにより、それぞれのコミットオブジェクトを指し示します。

Gitのマージは「3-way merge」というアルゴリズムで処理されます。

  1. C04C05が枝分かれ元のコミットオブジェクトC03を探す。
  2. C03C04の差分(→差分A)、C03C05の差分(→差分B)をそれぞれ求める。
  3. 差分Aと差分Bでどちらから一方のみ追加・修正・削除している場合は、その追加・修正・削除した結果を採用する。
  4. もし、差分Aと差分Bで、同じ個所を追加・修正・削除している場合は、競合として、ユーザーに指示を求める。

色々なマージ

Fast-forward

マージ対象のブランチが、自身のブランチの延長線上にある場合、マージコミットを生成せずに、ポインタをずらすだけとなります。これを「Fast-forward」と呼びます。

リベース

マージに似たような機能として「リベース」というものがあります。リベースはそのブランチが枝分かれしたコミットオブジェクトを最新化します。例えば、C03から枝分かれしたworking-branchブランチで修正を行っている最中に、masterブランチにC05がコミットされたとします。この時、C05から枝分かれしたことにしたい場合に、リベースを行います。

リベースを行うと、C03C04の差分と、C03C05の差分をマージした、新しいコミットオブジェクトC06が生成されます。C06のparentはC05を指します。なお、以前のC04は、オブジェクトとしては残っていますが、どこからも参照されなくなるので、ログなどにも表示されなくなります。

おわりに

GitHubなどではPull Requestなどでマージを行うため、あまりマージを意識していなかった方もいらっしゃるのではないでしょうか。ですがマージ処理はGitに関わらず、構成管理ツールでは必須の処理ですので、どのようにマージ処理が行われているのかを知った方が良いでしょう。

ではまた。

採用情報

「チームアイオス」入団者募集

〜就活で悩むアナタに来て欲しい〜