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
-
<<<<<<< HEADmarks the start of your changes -
=======divides your changes from the incoming changes -
>>>>>>> branch-namemarks the end of the conflict
Step-by-Step Resolution Workflow
1. Identify Conflicted Files
git status
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
Open the file and locate the conflict markers.
3. Understand the Changes
- Section between
<<<<<<< HEADand======== 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
This signals to Git that the conflict is resolved.
6. Complete the Merge
git commit -m "Resolved merge conflicts"
This finalizes the merge.
Emergency Abort
If you're stuck or want to start over:
git merge --abort
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:
- Open the conflicted file in VS Code
- Use the inline conflict resolver with "Accept Current", "Accept Incoming", or "Accept Both" options
- Save and stage the file
Git Mergetool
Configure and use a dedicated merge tool:
git mergetool
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:
- Go to the pull request
- Click Resolve conflicts
- Use the conflict editor to keep desired changes
- Click Mark as resolved for each file
- 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
When Code Logic Conflicts
For conflicts where both changes are valid but logically incompatible:
- Review both changes carefully
- Talk to the teammate who made the other changes
- Consider if a third solution exists that incorporates both intents
- Don't just pick one side without understanding the impact
Rebase vs Merge: Conflict Differences
Merge Conflicts
git merge main
- Creates a merge commit
- Preserves branch history exactly as it happened
- Regular
git pushworks after resolving - Better for shared branches
Rebase Conflicts
git rebase main
- Rewrites history by replaying your commits on top of main
- You may resolve conflicts multiple times (once per commit)
- Requires
git push --force-with-leaseafter (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
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
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
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
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
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)
Branch B modified the same function:
def calculate_total(items, tax_rate):
return sum(items) * (1 + tax_rate)
Conflict:
<<<<<<< HEAD
def calculate_total(items):
return sum(items)
=======
def calculate_total(items, tax_rate):
return sum(items) * (1 + tax_rate)
>>>>>>> feature-tax
Resolution (combine both):
def calculate_total(items, tax_rate=0):
return sum(items) * (1 + tax_rate)
Example 2: Import Statement Conflict
Team member A added a new import:
import pandas as pd
Team member B added a different import at the same location:
import numpy as np
Resolution (keep both):
import pandas as pd
import numpy as np
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
Resolution (use production settings, but discuss with team):
database:
host: production.db.example.com
port: 5432
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
- Don't fear conflicts-they're normal and teach you about your codebase
- Resolve conflicts early by pulling/rebasing daily
- Understand both sides before deciding which changes to keep
- Communicate with teammates before making large changes to shared files
- Use tools (VS Code, GitHub, mergetool) to simplify resolution
- 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)