DEV Community

Rizwan Saleem
Rizwan Saleem

Posted on

How to handle merge conflicts without fear — a practical guide for developers

How to handle merge conflicts without fear — a practical guide for developers

Mastering Git Merge Conflicts: A Complete Tutorial

Why Merge Conflicts Happen

A merge conflict arises when Git cannot automatically resolve code differences between two commits. This occurs when:

  • Same line modifications: Two branches edit the same line(s) in the same file differently
  • Deleted vs. modified: One branch deletes a file while another modifies it
  • Competing changes: Both branches add content at the same location

Git can automatically merge changes when they affect different parts of a file or when one branch makes no changes to a section the other modifies. Conflicts only happen when Gitboxedambiguity about which change should win.

Conflict Markers Explained

When a conflict occurs, Git inserts markers into the file:

<<<<<<< HEAD
// Your branch's changes
=======
// Incoming branch's changes
>>>>>>> branch-name
Enter fullscreen mode Exit fullscreen mode
  • <<<<<<< HEAD marks the start of your changes
  • ======= divides your changes from the incoming changes
  • >>>>>>> branch-name marks the end of the conflict

Step-by-Step Resolution Workflow

1. Identify Conflicted Files

git status
Enter fullscreen mode Exit fullscreen mode

This shows which files have conflicts.

2. Open the Conflicted File

Use your preferred text editor or IDE:

### Command line
vim filename.py

### VS Code
code filename.py
Enter fullscreen mode Exit fullscreen mode

Open the file and locate the conflict markers.

3. Understand the Changes

  • Section between <<<<<<< HEAD and ======= = your branch's changes
  • Section between ======= and >>>>>>> branch-name = incoming changes

4. Resolve Manually

Decide which changes to keep:

  • Keep only your branch's changes
  • Keep only the other branch's changes
  • Combine both changes into a new solution

Delete all conflict markers (<<<<<<<, =======, >>>>>>>) after making your modifications.

5. Stage the Resolved File

git add filename.py
Enter fullscreen mode Exit fullscreen mode

This signals to Git that the conflict is resolved.

6. Complete the Merge

git commit -m "Resolved merge conflicts"
Enter fullscreen mode Exit fullscreen mode

This finalizes the merge.

Emergency Abort

If you're stuck or want to start over:

git merge --abort
Enter fullscreen mode Exit fullscreen mode

This resets everything to the state before the merge.

Using Merge Tools

VS Code Merge Editor

VS Code provides a visual merge editor that makes resolving conflicts easier:

  1. Open the conflicted file in VS Code
  2. Use the inline conflict resolver with "Accept Current", "Accept Incoming", or "Accept Both" options
  3. Save and stage the file

Git Mergetool

Configure and use a dedicated merge tool:

git mergetool
Enter fullscreen mode Exit fullscreen mode

This launches your configured diff/merge tool (Meld, KDiff3, Beyond Compare, etc.).

GitHub's Built-in Conflict Resolver

For simple conflicts, GitHub offers an in-browser resolver:

  1. Go to the pull request
  2. Click Resolve conflicts
  3. Use the conflict editor to keep desired changes
  4. Click Mark as resolved for each file
  5. Click Commit merge when all conflicts are resolved

Handling Complex Conflicts

Multiple Conflicts in One File

Scroll through the file to find all conflict marker sets and resolve each one sequentially.

Nested Conflicts

When conflicts contain other conflicts (rare but possible), work from the outermost markers inward, understanding the full context before making decisions.

Binary Files

Binary files (images, compiled binaries) cannot be merged automatically. You must choose one version entirely:

### Keep your version
git checkout --ours path/to/binary.file

### Or keep incoming version
git checkout --theirs path/to/binary.file

git add path/to/binary.file
Enter fullscreen mode Exit fullscreen mode

When Code Logic Conflicts

For conflicts where both changes are valid but logically incompatible:

  1. Review both changes carefully
  2. Talk to the teammate who made the other changes
  3. Consider if a third solution exists that incorporates both intents
  4. Don't just pick one side without understanding the impact

Rebase vs Merge: Conflict Differences

Merge Conflicts

git merge main
Enter fullscreen mode Exit fullscreen mode
  • Creates a merge commit
  • Preserves branch history exactly as it happened
  • Regular git push works after resolving
  • Better for shared branches

Rebase Conflicts

git rebase main
Enter fullscreen mode Exit fullscreen mode
  • Rewrites history by replaying your commits on top of main
  • You may resolve conflicts multiple times (once per commit)
  • Requires git push --force-with-lease after (never force-push shared branches)
  • Produces cleaner, linear history

Rebase Conflict Resolution

