git mergeの使い方|ブランチ統合の基本からコンフリクト解決まで

チーム開発でブランチを統合するとき、「どのオプションを使えばいいのか」「コンフリクトが起きたらどう対処すればいいのか」と悩むことはありませんか。git mergeはGitの中でも特に重要なコマンドですが、オプションやマージ戦略が多く、最初は混乱しがちです。

この記事では、git mergeの基本的な使い方から、マージ戦略の選び方、コンフリクト解決の具体的な手順まで、実践的なコード例とともに解説します。

目次

git mergeとは

git mergeは、2つ以上の開発履歴を1つに統合するGitコマンドです。複数のブランチで並行して進められた作業を、共通のブランチ(通常はmainやdevelop)に取り込む際に使用します。

基本的な構文は以下のとおりです。

# 基本構文
git merge <ブランチ名>

# オプション付き
git merge [-n] [--stat] [--no-commit] [--squash] [--[no-]edit]
    [-s <strategy>] [-X <strategy-option>] [-m <msg>] [<commit>...]

# マージ操作の制御
git merge (--continue | --abort | --quit)

たとえば、feature-branchの変更をmainブランチに取り込む場合は、次のように実行します。

# mainブランチに切り替え
git checkout main

# feature-branchをマージ
git merge feature-branch

マージの種類を理解する

git mergeには大きく分けて2種類のマージ方法があります。状況に応じてGitが自動的に選択しますが、オプションで明示的に指定することもできます。

Fast-forwardマージ

マージ対象のブランチが現在のブランチの直接的な子孫である場合、Gitは「Fast-forward」マージを実行します。これは新しいマージコミットを作成せず、単純にブランチポインタを前方に移動させるだけの処理です。

# Fast-forwardマージの例
git checkout main
git merge feature-branch
# 出力: Fast-forward
#        index.html | 2 ++
#        1 file changed, 2 insertions(+)

履歴が線形のまま維持されるため、シンプルでわかりやすいというメリットがあります。ただし、機能ブランチの存在が履歴から見えなくなるため、「いつどの機能が統合されたか」を後から追跡しにくくなる点には注意が必要です。

3-wayマージ

2つのブランチの履歴が分岐している場合、Gitは3-wayマージを実行します。この方式では、両方のブランチのスナップショットと共通の祖先コミットの3つを使用して、新しいマージコミットを作成します。

# 3-wayマージの例
git checkout main
git merge feature-branch
# 出力: Merge made by the 'ort' strategy.
#        src/app.js |   15 +++++++++++++++
#        1 file changed, 15 insertions(+)

マージコミットには2つの親があり、どのブランチからどの変更が来たのかが履歴に記録されます。チーム開発では、この方式のほうが変更の追跡がしやすいため好まれることが多いです。

主要なオプション

git mergeには多くのオプションがありますが、実務でよく使うものを中心に紹介します。

オプション説明
--ffデフォルト。可能な場合はFast-forwardでマージ
--no-ff常にマージコミットを作成(履歴を明確に保持)
--ff-onlyFast-forwardでのみマージ。不可能な場合は中止
--squash変更を適用するがマージコミットは作成しない
--no-commitマージを実行するがコミットせず、ユーザーに確認させる
-m <msg>マージコミットのメッセージを指定
--abortマージを中止し、マージ前の状態に復元
--continueコンフリクト解決後、マージを続行

–no-ffオプションの活用

チーム開発では--no-ffオプションを使うことが推奨されます。これにより、Fast-forwardが可能な場合でも必ずマージコミットが作成され、機能ブランチの存在が履歴に明確に記録されます。

# マージコミットを強制的に作成
git checkout main
git merge --no-ff feature-branch -m "Merge feature: ユーザー認証機能を追加"

この設定をデフォルトにしたい場合は、以下のコマンドでグローバル設定を変更できます。

git config --global merge.ff false

–squashオプションの使いどころ

--squashオプションは、機能ブランチの複数のコミットを1つにまとめてマージしたい場合に便利です。ただし、マージコミットは作成されないため、自動的にコミットされません。

