Handling Merge Conflicts
A merge conflict occurs when Git can’t automatically combine changes because two people have edited the same part of a file in different ways.
Conflicts happen when:
- You and a colleague both modify the same line of code
- One person edits a line while another deletes it
- Changes are made in overlapping sections of a file
Importantly, conflicts do not occur when:
- Changes are in different files
- Changes are in different parts of the same file
- One person’s changes come entirely before or after another’s
Example Scenario
You and your colleague both create branches from main:
main: A -- B -- C
\
\-- D (your branch: change line 5)
\
\-- E (colleague's branch: change line 5)
Your colleague merges first. When you try to merge, Git sees:
- Main now has E (colleague’s version of line 5)
- Your branch has D (your version of line 5)
- Git doesn’t know which to keep, so it asks you to decide
What Conflicts Look Like
When you encounter a conflict, Git marks the conflicting section in your file:
def calculate_total(items):
<<<<<<< HEAD
# Current branch version
total = sum(item.price * 1.2 for item in items) # With 20% tax
=======
# Incoming branch version
total = sum(item.price * 1.15 for item in items) # With 15% tax
>>>>>>> feature/update-tax-calculation
return totalThe markers mean:
<<<<<<< HEAD: Start of your current branch’s version=======: Divider between the two versions>>>>>>> branch-name: End of the incoming branch’s version
Resolving Conflicts
When you encounter a merge conflict, follow these steps to resolve it:
Step 1: Identify the Conflicts
After attempting a merge, Git will tell you which files have conflicts:
$ git merge feature/update-tax-calculation
Auto-merging calculator.py
CONFLICT (content): Merge conflict in calculator.py
Automatic merge failed; fix conflicts and then commit the result.You can see all conflicted files with:
$ git statusFiles with conflicts will be listed under “Unmerged paths.”
Step 2: Open and Edit the Conflicted Files
Open each conflicted file in your editor. You’ll see the conflict markers as shown earlier. Your job is to:
- Decide which version to keep (yours, theirs, or a combination)
- Remove the conflict markers (
<<<<<<<,=======,>>>>>>>) - Keep only the final code you want
Option A: Keep your version
def calculate_total(items):
total = sum(item.price * 1.2 for item in items) # With 20% tax
return totalOption B: Keep their version
def calculate_total(items):
total = sum(item.price * 1.15 for item in items) # With 15% tax
return totalOption C: Combine both (if it makes sense)
def calculate_total(items, tax_rate=0.15):
total = sum(item.price * (1 + tax_rate) for item in items)
return totalStep 3: Mark as Resolved
After editing the file and removing all conflict markers, stage it:
$ git add calculator.pyThis tells Git that you’ve resolved the conflict in that file.
Step 4: Complete the Merge
Once all conflicts are resolved and staged, complete the merge with:
$ git commitGit will open your editor with a pre-filled commit message. You can modify it to explain how you resolved the conflicts, then save and close.
Best Practices for Conflict Resolution
- Test your code after resolving conflicts to ensure it works correctly
- Communicate with your team if you’re unsure which version to keep
- Review the full context by looking at both branches, not just the conflicted lines
- Use
git diffto see what changed in each branch before making decisions - Don’t rush — conflicts often reveal important differences in approach
Aborting a Merge
If you want to cancel the merge and start over:
$ git merge --abortThis returns your repository to the state before you attempted the merge.
This section provides practical, step-by-step guidance while maintaining the instructional tone of your existing content. Would you like me to adjust anything or add more detail to any particular step?
3.2 Exercise 2: Creating and Resolving Conflicts (15 minutes)
Let’s intentionally create a conflict to practice resolving it.
Part A: Creating a Conflict
Setup: Work with a partner, or simulate two developers by using two different branches yourself.
Person A (or Branch 1):
git checkout main
git pull origin main
git checkout -b feature/update-multiply-docstring
# Edit calc_lib.py - update the multiply function's docstringChange the multiply function docstring to:
def multiply(a, b):
"""
Multiply two numbers together.
Args:
a (float): First multiplicand
b (float): Second multiplicand
Returns:
float: The product of a and b
"""
return a * bgit add calc_lib.py
git commit -m "Improve multiply function documentation"
git push origin feature/update-multiply-docstringCreate a Pull Request and merge it.
Person B (or Branch 2):
git checkout main
git pull origin main
git checkout -b feature/enhance-multiply-docstring
# Edit calc_lib.py - update the same multiply function's docstring differentlyChange the multiply function docstring to:
def multiply(a, b):
"""
Calculate the product of two numbers.
Parameters:
a (float): The first number
b (float): The second number
Returns:
float: a multiplied by b
Example:
>>> multiply(4, 5)
20
"""
return a * bgit add calc_lib.py
git commit -m "Add example to multiply function documentation"
git push origin feature/enhance-multiply-docstringCreate a Pull Request. GitHub will indicate there’s a conflict!
Part B: Resolving the Conflict
When GitHub shows a conflict, you have two options:
- Resolve on GitHub (web interface): Good for simple conflicts
- Resolve locally (command line): Better for complex conflicts
Let’s resolve it locally:
# Make sure you're on your feature branch
git checkout feature/enhance-multiply-docstring
# Pull the latest main which now contains the merged changes
git pull origin mainGit will report a conflict:
Auto-merging calc_lib.py
CONFLICT (content): Merge conflict in calc_lib.py
Automatic merge failed; fix conflicts and then commit the result.
Step 1: Check which files have conflicts
git statusYou’ll see:
Unmerged paths:
both modified: calc_lib.py
Step 2: Open the conflicting file
Open calc_lib.py in your editor. You’ll see:
def multiply(a, b):
<<<<<<< HEAD
"""
Calculate the product of two numbers.
Parameters:
a (float): The first number
b (float): The second number
Returns:
float: a multiplied by b
Example:
>>> multiply(4, 5)
20
"""
=======
"""
Multiply two numbers together.
Args:
a (float): First multiplicand
b (float): Second multiplicand
Returns:
float: The product of a and b
"""
>>>>>>> main
return a * bStep 3: Decide what to keep
You have three options: 1. Keep your version (HEAD) 2. Keep their version (main) 3. Combine both (usually best!)
Let’s combine the best of both:
def multiply(a, b):
"""
Multiply two numbers together.
Args:
a (float): First multiplicand
b (float): Second multiplicand
Returns:
float: The product of a and b
Example:
>>> multiply(4, 5)
20
"""
return a * bRemove all conflict markers (<<<<<<<, =======, >>>>>>>).
Step 4: Mark the conflict as resolved
git add calc_lib.pyStep 5: Complete the merge
git commit -m "Merge main and resolve docstring conflict
Combined both documentation improvements:
- Kept clear docstring from main
- Added example from feature branch"Step 6: Push the resolved changes
git push origin feature/enhance-multiply-docstringYour Pull Request now shows no conflicts and can be merged!
3.3 Strategies to Minimise Conflicts (5 minutes)
While conflicts are normal, you can reduce their frequency:
1. Communicate with Your Team
- Discuss who’s working on what
- Avoid multiple people editing the same files simultaneously
- Use project management tools to track work
2. Keep Pull Requests Small
- Smaller changes = fewer conflicts
- Merge frequently rather than letting branches grow stale
3. Pull from Main Regularly
# While on your feature branch
git pull origin mainThis keeps your branch up to date and surfaces conflicts early when they’re easier to resolve.
4. Structure Code to Reduce Overlap
- Modular code with clear boundaries
- Each function/class in its own file when reasonable
- Avoid giant files that everyone needs to edit
5. Use Feature Flags
For long-running features, merge incomplete work behind a feature flag:
ENABLE_NEW_FEATURE = False
if ENABLE_NEW_FEATURE:
# New code path
else:
# Existing code pathThis allows you to merge regularly without activating incomplete features.