Git: Gitのマージとコンフリクト解決に関する詳細ガイド

マージとは、異なるブランチからの変更を統合するプロセスです。マージを行うことで、チームは異なる機能を並行して開発し、その後それらを単一のバージョンに統合することができます。マージの原則と競合の解決方法を理解することは、チームでの共同作業において極めて重要です。

1. 合併の基本概念

(1) 合併とは何か?

マージとは、あるブランチの変更を別のブランチに適用するプロセスです。Gitは変更を自動的にマージしようとしますが、2つのブランチの変更が同じ箇所に影響を与える場合、競合が発生することがあります。

100%
graph TB
    A[mainBranch] --> B[MergefeatureBranch]
    B --> C{Is there a conflict??}
    C -->|No conflict| D[Automatic merge successful]
    C -->|There is a conflict| E[Resolve conflicts manually]
    E --> F[Mark the conflict as resolved]
    F --> G[Complete the merger]
    
    style D fill:#d4edda
    style E fill:#fff3cd

(2) 合併の種類

Git では、2 種類のマージがサポートされています:

(3) マージの方向

TEXT 📖 参照専用
git merge feature  # Merge feature into the current branch

マージを行うと、常に指定されたブランチが現在のブランチにマージされます。そのため、マージを行う前に、必ず現在のブランチを確認してください。



2. 早送りマージ

(1) 早送りマージの原則

対象のブランチ(mainなど)に新しいコミットがなく、マージするブランチ(featureなど)に新しいコミットがある場合、Gitは単にmainポインタを先へ進めるだけで済みます。これを「ファストフォワードマージ」と呼びます。

100%
graph LR
    subgraph Before the merger
        C1[SubmitC1] --> C2[SubmitC2]
        C2 --> C3[SubmitC3]
        main1[main] --> C2
        feature1[feature] --> C3
    end
    
    subgraph After the merger
        C4[SubmitC1] --> C5[SubmitC2]
        C5 --> C6[SubmitC3]
        main2[main] --> C6
        feature2[feature] --> C6
    end
    
    style main1 fill:#fff3cd
    style main2 fill:#d4edda

(2) 早送りマージを実行する

▶ サンプル:早送りマージ

BASH
# View Current Status
git log --oneline --graph --all

# Output:
# * d4e5f6g (feature) Add feature
# * a1b2c3d (HEAD -> main) Initial commit

# Switch tomainBranch
git switch main

# MergefeatureBranch
git merge feature

# Output:
# Updating a1b2c3d..d4e5f6g
# Fast-forward
#  feature.js | 1 +
#  1 file changed, 1 insertion(+)
#  create mode 100644 feature.js

# View the merge results
git log --oneline --graph --all

# Output:
# * d4e5f6g (HEAD -> main, feature) Add feature
# * a1b2c3d Initial commit

(3) 高速マージを無効にする

場合によっては、ファストフォワードマージが可能であっても、ブランチの履歴を残すためにマージコミットを作成したいことがあります。

▶ サンプル:高速マージの無効化

BASH
# Usage--no-ffDisable Fast-Forward Merge
git merge --no-ff feature

# Output:
# Merge made by the 'ort' recursive strategy.
#  feature.js | 1 +
#  1 file changed, 1 insertion(+)
#  create mode 100644 feature.js

# View History
git log --oneline --graph --all

# Output:
# *   a1b2c3d (HEAD -> main) Merge branch 'feature'
# |\
# | * d4e5f6g (feature) Add feature
# |/
# * h7i8j9k Initial commit


3. 三社合併

(1) 三者統合の原則

両方のブランチに新しいコミットがある場合、Gitは共通の祖先(マージベース)を見つけ、その後、3ウェイマージを実行する必要があります。

100%
graph TB
    A[Common Ancestor<br/>Merged Base] --> B[mainBranch Commit]
    A --> C[featureBranch Commit]
    B --> D[Three-Party Merger]
    C --> D
    D --> E[Merge Commit]
    
    style A fill:#fff3cd
    style E fill:#d4edda

(2) 三社合併を実施する

▶ サンプル:3社による合併

BASH
# View Branch Status
git log --oneline --graph --all