git checkout main
git merge --squash feature-branch
# この時点ではまだコミットされていない

git commit -m "Add feature: 複数コミットを1つにまとめて統合"

プルリクエストでよく使われる「Squash and merge」と同様の効果が得られます。履歴をクリーンに保ちたい場合に有効ですが、個々のコミット履歴は失われる点に注意してください。

マージ戦略を理解する

git mergeは内部的に「マージ戦略」というアルゴリズムを使用して、ブランチの統合方法を決定します。-sオプションで明示的に指定できますが、通常はデフォルトのまま使用して問題ありません。

ort(デフォルト)

「Ostensibly Recursive’s Twin」の略で、Git 2.34で導入された新しいマージ戦略です。v2.50.0以降では、1つのブランチをマージする場合のデフォルトになっています。

# 明示的にort戦略を指定
git merge -s ort feature-branch

ortは3-wayマージアルゴリズムを使用し、ファイルのリネーム検出にも対応しています。従来のrecursive戦略と比べて、大規模リポジトリでのパフォーマンスとメモリ効率が大幅に改善されています。

その他の戦略

戦略用途
recursivev2.50.0以降はortの同義語。後方互換性のために残存
octopus3つ以上のブランチを同時にマージする場合のデフォルト
oursマージ対象の変更をすべて無視し、現在のブランチを維持
subtreeツリー構造が異なるブランチをマージする場合に使用

複数のブランチを同時にマージする場合は、自動的にoctopus戦略が選択されます。

# 複数ブランチの同時マージ(octopus戦略が自動選択)
git merge feature1 feature2 feature3

戦略オプション(-X)の活用

-Xオプションを使うと、マージ戦略の動作を細かく制御できます。特にコンフリクト解決を自動化したい場合に便利です。

オプション説明
oursコンフリクト時に現在のブランチの変更を優先
theirsコンフリクト時にマージ対象ブランチの変更を優先
patience分岐が大きいブランチでミスマージを回避
ignore-space-change空白の変更を無視

コンフリクト時に特定の側を優先する

コンフリクトが発生したとき、一方の変更を自動的に優先させたい場合は-X oursまたは-X theirsを使います。

# コンフリクト時に現在のブランチ(main)の変更を優先
git merge -X ours feature-branch

# コンフリクト時にマージ対象(feature-branch)の変更を優先
git merge -X theirs feature-branch

注意点として、-s ours(戦略)と-X ours(戦略オプション)は異なります。-s oursはマージ対象の変更をすべて無視しますが、-X oursはコンフリクトが発生した部分のみ現在のブランチを優先します。

コンフリクト解決の手順

コンフリクトは、同じファイルの同じ行に対して両方のブランチで異なる変更が加えられた場合に発生します。Gitは自動的にマージできない部分を「コンフリクトマーカー」で示し、手動での解決を求めます。

コンフリクトの検出

マージを実行してコンフリクトが発生すると、以下のようなメッセージが表示されます。

git merge feature-branch
# Auto-merging src/app.js
# CONFLICT (content): Merge conflict in src/app.js
# Automatic merge failed; fix conflicts and then commit the result.

git statusコマンドで、コンフリクトが発生しているファイルを確認できます。

git status
# On branch main
# You have unmerged paths.
#   (fix conflicts and run "git commit")
#
# Unmerged paths:
#   (use "git add <file>..." to mark resolution)
#     both modified:   src/app.js

コンフリクトマーカーの読み方

コンフリクトが発生したファイルには、以下のようなマーカーが挿入されます。

<<<<<<< HEAD
現在のブランチ(main)の変更
=======
マージ対象ブランチ(feature-branch)の変更
>>>>>>> feature-branch

<<<<<<< HEADから=======までが現在のブランチの内容、=======から>>>>>>>までがマージ対象ブランチの内容です。

diff3形式の活用

デフォルトのコンフリクトマーカーでは、「元々どうなっていたか」がわかりません。diff3形式を有効にすると、共通の祖先(変更前の状態)も表示されるため、解決が容易になります。

# diff3形式を有効にする
git config --global merge.conflictStyle diff3

