マージ — 定義、マージの種類と動作メカニズム

著者: IT Sectr 公開日: 2026-05-10 読了時間: 10 分

マージ — はGitの操作で、あるブランチから別のブランチへ変更を統合し、マージコミットを作成します。Gitはいくつかの戦略をサポートしています:fast-forward(線形履歴)、three-wayマージ(マージコミットを作成)、squashマージ(すべてのコミットを1つに圧縮)。git-scm.com、2025によると、マージはチームのGit開発で最も使用されるコード統合メカニズムです。

要点

  • マージ — マージコミットあり/なしでブランチを統合するGit操作
  • Fast-forwardマージ — 分岐がない場合に追加コミットなしで線形マージ
  • Three-wayマージ — ブランチ分岐時にマージコミットを作成
  • Squashマージ — マージ前にブランチの全コミットを1つに圧縮
  • コンフリクト — 両方のブランチで同じ行が変更された場合に発生

マージとは?

マージはGitの基本操作で、あるブランチ(ソース)から別のブランチ(ターゲット)へ変更を統合します。マージの結果、ターゲットブランチはソースブランチのまだ含まれていないすべてのコミットを受け取ります。状況に応じて、Gitは3つの異なる方法でマージを実行できます。

マージの主な価値は履歴の保存です:マージコミットはブランチ統合の事実を記録し、いつどのブランチが統合されたかの情報を保持します。これにより、変更の監査、リグレッションの検索、開発の時系列の理解が容易になります。大規模プロジェクトでは、マージコミットがコード統合の標準的な方法です。

GitLab Flowによると、Gitを使用するチームの73%がマージコミットを使用しています。代替アプローチ(リベース、スクワッシュ)は線形履歴を重視するチームが好みます。戦略の選択は、チームの規模、リリース頻度、プロジェクトの規約に依存します。

マージが必要なケース

マージは、開発者が機能の作業を完了し、developまたはmainに統合したい場合に必要です。典型的なシナリオ:開発者がdevelopから機能ブランチを作成し、数日間作業し、その間にdevelopに他のチームメンバーからの新しいコミットが追加されました。統合前に変更を結合する必要があり、これにマージが使用されます。

マージなしでは、Gitで単一のコードベースで協調作業することは不可能です。2人の開発者が同時に同じコードベースに変更を加えるたびに、ブランチは分岐します。マージはデータ損失なしにこれらの変更を戻す唯一の方法です。

Gitのマージタイプ

Gitは3つのマージタイプをサポートしており、それぞれが独自のシナリオ向けに設計されています。マージタイプの選択は、コミット履歴、ロールバックの容易さ、ログの可読性に影響します。

Fast-forwardマージ

Fast-forwardは、ターゲットブランチにソースブランチ作成以降新しいコミットがない場合に発生します。この場合、Gitはターゲットブランチのポインタをソースブランチの最新コミットに単純に進めます。履歴は線形のままで、マージコミットは作成されません。

bash
# Fast-forwardマージ:機能作成以降developは変更なし
git checkout develop
git merge feature/new-login

# 結果:developポインタが機能の末尾に移動
# マージコミットは作成されなかった

Fast-forwardは、開発者が単独で作業する短期間のブランチに便利です。しかし、このアプローチには欠点があります:ブランチが存在したという情報が失われ、すべてのコミットがdevelopに直接行われたように見えます。

Three-wayマージ

Three-wayマージは、分岐ポイント以降に両方のブランチに新しいコミットがある場合に実行されます。Gitは2つの親を持つ別個のマージコミットを作成し、ブランチ統合の事実を記録します。このアプローチはチーム開発の機能ブランチに推奨されます。

bash
# --no-ffフラグで強制three-wayマージ
git checkout develop
git merge --no-ff feature/new-login

# デフォルトメッセージでマージコミット作成
# -mで独自メッセージを設定可能
git merge --no-ff feature/new-login -m "Merge feature/new-login into develop"

--no-ffフラグは、fast-forwardが可能な場合でもマージコミットの作成を保証します。これはプロジェクトでブランチ情報を保存するためのベストプラクティスです。

Squashマージ

Squashマージはソースブランチのすべてのコミットを1つに圧縮してターゲットに適用します。機能の履歴は失われ、すべての変更を含む1つのコミットがブランチに取り込まれます。これは機能ブランチの詳細なコミットが全体の履歴に価値を追加しない場合に便利です。

bash
# Squashマージ:機能の全コミットが1つに圧縮
git checkout develop
git merge --squash feature/experimental
git commit -m "feat: experimental login flow (squashed)"

Squashはドラフト、実験的ブランチ、クリーンな履歴を維持することが重要な状況に適しています。欠点は、元のコミットとの関連性が失われ、個々の変更のロールバックが困難になることです。

OursとTheirs戦略

OursとTheirsはGitの2つの特別なマージ戦略です。Oursはソースブランチからの変更を完全に無視し、ターゲットにあるものだけを保持します。Theirsは逆に、競合があればソースブランチのバージョンを採用します。これらの戦略は、どのバージョンを優先すべきか事前にわかっている場合に、大量のコードをマージする際に有用です。

マージの仕組み

Gitのマージメカニズムは、3つのポイントの比較に基づいています:共通の祖先(マージベース)、ソースブランチの状態、ターゲットブランチの状態。Gitはマージベース(両方のブランチに共通する最新コミット)を見つけ、分岐後に各ブランチで何が変更されたかを計算します。

  • ステップ1 — Gitがマージベースを特定:両方のブランチに存在する最新コミット
  • ステップ2 — Gitが2つの差分を構築:マージベースからソースへ、マージベースからターゲットへ
  • ステップ3 — Gitが両方の変更セットをマージベースに適用しようとする
  • ステップ4 — 変更が競合しない場合、マージは自動的に完了
  • ステップ5 — 競合がある場合、Gitは停止して解決を要求

