Merge conflicts are inevitable in team development. Two developers edit the same file, and Git doesn't know whose changes to keep. The conflict isn't a failure—it's Git asking for your help. In this lesson, you'll learn to resolve conflicts confidently and prevent them with better practices.
1. Learning Objectives
By the end of this lesson, you will be able to:
- Understand what causes merge conflicts
- Read Git's conflict markers (
<<<<<<<,=======,>>>>>>>) - Resolve conflicts manually in any editor
- Use merge tools like
meldand VS Code - Apply conflict resolution strategies
- Prevent conflicts with better practices
2. Why This Matters
Real-world scenario: Two developers modify the same function on different branches. Git can't decide which version is correct. The merge pauses, showing conflict markers. Your job is to combine both changes or choose one. Without conflict resolution skills, you'll be stuck. With them, you'll resolve in minutes.
3. Core Concepts
What Causes Merge Conflicts?
Creating a Test Conflict
# Create a repository with a conflict
mkdir conflict-lab
cd conflict-lab
git init
# Create base file
echo "Line 1" > file.txt
echo "Line 2" >> file.txt
echo "Line 3" >> file.txt
git add .
git commit -m "Initial commit"
# Create branch 'feature-a'
git checkout -b feature-a
# Modify line 2
sed -i '2s/Line 2/Line 2 - Feature A/' file.txt
git commit -am "Feature A: Update line 2"
# Create branch 'feature-b' from main
git checkout main
git checkout -b feature-b
# Modify same line differently
sed -i '2s/Line 2/Line 2 - Feature B/' file.txt
git commit -am "Feature B: Update line 2"
# Try to merge feature-a into feature-b (CONFLICT!)
git merge feature-a
Creating a test conflict scenario
kubectl get pods -w
$ git merge feature-a
Auto-merging file.txt
CONFLICT (content): Merge conflict in file.txt
Automatic merge failed; fix conflicts and then commit the result.
$ git status
On branch feature-b
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: file.txt
Git detects a merge conflict
Understanding Conflict Markers
# file.txt with conflict markers
Line 1
<<<<<<< HEAD
Line 2 - Feature B
=======
Line 2 - Feature A
>>>>>>> feature-a
Line 3
# Marker meanings:
# <<<<<<< HEAD - Start of current branch's version
# ======= - Separator between versions
# >>>>>>> feature-a - End of incoming branch's version
Conflict marker anatomy
Manual Conflict Resolution
# Step 1: Open conflicted file
nano file.txt
# Step 2: Decide resolution
# Option A: Keep HEAD version
Line 1
Line 2 - Feature B
Line 3
# Option B: Keep feature-a version
Line 1
Line 2 - Feature A
Line 3
# Option C: Combine both
Line 1
Line 2 - Feature B (from HEAD) and Feature A (from feature-a)
Line 3
# Step 3: Remove conflict markers and save
# Step 4: Mark as resolved
git add file.txt
# Step 5: Commit merge
git commit -m "Merge feature-a: resolved conflict in line 2"
Manual conflict resolution steps
Using Merge Tools
# Install meld (Linux)
sudo apt install meld
# Install kdiff3 (cross-platform)
sudo apt install kdiff3
# Set merge tool
git config --global merge.tool meld
# Or use VS Code
git config --global merge.tool vscode
git config --global mergetool.vscode.cmd 'code --wait $MERGED'
# Launch merge tool
git mergetool
# After resolving in tool, save and close
# Git will automatically stage resolved files
Using visual merge tools
Conflict Resolution Strategies
# Strategy 1: Always take one side
git checkout --ours file.txt # Keep current branch version
git checkout --theirs file.txt # Keep incoming branch version
git add file.txt
# Strategy 2: Use merge strategies
git merge -X ours feature-branch # Auto-resolve conflicts using ours
git merge -X theirs feature-branch # Auto-resolve conflicts using theirs
# Strategy 3: Interactive resolution
git mergetool # Launch configured merge tool
# Strategy 4: Abort and try different approach
git merge --abort # Cancel merge
git rebase feature-branch # Try rebase instead
Different resolution strategies
Advanced: git rerere (Reuse Recorded Resolution)
# Enable rerere
git config --global rerere.enabled true
# Now Git remembers how you resolved conflicts
# Next time the same conflict occurs, it resolves automatically
# Check rerere status
git rerere status
# See recorded resolutions
git rerere diff
# Clear recorded resolutions
git rerere forget file.txt
git rerere - learn from past resolutions
Complex Conflict Scenarios
# Scenario 1: Deleted vs Modified
# One branch deletes file, another modifies it
git status
# deleted by us: file.txt
# modified by them: file.txt
# Resolution options:
git rm file.txt # Accept deletion
git add file.txt # Keep the file
# Scenario 2: Binary files (images, PDFs)
# Git can't merge binary files automatically
git checkout --ours image.png # Keep our version
git checkout --theirs image.png # Keep their version
# Scenario 3: Rename conflicts
git mv oldname.txt newname.txt
# After merge, resolve with:
git add oldname.txt newname.txt
Special conflict scenarios
4. Complete Project: Conflict Resolution Practice
#!/bin/bash
# conflict_practice.sh - Interactive conflict resolution training
echo "=== Git Conflict Resolution Lab ==="
# Setup
export LAB_DIR="$HOME/git-conflict-lab"
mkdir -p "$LAB_DIR"
cd "$LAB_DIR"
# Clean previous
git init
# Create base application
echo '{
"version": "1.0.0",
"database": {
"host": "localhost",
"port": 5432,
"name": "myapp"
},
"redis": {
"host": "localhost",
"port": 6379
}
}' > config.json
echo 'def calculate_total(items):
"""Calculate total price of items"""
total = 0
for item in items:
total += item.price
return total' > cart.py
git add .
git commit -m "Initial commit: basic app structure"
echo ""
echo "Scenario 1: Both modify same lines"
echo "================================"
echo "Team A adds tax calculation, Team B adds discount"
# Team A branch
git checkout -b team-a/tax
echo 'def calculate_total(items):
"""Calculate total price of items with tax"""
total = 0
for item in items:
total += item.price
total = total * 1.1 # Add 10% tax
return total' > cart.py
git commit -am "Team A: Add tax calculation"
# Team B branch (from main)
git checkout main
git checkout -b team-b/discount
echo 'def calculate_total(items):
"""Calculate total price of items with discount"""
total = 0
for item in items:
total += item.price
if total > 100:
total = total * 0.9 # 10% discount
return total' > cart.py
git commit -am "Team B: Add discount logic"
# Try to merge (creates conflict)
git merge team-a/tax 2>/dev/null || echo "✓ CONFLICT created!"
echo ""
echo "Now resolve the conflict by combining both features:"
echo "- Add both tax AND discount logic"
echo "- Apply discount first, then tax"
echo ""
echo "After resolving: git add cart.py && git commit"
# Provide solution
echo ""
echo "Suggested resolution:"
echo 'def calculate_total(items):
"""Calculate total price with tax and discount"""
total = 0
for item in items:
total += item.price
if total > 100:
total = total * 0.9 # 10% discount
total = total * 1.1 # 10% tax
return total'
echo ""
echo "Practice with more scenarios:"
echo "1. Create your own conflicts"
echo "2. Use git mergetool"
echo "3. Practice with git rerere"
Interactive conflict resolution practice lab
5. Preventing Conflicts
# Best practices to avoid conflicts
# 1. Pull frequently
git pull --rebase origin main # Before starting work
# 2. Keep branches short-lived (hours, not days)
# 3. Communicate with team about file changes
# 4. Use code ownership (CODEOWNERS file)
# GitHub CODEOWNERS example
# .github/CODEOWNERS
# /config.json @devops-team
# /cart.py @backend-team
# 5. Smaller commits are better
# 6. Use different directories for different features
# 7. Automate formatting to avoid whitespace conflicts
# Pre-commit hook for consistent formatting
cat > .git/hooks/pre-commit << 'EOF'
#!/bin/bash
# Auto-format Python files before commit
black .
git add .
EOF
chmod +x .git/hooks/pre-commit
Conflict prevention strategies
6. Common Errors & Solutions
7. Summary Checklist
8. Next Steps
Next lesson: Git Lesson 3.5: Advanced Git (Rebase, Cherry-pick, Reflog)
You'll learn to:
- Rewrite history with interactive rebase
- Selectively apply commits with cherry-pick
- Recover lost commits with reflog
- Clean up messy history
Comments (0)
This is exactly what I needed! The initContainer approach solved our migration issues completely. Thanks for the detailed guide!
ReplyLeave a Comment