Git: Gitのマージとコンフリクト解決に関する詳細ガイド
マージとは、異なるブランチからの変更を統合するプロセスです。マージを行うことで、チームは異なる機能を並行して開発し、その後それらを単一のバージョンに統合することができます。マージの原則と競合の解決方法を理解することは、チームでの共同作業において極めて重要です。
1. 合併の基本概念
(1) 合併とは何か?
マージとは、あるブランチの変更を別のブランチに適用するプロセスです。Gitは変更を自動的にマージしようとしますが、2つのブランチの変更が同じ箇所に影響を与える場合、競合が発生することがあります。
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ウェイマージ:両方のブランチに新しいコミットがある場合、マージコミットを作成する
(3) マージの方向
git merge feature # Merge feature into the current branch
マージを行うと、常に指定されたブランチが現在のブランチにマージされます。そのため、マージを行う前に、必ず現在のブランチを確認してください。
2. 早送りマージ
(1) 早送りマージの原則
対象のブランチ(mainなど)に新しいコミットがなく、マージするブランチ(featureなど)に新しいコミットがある場合、Gitは単にmainポインタを先へ進めるだけで済みます。これを「ファストフォワードマージ」と呼びます。
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) 早送りマージを実行する
▶ サンプル:早送りマージ
# 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) 高速マージを無効にする
場合によっては、ファストフォワードマージが可能であっても、ブランチの履歴を残すためにマージコミットを作成したいことがあります。
▶ サンプル:高速マージの無効化
# 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ウェイマージを実行する必要があります。
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社による合併
# 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) マージベースを表示する
▶ サンプル:共通の祖先を見つける
# 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はそれらを自動的にマージすることができず、コンフリクトが発生します。
▶ サンプル:対立
# 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) 競合状況の確認
▶ サンプル:対立の分析
# 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) 対立の解決
▶ サンプル:競合を手動で解決する
# 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) ツールを活用して対立を解決する
▶ サンプル:マージツールの使用方法
# 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) 対立マーカーの詳細な説明
<<<<<<< HEAD
Content of the current branch(HEAD)
=======
To merge the contents of the branches
>>>>>>> feature
<<<<<<< HEAD: 現在のブランチの内容の開始=======: 区切り記号。現在のブランチはその上にあり、マージされるブランチはその下にある>>>>>>> feature: ブランチからマージするコンテンツの終わり
5. 合併戦略
(1) マージ戦略のオプション
Git は、さまざまなマージ戦略をサポートしています:
| 戦略 | 説明 | 活用事例 |
|---|---|---|
| 再帰的 (デフォルト) | 再帰的な3ウェイマージ | ほとんどの場合 |
| octopus | 複数のブランチのマージ | 複数のブランチをマージする際に自動的に使用される |
| ours | 他のブランチを無視 | 現在のブランチを維持 |
| 相手側 | 現在のブランチを無視する | マージ対象のブランチを維持する |
| 解決方法 | 単純な3ウェイマージ | 特殊なケース |
▶ サンプル:マージ戦略の使用
# 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つのコミットにまとめ、その後マージします。
▶ サンプル:圧縮と結合
# 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) マージのみ、コミットは行わない
▶ サンプル:マージのプレビュー
# 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) 合併の停止
▶ サンプル:進行中のマージをキャンセルする
# 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) マージ履歴を表示する
▶ サンプル:マージされたコミットを表示する
# 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) 合併の取り消し
▶ サンプル:完了したマージを元に戻す
# 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
❓ よくある質問
git add を使用して競合を解決済みとしてマークし、最後に git commit を使用してマージを完了させます。git merge --abort を使用すると、マージをキャンセルしてマージ前の状態に戻すことができます。すでに一部の競合を解決している場合は、git reset --merge を使用してリセットすることもできます。📖 まとめ
- マージとは、あるブランチの変更内容を別のブランチに統合するプロセスです。
- ファストフォワードマージ:対象ブランチに新しいコミットがない場合は、単にポインタを移動させる
- 3ウェイマージ:両方のブランチに新しいコミットがある場合、マージコミットを作成する
- 競合の解決:競合が発生したファイルを編集し、マーカーを削除して、必要な内容を保持します
- マージ戦略:再帰的(デフォルト)、当社式、他社式、スクイーズなど。
- マージ操作:--abort でキャンセル、--no-commit でプレビュー、revert で元に戻す
📝 練習問題
-
基本演習:2つのブランチを作成し、それぞれのブランチで異なるファイルを編集した後、それらをマージして、ファストフォワードマージと3ウェイマージの違いを体験してください。
-
応用演習:競合シナリオをシミュレートします。2つのブランチ上で、同じファイルの同じ箇所に変更を加えます。マージを行うと競合が発生しますので、手動で競合を解決し、マージを完了させてください。
-
課題:さまざまなマージ戦略(--no-ff、--squash、-X ours など)を使用してブランチをマージし、その結果と各戦略の適切な使用例を比較してください。