# Output:
# * d4e5f6g (feature) Feature work
# | * a1b2c3d (HEAD -> main) Main work
# |/
# * h7i8j9k Initial commit

# MergefeatureBranch
git merge feature

# Output:
# Merge made by the 'ort' recursive strategy.
#  feature.js | 1 +
#  1 file changed, 1 insertion(+)

# View the merge results
git log --oneline --graph --all

# Output:
# *   k9l0m1n (HEAD -> main) Merge branch 'feature'
# |\
# | * d4e5f6g (feature) Feature work
# * | a1b2c3d Main work
# |/
# * h7i8j9k Initial commit

(3) マージベースを表示する

▶ サンプル:共通の祖先を見つける

BASH
# Find the common ancestor of two branches
git merge-base main feature

# Output:
# h7i8j9k

# View the content to be merged
git diff $(git merge-base main feature) feature

# Or use the three-point syntax
git diff main...feature


4. マージの競合の解決

(1) 紛争の起源

2つのブランチが同じファイル内の同じ箇所を変更した場合、Gitはそれらを自動的にマージすることができず、コンフリクトが発生します。

▶ サンプル:対立

BASH
# Modifying Files on a Branch
echo "main content" > file.js
git add file.js
git commit -m "Main modification"

# Switch tofeatureBranch
git switch feature

# Modify the same location in the same file
echo "feature content" > file.js
git add file.js
git commit -m "Feature modification"

# Switch back tomainCombine and Merge
git switch main
git merge feature

# Output:
# Auto-merging file.js
# CONFLICT (content): Merge conflict in file.js
# Automatic merge failed; fix conflicts and then commit the result.

(2) 競合状況の確認

▶ サンプル:対立の分析

BASH
# View Status
git status

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

# View Conflicting Files
cat file.js

# Output:
# <<<<<<< HEAD
# main content
# =======
# feature content
# >>>>>>> feature

# View Conflict Details
git diff

# Output:
# <<<<<<< HEAD
# -main content
# =======
# -feature content
# >>>>>>> feature

(3) 対立の解決

▶ サンプル:競合を手動で解決する

BASH
# Editing Files with Conflicts,Select the content to keep
cat file.js

# Method1:RetainmainChanges to
# main content

# Method2:RetainfeatureChanges to
# feature content

# Method3:Merge the changes from both
# main content
# feature content

# Mark the conflict as resolved
git add file.js

# Complete the merger
git commit

# Output:
# [main d4e5f6g] Merge branch 'feature'

(4) ツールを活用して対立を解決する

▶ サンプル:マージツールの使用方法

BASH
# Using a Graphical Merge Tool
git mergetool

# Using Specific Tools
git mergetool --tool=vimdiff

# View available merge tools
git mergetool --tool-help

# UsagecheckoutSelect a Version
git checkout --ours file.js      # Select the current branch version
git checkout --theirs file.js    # Select a branch version to merge

(5) 対立マーカーの詳細な説明

TEXT 📖 参照専用
<<<<<<< HEAD
Content of the current branch(HEAD)
=======
To merge the contents of the branches
>>>>>>> feature


5. 合併戦略

(1) マージ戦略のオプション

Git は、さまざまなマージ戦略をサポートしています:

戦略 説明 活用事例
再帰的 (デフォルト) 再帰的な3ウェイマージ ほとんどの場合
octopus 複数のブランチのマージ 複数のブランチをマージする際に自動的に使用される
ours 他のブランチを無視 現在のブランチを維持
相手側 現在のブランチを無視する マージ対象のブランチを維持する
解決方法 単純な3ウェイマージ 特殊なケース

▶ サンプル:マージ戦略の使用

BASH
# UsagerecursiveStrategy(Default)
git merge feature

# UsageoursStrategy(IgnorefeatureChanges to)
git merge -s ours feature

# UsagerecursiveStrategy Options
git merge -X ours feature    # In case of a conflict, prioritize the current branch
git merge -X theirs feature  # In the event of a conflict, prioritize the branch to be merged
git merge -X ignore-space-change feature  # Ignore changes in whitespace