Gitは三者間マージアルゴリズムを使用しており、比較する2つのファイルバージョンだけでなく、それらの共通祖先も考慮します。これにより、一方のブランチの変更が他方の変更領域に影響しない場合、たとえ両方のファイルが変更されていても、Gitは自動的に解決できます。

マージ動作の例

シナリオを考えます:2人の開発者が1つの機能ブランチ内の異なるファイルで作業しています。1人目がLoginActivity.ktを変更し、2人目がProfileFragment.ktを変更しました。変更をマージするとき、Gitは変更が異なるファイルに影響していることを確認し、人間の介入なしに自動的にマージを実行します。

両方の開発者がLoginActivity.ktを変更した場合でも、異なるメソッドであればGitは自動的に処理し、変更を行ごとにマージします。競合は、両方が同じ行を変更した場合、または一方が他方が変更したコードを削除した場合にのみ発生します。

マージコンフリクトの解決

マージコンフリクトは、両方のブランチが同じ行を異なる方法で変更したため、Gitが自動的に変更をマージできない場合に発生します。この場合、Gitはファイル内の競合領域をマークし、開発者による手動解決を待ちます。

競合領域は特別なマーカーでマークされます:<<<<<<< HEADはターゲットブランチのコード、=======は区切り、>>>>>>> source-branchはソースブランチのコードを示します。開発者は手動でどのバージョンを保持するか、またはそれらを結合するかを選択する必要があります。

bash
# 1. マージを実行しコンフリクトを確認
git merge feature/new-login
# 出力:CONFLICT (content): Merge conflict in LoginActivity.kt

# 2. コンフリクトのあるファイル一覧を表示
git status
# both modified: src/ui/login/LoginActivity.kt

# 3. コンフリクト解決:ファイルを編集、マーカーを削除
# 4. 解決済みファイルを追加してマージを完了
git add src/ui/login/LoginActivity.kt
git merge --continue
# または:git commit(--continueなし)

競合解決のためのツールがあります:git mergetoolはビジュアルマージャー(Meld、Beyond Compare、VS Code)を開きます。多くの開発者はIDEで競合を解決することを好みます — IntelliJ IDEAやAndroid Studioは3ペイン比較の内蔵ツールを提供し、このプロセスを大幅に簡素化します。

競合解決のヒント:競合の各サイドが何をするかを常に理解し、ロジックを理解せずに他人のコードを削除せず、競合が複雑すぎる場合は両方のブランチの作成者を協力的な解決に参加させてください。

マージ vs リベース:どちらを選ぶべきか

マージとリベースの選択はGitで最も一般的なアーキテクチャ上の意思決定の1つです。両方のアプローチは変更を結合しますが、方法が異なります:マージはブランチ履歴を保存し、リベースは履歴を書き換えて線形にします。

  • マージ — コンテキストを保存:いつどのブランチからマージされたかがわかる。公開ブランチ(develop、main)とチーム作業に適している
  • リベース — 余分なマージコミットなしでクリーンな線形履歴を作成。レビュー前の個人用機能ブランチに適している
  • ルール:他の開発者が使用している公開ブランチをリベースしてはいけない

多くのチームはハイブリッドアプローチを使用しています:機能ブランチをdevelopで更新するためにリベース(git rebase develop)し、その後マージを記録するために--no-ffフラグ付きでマージします。これにより、機能内ではクリーンな履歴、developレベルでは情報豊富なマージポイントが得られます。

よくある質問

マージとmerge --no-ffの違いは?

--no-ffなしでは、可能な場合Gitはfast-forwardマージを実行します — 単にブランチポインタを移動します。--no-ffありでは、Gitは常にマージコミットを作成し、ブランチ情報を保持します。チーム開発の機能ブランチに推奨されます。

マージコンフリクトが非常に大きい場合どうするか?

git mergetoolまたはIDEの内蔵ツールを使用してください。コンフリクトが数十のファイルに及ぶ場合、ブランチが乖離しすぎている可能性があります。その場合は、チームとマージ計画を話し合い、可能であれば複数の段階に分割してください。

マージをキャンセルできますか?

はいgit merge --abortはマージがまだ完了していない場合(コンフリクト)にマージをキャンセルします。マージが既に完了している場合は、安全なロールバックのためにgit reset --hard HEAD~1またはgit revert -m 1 <merge-commit>を使用してください。

すべての機能にマージコミットを作成する必要がありますか?

チーム作業には推奨されます。マージコミットは統合の事実を記録し、両方のブランチへの参照を含み、履歴の理解を容易にします。個人用や実験的なブランチには、squashマージまたはfast-forwardが許容されます。

マージはバイナリファイルでどう機能しますか?

Gitはバイナリファイルを自動的にマージできません — 完全に1つのバージョンを選択します。バイナリファイル(画像、.aab、.apk)については、並行変更を最小限に抑え、大きなファイルにはGit LFSを使用することをお勧めします。

まとめ

  • マージ — あるブランチから別のブランチへ変更を統合するGitの基本操作
  • Fast-forward — 分岐がない場合のマージコミットなしの線形マージ
  • Three-wayマージ — 2つの親を持つマージコミットを作成、コンテキストを保持
  • Squashマージ — ブランチの全コミットを1つに圧縮、機能履歴を喪失
  • コンフリクトは同じ行の変更で発生し、手動で解決
  • マージはリベースと異なる:前者はブランチを保存、後者は履歴を線形化
  • 公開ブランチには --no-ff付きマージ推奨、個人用にはリベースまたはスクワッシュ

ターンキー方式のモバイルアプリケーションを開発します

IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。

プロジェクトについて相談

こちらもお読みください