設定後のコンフリクトマーカーは以下のようになります。

<<<<<<< HEAD
現在のブランチの変更
||||||| base
元の内容(共通祖先)
=======
マージ対象ブランチの変更
>>>>>>> feature-branch

これにより、両方のブランチがどのように変更したかを比較しながら、適切な解決方法を判断できます。

解決の手順

コンフリクトを解決するには、以下の手順に従います。

# 1. コンフリクトファイルを確認
git status

# 2. ファイルを編集してコンフリクトマーカーを削除
#    (エディタで開いて、最終的に残したい内容だけにする)

# 3. 解決したファイルをステージング
git add src/app.js

# 4. マージを完了
git commit
# または
git merge --continue

VS Codeなどのエディタを使用している場合は、組み込みのマージエディタで視覚的に解決できます。「Accept Current」「Accept Incoming」「Accept Both」ボタンをクリックするだけで、簡単に選択できます。

VS Codeをマージツールとして設定

VS Codeの3-wayマージエディタを使いたい場合は、以下の設定を追加します。

git config --global merge.tool vscode
git config --global mergetool.vscode.cmd 'code --wait $MERGED'

設定後、コンフリクトが発生したらgit mergetoolコマンドでVS Codeが起動します。

mergeとrebaseの使い分け

ブランチを統合する方法として、mergeの他にrebaseもあります。どちらを使うべきかはチームのワークフローや状況によって異なりますが、基本的な指針を紹介します。

mergeを使うべき場合

共有ブランチや公開ブランチで作業している場合はmergeを使います。複数の開発者が同じブランチで作業しており、変更の履歴とコンテキストを保持する必要がある場合に適しています。

# 公開ブランチへの統合にはmergeを使用
git checkout main
git merge feature-branch

監査やコンプライアンスの目的で完全なトレーサビリティが必要なプロジェクトにも向いています。

rebaseを使うべき場合

プライベートな機能ブランチで作業しており、クリーンな線形履歴を維持したい場合はrebaseを使います。プルリクエスト前にコミットを整理したり、メインブランチの最新変更を取り込む場合に適しています。

# ローカルの機能ブランチでrebaseを使用
git checkout feature-branch
git rebase main

Golden Rule of Rebasing

rebaseを使う際の最も重要なルールは「公開ブランチでは絶対にrebaseしない」ことです。他の開発者が作業しているブランチの履歴を書き換えると、全員の履歴が分岐し、混乱を招きます。

推奨されるワークフローは、ローカルの機能ブランチではrebaseを使ってコミットを整理し、チームとの統合にはmergeを使用するハイブリッドアプローチです。

マージの取り消し

マージ操作を取り消したい場合、状況に応じて異なるコマンドを使用します。

マージ中の中止

コンフリクトが発生してマージを中断したい場合は、--abortオプションを使います。

git merge --abort

このコマンドはマージ前の状態に復元します。ただし、マージ開始前に未コミットの変更があった場合は、完全には復元できない可能性があります。そのため、マージ前にはローカルの変更をコミットまたはstashしておくことを推奨します。

完了したマージの取り消し(ローカルのみ)

まだプッシュしていないマージを取り消す場合は、git resetを使います。

# 直前のマージを取り消し
git reset --merge HEAD~1

# または特定のコミットに戻す
git reset --hard <マージ前のコミットハッシュ>

--hardオプションはワーキングディレクトリの変更も破棄するため、注意して使用してください。

プッシュ済みマージの取り消し

すでにリモートにプッシュしたマージを取り消す場合は、git revertを使います。これは履歴を書き換えずに、マージを打ち消す新しいコミットを作成します。

git revert -m 1 <マージコミットハッシュ>

-m 1オプションは、マージコミットの最初の親(通常はマージ先のブランチ)を維持することを指定しています。

ベストプラクティス

日常的にgit mergeを使う上で、覚えておくと便利なベストプラクティスを紹介します。

マージ前の準備

マージを実行する前に、ローカルの変更をコミットまたはstashしておくことが重要です。未コミットの変更がある状態でマージすると、コンフリクトが発生した際にgit merge --abortで完全に復元できない可能性があります。

