Merge conflicts are one of the most intimidating parts of Git for beginners, but they're actually straightforward once you understand them. A conflict simply means Git found changes it can't automatically combine and needs your help deciding what to keep. In this lesson, you'll learn what causes conflicts, how to read conflict markers, resolve conflicts step-by-step, use merge tools, and prevent conflicts from happening in the first place. By the end, conflicts won't be scaryβthey'll just be part of your normal workflow!
What Are Merge Conflicts?
A merge conflict occurs when Git can't automatically combine changes from different branches.
When Do Conflicts Happen?
Conflicts occur when:
- Same lines changed: Two branches modify the same lines in a file
- File deleted in one branch: One branch deletes a file another branch modifies
- File renamed: Different branches rename the same file differently
The good news:
Most merges don't have conflicts! Git automatically merges changes to different parts of files. Conflicts only happen when changes overlap in ways Git can't reconcile automatically.
Example Scenario
Starting point (main branch):
<h1>Welcome</h1>
You (on main):
<h1>Welcome to My Site</h1>
Teammate (on feature branch):
<h1>Welcome to Our Website</h1>
Both changed the same line!
Git can't decide which to keep β CONFLICTπ‘ Conflicts Are Normal
Merge conflicts are a normal part of collaborative development. They're not errors or bugsβthey're Git asking for your help making a decision. Don't panic when you see them!
Anatomy of a Conflict
When a conflict occurs, Git adds special markers to the file to show you what's conflicting:
<<<<<<< HEAD
<h1>Welcome to My Site</h1>
=======
<h1>Welcome to Our Website</h1>
>>>>>>> feature-branchUnderstanding the Markers
Conflict markers explained:
<<<<<<< HEAD- Marks the start of the conflict
- HEAD = your current branch (what you have)
=======- Separates the two conflicting versions
>>>>>>> feature-branch- Marks the end of the conflict
- Shows what branch you're merging from
Visual Breakdown
<<<<<<< HEAD β Your changes start here
<h1>Welcome to My Site</h1> β What YOU have
======= β Separator
<h1>Welcome to Our Website</h1> β What's INCOMING
>>>>>>> feature-branch β Incoming changes end hereMultiple Conflicts in One File
A file can have multiple conflict sections:
function greet() {
<<<<<<< HEAD
console.log("Hello!");
=======
console.log("Hi there!");
>>>>>>> feature-branch
}
function calculate() {
<<<<<<< HEAD
return x + y;
=======
return x * y;
>>>>>>> feature-branch
}You'll need to resolve each conflict section independently.
Detecting Conflicts
When Merging
You'll see a conflict message when merging:
git merge feature-branch
# Output:
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.Check Status
git status
# Output:
On branch main
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: index.html
both modified: app.js
no changes added to commitIdentify Conflicted Files
Files with conflicts are marked as "both modified" in git status. These are the files you need to fix.
Resolving Conflicts Step-by-Step
Step 1: Identify Conflicted Files
git status
# Look for "both modified" filesStep 2: Open Conflicted File
Open the file in your editor. You'll see conflict markers:
<!DOCTYPE html>
<html>
<head>
<title>My Website</title>
</head>
<body>
<<<<<<< HEAD
<h1>Welcome to My Site</h1>
<p>This is my personal website.</p>
=======
<h1>Welcome to Our Website</h1>
<p>This is our company website.</p>
>>>>>>> feature-branch
</body>
</html>Step 3: Decide What to Keep
You have several options:
Option A: Keep Your Version
<body>
<h1>Welcome to My Site</h1>
<p>This is my personal website.</p>
</body>Option B: Keep Their Version
<body>
<h1>Welcome to Our Website</h1>
<p>This is our company website.</p>
</body>Option C: Keep Both (Combined)
<body>
<h1>Welcome to Our Website</h1>
<p>This is our company's personal website.</p>
</body>Option D: Write Something New
<body>
<h1>Welcome</h1>
<p>Explore our site to learn more.</p>
</body>Critical: You MUST remove ALL conflict markers (<<<<<<<, =======, >>>>>>>) from the file!
Step 4: Mark as Resolved
After editing, stage the file:
# Stage the resolved file
git add index.html
# Check status
git status
# Shows: "All conflicts fixed but you are still merging."Step 5: Complete the Merge
# Commit the merge
git commit
# Git opens editor with pre-filled merge message:
# "Merge branch 'feature-branch'"
# You can edit it or just save and closeDone! The conflict is resolved and the merge is complete.
Complete Example
# Start merge
git merge feature-branch
# CONFLICT (content): Merge conflict in index.html
# Check what's conflicted
git status
# Open and edit index.html to resolve conflicts
# Remove conflict markers, keep desired changes
# Stage resolved file
git add index.html
# Check everything is resolved
git status
# Complete merge
git commit -m "Merge feature-branch, resolved conflicts in index.html"
# Verify
git log --oneline -3Conflict Resolution Strategies
Strategy 1: Accept One Side Completely
Use when one version is clearly correct:
# Keep your version (ours)
git checkout --ours index.html
git add index.html
# Keep their version (theirs)
git checkout --theirs index.html
git add index.htmlUse with caution! This accepts ALL changes in the file from one side. Only use when you're certain one side is completely correct.
Strategy 2: Manual Resolution
Most common approachβmanually edit to combine best of both:
// Before (conflict):
<<<<<<< HEAD
function calculate(a, b) {
return a + b;
}
=======
function calculate(x, y) {
return x * y;
}
>>>>>>> feature-branch
// After (resolved):
function calculate(a, b) {
// Combined: kept parameter names from HEAD, operation from feature
return a * b;
}Strategy 3: Rewrite Both Sections
When neither version is quite right:
// Before (conflict):
<<<<<<< HEAD
if (user) return true;
=======
if (user && user.active) return true;
>>>>>>> feature-branch
// After (better solution):
if (user?.active) return true; // Modern optional chainingUsing Merge Tools
Visual merge tools make conflict resolution easier by showing three-way diffs:
Built-in Git Mergetool
# Launch configured merge tool
git mergetool
# Git will open each conflicted file in the toolPopular Merge Tools
VS Code (Built-in)
VS Code automatically detects conflicts and shows buttons:
- Accept Current Change: Keep your version
- Accept Incoming Change: Keep their version
- Accept Both Changes: Keep both
- Compare Changes: See side-by-side diff
Configure Git to Use VS Code
git config --global merge.tool vscode
git config --global mergetool.vscode.cmd 'code --wait $MERGED'Other Popular Tools
- KDiff3: Free, cross-platform
- P4Merge: Free from Perforce
- Meld: Open-source, Linux/Windows/Mac
- Beyond Compare: Commercial, powerful
- Sublime Merge: From Sublime Text makers
Three-Way Merge View
Most merge tools show three panels:
βββββββββββββββ¬ββββββββββββββ¬ββββββββββββββ
β YOURS β BASE β THEIRS β
β (current) β (common) β (incoming) β
βββββββββββββββ΄ββββββββββββββ΄ββββββββββββββ€
β RESULT (merged) β
βββββββββββββββββββββββββββββββββββββββββββ- Yours: Your current branch changes
- Base: Common ancestor (what both started from)
- Theirs: Incoming branch changes
- Result: What you're creating (resolved version)
Aborting a Merge
If conflicts are too complex or you made a mistake, you can abort:
# Abort the merge
git merge --abort
# Your repository returns to state before merge started
# No changes lost!When to abort:
- Conflicts are more complex than expected
- You realize you merged the wrong branch
- You need to discuss approach with team first
- You want to try a different merge strategy
After aborting, you can:
- Plan a better approach
- Discuss with team
- Work on smaller, focused merges
- Use rebase instead of merge
Practice Resolving Conflicts
Use this interactive conflict resolver to practice:
Merge Conflict Resolver
Practice resolving merge conflicts
Merge conflict in app.js
Automatic merge failed. Fix conflicts and commit the result.
Conflict Markers
<<<<<<< main
function greeting() {
console.log("Hello, World!");
return "Welcome!";
}
=======
function greeting() {
console.log("Hello, Developer!");
return "Welcome to our app!";
}
>>>>>>> feature/new-uiCurrent (main)
function greeting() {
console.log("Hello, World!");
return "Welcome!";
}Incoming (feature/new-ui)
function greeting() {
console.log("Hello, Developer!");
return "Welcome to our app!";
}Your Resolution
Common Conflict Scenarios
Scenario 1: Simple Text Conflict
# Both branches changed a title
<<<<<<< HEAD
# User Guide
=======
# Getting Started Guide
>>>>>>> docs-update
# Resolution - combine both ideas:
# Getting Started - User GuideScenario 2: Code Logic Conflict
# Both branches modified validation
<<<<<<< HEAD
if (age >= 18) {
return true;
}
=======
if (age >= 21) {
return true;
}
>>>>>>> feature-age-check
# Resolution - add parameter to make it flexible:
function canAccess(age, minimumAge = 18) {
return age >= minimumAge;
}Scenario 3: Import Statement Conflicts
# Both added different imports
<<<<<<< HEAD
import React from 'react';
import { useState } from 'react';
=======
import React from 'react';
import { useEffect } from 'react';
>>>>>>> feature-effects
# Resolution - keep both:
import React from 'react';
import { useState, useEffect } from 'react';Scenario 4: Delete vs Modify Conflict
# One branch deleted file, other modified it
# Git shows:
CONFLICT (modify/delete): old-config.js deleted in feature-branch
and modified in HEAD.
# Resolution options:
# 1. Keep deletion (their side was right to remove it)
git rm old-config.js
# 2. Keep file (your changes were important)
git add old-config.jsPreventing Merge Conflicts
While conflicts are normal, you can reduce their frequency:
1. Communicate with Team
- Discuss who's working on what
- Coordinate changes to shared files
- Use separate files when possible
2. Commit and Sync Frequently
# Pull often to get latest changes
git pull origin main
# Commit small, focused changes
git commit -m "Add user validation"
# Push regularly
git push origin feature-branch3. Keep Branches Short-Lived
- Don't let feature branches drift too long
- Merge or rebase with main regularly
- Smaller PRs = fewer conflicts
4. Use Feature Flags
Instead of long-running branches, use feature flags:
// Merge incomplete features behind flags
if (featureFlags.newDashboard) {
return <NewDashboard />;
}
return <OldDashboard />;5. Modularize Code
Well-structured code has fewer conflicts:
- Small, focused files
- Clear module boundaries
- Avoid giant monolithic files
6. Agree on Formatting
Use automated formatters to prevent style conflicts:
# Use Prettier, Black, gofmt, etc.
# Configure in project:
npm install --save-dev prettier
# Add .prettierrc configuration
# Format before committing
npx prettier --write .7. Rebase Before Opening PR
# Update your branch with main before PR
git checkout main
git pull
git checkout feature-branch
git rebase main
# Resolve any conflicts now
git push --force-with-leaseπ― Pull Often, Push Often
The single best way to minimize conflicts: stay synchronized with your team. Pull before you start work, and push when you finish. The longer branches diverge, the more conflicts you'll have!
Practice Conflict Commands
Try these commands to practice identifying and working with conflicts:
Practice Conflict Resolution
Commands for handling merge conflicts
Try these examples:
Advanced Conflict Techniques
Rerere (Reuse Recorded Resolution)
Git can remember how you resolved conflicts:
# Enable rerere
git config --global rerere.enabled true
# Now Git remembers your conflict resolutions
# If same conflict appears again, it auto-resolves!Checking Conflict History
# See which commits caused conflict
git log --merge
# See what both sides changed
git log --left-right HEAD...MERGE_HEAD
# Detailed diff
git diff HEAD...MERGE_HEADMerge Strategies
# Different merge strategies for different scenarios
# Recursive (default) - most common
git merge -s recursive feature-branch
# Ours - keep our version in conflicts
git merge -s ours feature-branch
# Theirs - prefer their changes (via recursive option)
git merge -X theirs feature-branch
# Ours option - keep our changes when conflicts
git merge -X ours feature-branchCommand Reference
Here's a quick reference for handling conflicts:
# Detecting Conflicts
git status # See conflicted files
git diff # View conflict details
git log --merge # See conflicting commits
# Resolving Conflicts
# 1. Edit files manually to resolve
# 2. Remove conflict markers
git add <file> # Mark as resolved
git commit # Complete merge
# Using One Side
git checkout --ours <file> # Keep your version
git checkout --theirs <file> # Keep their version
git add <file>
# Merge Tools
git mergetool # Launch merge tool
git mergetool --tool=vimdiff # Use specific tool
# Aborting
git merge --abort # Cancel the merge
git reset --hard HEAD # Discard all changes (careful!)
# Advanced
git rerere # Manually trigger rerere
git config rerere.enabled true # Enable automatic rerere
git merge -X ours <branch> # Prefer our changes
git merge -X theirs <branch> # Prefer their changesKey Takeaways
- Conflicts occur when the same lines are changed in different branches
- Conflict markers show: <<<<<<< (yours), ======= (separator), >>>>>>> (theirs)
- To resolve: edit file, remove markers, add file, commit
- Use
git statusto see which files have conflicts git merge --abortsafely cancels a merge- Visual merge tools make resolution easier with three-way diffs
- You can accept one side completely with
--oursor--theirs - Prevent conflicts by communicating, syncing often, and keeping branches short
- Conflicts are normalβdon't panic, just work through them systematically
- Enable rerere to automatically reuse conflict resolutions
What's Next?
Excellent work! You now understand merge conflicts and can resolve them confidently. Conflicts are no longer scaryβthey're just another part of collaborative development!
In the next lesson, we'll explore Issues & Project Management. You'll learn how to use GitHub Issues to track bugs and features, organize work with labels and milestones, manage projects effectively, and coordinate team efforts. Issues are how successful teams plan and track their work on GitHub!
π― Practice Assignment
Before the next lesson, practice resolving conflicts:
- Create a test repository with two branches
- Make conflicting changes to the same file in both branches
- Merge one branch into the other
- Resolve the conflicts manually
- Try using a merge tool (like VS Code's built-in tool)
- Practice using
git checkout --oursand--theirs - Try
git merge --abortand start over
The more you practice, the more comfortable you'll become with conflicts!