(2) 圧縮と結合

複数のコミットを1つのコミットにまとめ、その後マージします。

▶ サンプル:圧縮と結合

BASH
# Compress and Merge
git merge --squash feature

# View Status
git status

# Output:
# Changes to be committed:
#   new file:   feature1.js
#   new file:   feature2.js

# Commit the compressed changes
git commit -m "Merge feature branch (squashed)"

# Advantages:Keep the main branch history clean
# Disadvantages:LostfeatureDetailed History of the Branch

(3) マージのみ、コミットは行わない

▶ サンプル:マージのプレビュー

BASH
# Merge but do not commit automatically
git merge --no-commit feature

# View the merge results
git status
git diff --staged

# If you're satisfied,Manual Submission
git commit -m "Merge feature branch"

# If you are not satisfied,Cancel Merge
git merge --abort


6. マージ操作

(1) 合併の停止

▶ サンプル:進行中のマージをキャンセルする

BASH
# Conflicts Arising from Mergers
git merge feature
# CONFLICT (content): Merge conflict in file.js

# Cancel Merge,Restore to the state prior to the merge
git merge --abort

# Or usereset
git reset --merge

(2) マージ履歴を表示する

▶ サンプル:マージされたコミットを表示する

BASH
# View All Merge Commits
git log --merges --oneline

# Output:
# d4e5f6g Merge branch 'feature'
# a1b2c3d Merge branch 'develop'

# View Unmerged Commits
git log --no-merges --oneline

# View details of the merge
git show --stat d4e5f6g

(3) 合併の取り消し

▶ サンプル:完了したマージを元に戻す

BASH
# Undo the Last Merge(Merge requests are still available)
git reset --hard HEAD~1

# UsagerevertRevoke Merger(Create a New Commit)
git revert -m 1 HEAD

# -m 1 Indicates that the first parent commit is being preserved(mainBranch)

# View Results
git log --oneline --graph

❓ よくある質問

Q ファストフォワードマージと3ウェイマージの違いは何ですか?
A ターゲットブランチに新しいコミットがない場合は、ファストフォワードマージが行われます。これは、マージコミットを作成せずにポインタを移動させるだけです。両方のブランチに新しいコミットがある場合は、3ウェイマージが行われます。これは、マージするための共通の祖先を見つけ出し、マージコミットを作成します。
Q マージの競合はどのように解決すればよいですか?
A 競合が発生しているファイルを編集し、競合マーカー(<<<<<<<、=======、>>>>>>>)を削除して必要な内容を残した後、git add を使用して競合を解決済みとしてマークし、最後に git commit を使用してマージを完了させます。
Q --no-ff オプションはいつ使用すべきですか?
A ブランチの履歴を保持し、これがマージ操作であることを明確に示したい場合にこれを使用します。通常、機能ブランチをメインブランチにマージする際に使用され、履歴上でマージポイントが確認できるようになります。
Q 進行中のマージをキャンセルするにはどうすればよいですか?
A git merge --abort を使用すると、マージをキャンセルしてマージ前の状態に戻すことができます。すでに一部の競合を解決している場合は、git reset --merge を使用してリセットすることもできます。
Q スカッシュマージと通常のマージの違いは何ですか?
A スクワッシュマージは、ブランチ上のすべてのコミットを1つのコミットに圧縮するもので、ブランチの詳細な履歴は保持されません。メリットは、メインブランチの履歴が簡潔に保たれることです。デメリットは、ブランチのコミット履歴や文脈情報が失われてしまうことです。

📖 まとめ


📝 練習問題

  1. 基本演習:2つのブランチを作成し、それぞれのブランチで異なるファイルを編集した後、それらをマージして、ファストフォワードマージと3ウェイマージの違いを体験してください。

  2. 応用演習:競合シナリオをシミュレートします。2つのブランチ上で、同じファイルの同じ箇所に変更を加えます。マージを行うと競合が発生しますので、手動で競合を解決し、マージを完了させてください。

  3. 課題:さまざまなマージ戦略(--no-ff、--squash、-X ours など)を使用してブランチをマージし、その結果と各戦略の適切な使用例を比較してください。

Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%