# 変更をstashしてからマージ
git stash
git merge feature-branch
git stash pop

コンフリクト予防

コンフリクトを最小化するには、小さく自己完結した変更を頻繁にコミットすることが効果的です。また、メインブランチからの変更を定期的に取り込むことで、大きな差分が蓄積するのを防げます。

# 定期的にmainの変更を取り込む
git checkout feature-branch
git merge main

複数の開発者が同じファイルの同じ部分を同時に編集することを避けるのも、コンフリクト予防に有効です。

履歴の管理

チーム開発では、--no-ffオプションをデフォルトにすることで、機能ブランチの存在が履歴に明確に記録されます。これにより、どのコミットがどの機能に属していたかを後から追跡しやすくなります。

# グローバル設定で--no-ffをデフォルトに
git config --global merge.ff false

よくある質問

Fast-forwardと3-wayマージはどう使い分ければいいですか?

個人開発や小規模なプロジェクトでは、デフォルトのFast-forwardで問題ありません。チーム開発では--no-ffを使って常にマージコミットを作成し、機能ブランチの履歴を明確に残すことを推奨します。

コンフリクトが頻発する場合の対処法は?

メインブランチからの変更を頻繁に取り込むことで、コンフリクトを最小化できます。また、diff3形式を有効にすると、コンフリクトの原因がわかりやすくなり、解決が容易になります。

squashマージはいつ使うべきですか?

機能ブランチに多数の細かいコミット(WIPやtypo修正など)が含まれており、それらを1つのまとまったコミットとして統合したい場合に使います。ただし、個々のコミット履歴は失われるため、詳細な履歴が必要な場合は通常のマージを使ってください。

マージコミットのメッセージはどう書くべきですか?

マージコミットのメッセージには、何をマージしたか(機能名やチケット番号)を明記します。自動生成されるメッセージをそのまま使うこともできますが、-mオプションでカスタマイズすると後から探しやすくなります。

git merge --no-ff feature/user-auth -m "Merge feature: ユーザー認証機能 (#123)"

まとめ

git mergeはブランチ統合の基本となる重要なコマンドです。Fast-forwardと3-wayマージの違いを理解し、--no-ffオプションでチーム開発に適した履歴管理を行うことで、効率的なワークフローを実現できます。

コンフリクトが発生した場合は、diff3形式を活用することで解決が容易になります。また、VS Codeなどのエディタのマージツールを使えば、視覚的にわかりやすく解決できます。

次のステップとして、チームのブランチ戦略(Git Flow、GitHub Flowなど)に合わせて、マージのオプション設定をカスタマイズしてみてください。

参考リンク

Git公式ドキュメント – git-merge

Git Book – Basic Branching and Merging

Atlassian Git Tutorial – Merging vs Rebasing

VS Code – Resolve merge conflicts

さらに深く学びたい方へ

この記事で紹介した技術をマスターするには、体系的な学習が重要です。独学で挫折しそうな方は、現役
エンジニアから直接学べるプログラミングスクールも検討してみてください。

現場で通用するスキルを身につけるなら

DMM WEBCAMPのカリキュラムは、実際の開発現場を想定したチーム開発も経験できます。ポートフォリオ制作
支援もあり、転職活動で差をつけられます。

未経験から4ヶ月でエンジニアとして活躍できるレベルまで成長可能です。

実務レベルのWeb開発スキルを習得するなら

RUNTEQは、1000時間の圧倒的学習量で、現場で即戦力となるWebエンジニアを育成します。Ruby on
Railsに特化し、実際のWebサービス開発を通じて実践力を養います。

卒業生の多くが自社開発企業への転職に成功している実績があります。

じっくり理解を深めたい方へ

この記事で紹介した内容を確実に身につけるには、分からない点をすぐに質問できる環境が重要です。CodeCa
mpなら、現役エンジニアとのマンツーマンレッスンで、あなたのペースで着実にスキルアップできます。

朝7時〜夜23時まで、365日受講可能なので、仕事や学業と両立しながら学習を進められます。

この記事が気に入ったら
フォローしてね!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次