### Resolve the conflict in the file
git add filename.py

### Continue rebasing
git rebase --continue

### Skip a problematic commit
git rebase --skip

### Abort entire rebase
git rebase --abort
Enter fullscreen mode Exit fullscreen mode

Key rule: Never rebase a branch that isn't yours; be careful rebasing shared branches.

Conflict Prevention Patterns

1. Pull Latest Changes Frequently

git pull origin main
Enter fullscreen mode Exit fullscreen mode

Regularly update your branch to stay current with recent modifications.

2. Use the "Sandwich Effect" with Rebase

### First, pull latest master
git pull

### Then rebase your branch onto master
git rebase main
Enter fullscreen mode Exit fullscreen mode

Do this at least once daily for long-lived branches.

3. Make Small, Frequent Commits

Smaller commits make conflicts easier to identify and resolve incrementally.

4. Enable git rerere

git config --global rerere.enabled true
Enter fullscreen mode Exit fullscreen mode

This remembers how you resolved conflicts, so Git auto-applies the same resolution if the same conflict appears again.

5. Communicate Before Large Changes

Discuss critical or large changes with your team before implementing to avoid overlapping work.

6. Keep Branch Lifetimes Short

Long-lived branches diverge significantly, making merges more complex.

Team Workflows That Minimize Conflicts

Feature Branch Workflow

  • Everyone works on their own branch
  • One topic per branch (avoid "everything I worked on this month" PRs)
  • Branches are cheap-create them frequently

Daily Sync Routine

### Start the day by pulling/rebasing from upstream main
git fetch origin
git rebase origin/main
Enter fullscreen mode Exit fullscreen mode

Everyone does this daily.

Code Review Gates

  • Only one person/group can approve merges to main
  • Reviewers check for potential conflicts before approving
  • Author resolves conflicts before merging

Conventional File Ownership

  • Team members coordinate on who works on specific files
  • Use CODEOWNERS files in GitHub to assign reviewers per directory
  • Avoid having multiple people editing the same configuration files simultaneously

Pull Request Size Limits

  • Keep PRs small (<400 lines changed)
  • Small PRs merge faster and conflict less
  • Reviewers catch conflicts earlier

Real Examples

Example 1: Simple Line Conflict

Branch A added a function:

def calculate_total(items):
    return sum(items)
Enter fullscreen mode Exit fullscreen mode

Branch B modified the same function:

def calculate_total(items, tax_rate):
    return sum(items) * (1 + tax_rate)
Enter fullscreen mode Exit fullscreen mode

Conflict:

<<<<<<< HEAD
def calculate_total(items):
    return sum(items)
=======
def calculate_total(items, tax_rate):
    return sum(items) * (1 + tax_rate)
>>>>>>> feature-tax
Enter fullscreen mode Exit fullscreen mode

Resolution (combine both):

def calculate_total(items, tax_rate=0):
    return sum(items) * (1 + tax_rate)
Enter fullscreen mode Exit fullscreen mode

Example 2: Import Statement Conflict

Team member A added a new import:

import pandas as pd
Enter fullscreen mode Exit fullscreen mode

Team member B added a different import at the same location:

import numpy as np
Enter fullscreen mode Exit fullscreen mode

Resolution (keep both):

import pandas as pd
import numpy as np
Enter fullscreen mode Exit fullscreen mode

Example 3: Configuration File Conflict

Two developers modified the same config.yaml:

<<<<<<< HEAD
database:
  host: localhost
  port: 5432
=======
database:
  host: production.db.example.com
  port: 5432
>>>>>>> feature-deployment
Enter fullscreen mode Exit fullscreen mode

Resolution (use production settings, but discuss with team):

database:
  host: production.db.example.com
  port: 5432
Enter fullscreen mode Exit fullscreen mode

Quick Reference Cheatsheet

Situation Command
View conflicted files git status
Abort merge git merge --abort
Stage resolved file git add filename
Complete merge git commit
Abort rebase git rebase --abort
Continue rebase git rebase --continue
Skip rebase commit git rebase --skip
Use merge tool git mergetool

Key Takeaways

  1. Don't fear conflicts-they're normal and teach you about your codebase
  2. Resolve conflicts early by pulling/rebasing daily
  3. Understand both sides before deciding which changes to keep
  4. Communicate with teammates before making large changes to shared files
  5. Use tools (VS Code, GitHub, mergetool) to simplify resolution
  6. Keep branches short-lived to minimize divergence

Merge conflicts are inevitable in collaborative development, but with these strategies and workflows, you can minimize their frequency and resolve them efficiently when they occur.


Rizwan Saleem — https://rizwansaleem.co

Top comments (0)