Gitのブランチとマージの基礎知識
皆さん、こんにちは。技術開発グループのn-ozawanです。
ムール貝は水質が悪化するとすぐに殻を閉じる習性があります。その習性を利用してムール貝に慣性測定ユニットを取り付け、水質状況を遠隔で検知するシステムが開発されています。これもIoTですね。
Gitを運用していると避けて通れないのがマージです。作業者は作業用のブランチを作成して修正を行い、その結果をmasterブランチへマージします。今回はGitの初心者向けに、ブランチの作成からマージまでの一連の流れから、Gitで何が起きているのかを確認していきたいと思います。
目次
作業用ブランチの作成とマージ
はじめに
masterブランチから作業用ブランチを作成して修正を行い、masterブランチへマージをする流れを確認します。確認する前に、以前のおさらいを含めて、いくつか整理したいと思います。
Gitはオブジェクトの集合体であり、コミットもオブジェクトで管理しています。コミットオブジェクトはparent
で以前のコミットオブジェクトを指し示すことにより、Gitはコミット履歴を保持します。

上の図はそのコミット履歴を表現しています。C01
が過去に行ったコミットで、C03
が最新のコミットになります。時系列としてはC01
→C02
→C03
ですので、矢印の方向が逆だと思いますが、コミットオブジェクトの指し示す方向がC03
→C02
→C01
となりますので、上の図のようにしています。
上の図にあるmaster
は「masterブランチの先頭のコミットオブジェクトを示すポインタ」となります。HEAD
は「現在作業しているブランチを示すポインタ」であり、masterブランチで作業をしていることを表しています。この後の確認で、これらポイントがどう移り変わるのかも注目してください。
作業用ブランチの作成
では早速ブランチを作成してみましょう。ブランチを作成しただけではコミットオブジェクトは生成されず、C03
を指し示すworking-branch
というポインタが作成されます。
$ git branch working-branch

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

なお、master
やworking-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-branch
とHEAD
がC04
を示すように移動します。この状態のまま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」というアルゴリズムで処理されます。
C04
とC05
が枝分かれ元のコミットオブジェクトC03
を探す。C03
とC04
の差分(→差分A)、C03
とC05
の差分(→差分B)をそれぞれ求める。- 差分Aと差分Bでどちらから一方のみ追加・修正・削除している場合は、その追加・修正・削除した結果を採用する。
- もし、差分Aと差分Bで、同じ個所を追加・修正・削除している場合は、競合として、ユーザーに指示を求める。
色々なマージ
Fast-forward
マージ対象のブランチが、自身のブランチの延長線上にある場合、マージコミットを生成せずに、ポインタをずらすだけとなります。これを「Fast-forward」と呼びます。

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

リベースを行うと、C03
とC04
の差分と、C03
とC05
の差分をマージした、新しいコミットオブジェクトC06
が生成されます。C06
のparentはC05
を指します。なお、以前のC04
は、オブジェクトとしては残っていますが、どこからも参照されなくなるので、ログなどにも表示されなくなります。
おわりに
GitHubなどではPull Requestなどでマージを行うため、あまりマージを意識していなかった方もいらっしゃるのではないでしょうか。ですがマージ処理はGitに関わらず、構成管理ツールでは必須の処理ですので、どのようにマージ処理が行われているのかを知った方が良いでしょう。
ではまた。