Skip to main content

Merge Strategies & Conflict Resolution

Module 02 75 min

Section Objectives

  • Understand the different merge strategies (fast-forward, 3-way, squash)
  • Perform a merge without conflicts
  • Resolve merge conflicts with confidence
  • Choose the right merge strategy for each situation

Types of Merges

1. Fast-Forward Merge

A fast-forward merge occurs when the target branch has no new commits since the branch diverged. Git simply moves the pointer forward — no merge commit is created.

After git merge feature/login (fast-forward):

# Perform a fast-forward merge
git switch main
git merge feature/login

# Force a merge commit even if fast-forward is possible
git merge --no-ff feature/login

2. Three-Way Merge (Recursive)

When both branches have diverged (each has new commits), Git creates a merge commit with two parents.

git switch main
git merge feature/auth
# Opens editor for merge commit message

3. Squash Merge

Condenses all commits from a branch into one single commit on the target branch:

git switch main
git merge --squash feature/messy-history
git commit -m "feat: complete payment feature"
# All changes from feature/messy-history → single clean commit

Comparison of Merge Strategies

StrategyCreates merge commit?Preserves history?When to use
Fast-forwardNoYes (linear)Short-lived feature branches
3-way mergeYesYes (all commits)Long-lived branches
--no-ffAlways yesYesWhen you want to mark the merge
SquashNo (1 commit)No (squashed)Messy history, clean main

Performing a Merge

# Standard workflow
git switch main # Switch to target branch
git pull # Ensure it's up to date
git merge feature/login # Merge the feature branch

# View the result
git log --oneline --graph

# After merge, delete the feature branch (optional)
git branch -d feature/login

Merge Conflicts

A conflict occurs when the same lines in the same file were modified differently on both branches.

Simulating a Conflict

# Initial state
echo "Hello World" > greeting.txt
git add greeting.txt
git commit -m "initial greeting"

# Branch 1: modify the greeting
git switch -c branch-alice
echo "Hello Alice!" > greeting.txt
git commit -am "feat: Alice's greeting"

# Branch 2: different modification
git switch main
echo "Hello Bob!" > greeting.txt
git commit -am "feat: Bob's greeting"

# Merge: CONFLICT!
git merge branch-alice
# CONFLICT (content): Merge conflict in greeting.txt

Conflict Markers

Git marks conflicts with special markers in the file:

<<<<<<< HEAD
Hello Bob!
=======
Hello Alice!
>>>>>>> branch-alice
SectionMeaning
<<<<<<< HEADStart of YOUR version (current branch)
=======Separator
>>>>>>> branch-aliceEnd of INCOMING version (branch being merged)

Resolving Conflicts

Method 1: Manual Resolution

# 1. Open the conflicted file
# 2. Edit it to remove the markers and keep what you want
# 3. Final result (your choice):
echo "Hello Alice and Bob!" > greeting.txt

# 4. Mark as resolved
git add greeting.txt

# 5. Complete the merge
git commit # Opens editor with pre-filled merge commit message
# or
git commit -m "merge: resolve greeting conflict - include both names"

Method 2: git checkout --ours/--theirs

# Keep only YOUR version (current branch)
git checkout --ours greeting.txt
git add greeting.txt

# Keep only the INCOMING version (branch being merged)
git checkout --theirs greeting.txt
git add greeting.txt

Method 3: VS Code Merge Editor

VS Code has a built-in merge editor that makes it visual:

  1. Open the conflicted file in VS Code
  2. You'll see "Accept Current Change" / "Accept Incoming Change" / "Accept Both" buttons
  3. Click the appropriate option
  4. Save the file
  5. git add and git commit

Method 4: git mergetool

# Open a graphical merge tool
git mergetool

# Configure VS Code as merge tool
git config --global merge.tool vscode
git config --global mergetool.vscode.cmd 'code --wait $MERGED'

Aborting a Merge

# Abort a merge in progress (restore pre-merge state)
git merge --abort

# Check that the state is clean
git status

Strategies for Preventing Conflicts

StrategyDescription
Frequent small mergesMerge often to avoid large divergences
Clear responsibilitiesEach developer owns different files
Feature flagsMerge code without activating it
CommunicationTell your team when modifying shared files
Regular git pullStay up to date with main
Good code structureSingle Responsibility Principle → smaller files

Common Conflict Scenarios

Two developers modified the same function
<<<<<<< HEAD
def calculate_price(item, tax_rate=0.20):
return item['price'] * (1 + tax_rate)
=======
def calculate_price(item, discount=0):
return item['price'] * (1 - discount)
>>>>>>> feature/discounts

Resolution: Combine both features:

def calculate_price(item, tax_rate=0.20, discount=0):
return item['price'] * (1 - discount) * (1 + tax_rate)
JSON configuration file conflict
<<<<<<< HEAD
{
"version": "2.0",
"port": 3000
=======
{
"version": "2.0",
"port": 8080,
"debug": true
>>>>>>> feature/debug-mode

Resolution: Combine the two:

{
"version": "2.0",
"port": 3000,
"debug": true
}

Summary of Key Commands

CommandDescription
git merge <branch>Merge a branch
git merge --no-ff <branch>Force merge commit
git merge --squash <branch>Squash and merge
git merge --abortCancel merge in progress
git checkout --ours <file>Keep our version
git checkout --theirs <file>Keep their version
git mergetoolOpen merge tool

Next Steps