Resolving Conflicts
Learn how to identify and resolve merge conflicts that arise during collaboration.
Resolving Conflicts
Git conflicts are inevitable in collaborative development. This tutorial will teach you how to understand, identify, and efficiently resolve merge conflicts to keep your team workflow running smoothly.
What Is a Git Conflict?
A conflict occurs when Git cannot automatically merge the changes from two branches because they modify the same lines of code in incompatible ways.
Types of Conflicts
1. Content Conflicts
Simultaneous changes to the same lines:
# Branch A modifies:
function greet() {
return "Hello World!";
}
# Branch B modifies:
function greet() {
return "Bonjour le monde!";
}
2. Rename Conflicts
# Branch A: renames file.txt to document.txt
# Branch B: modifies the contents of file.txt
# Result: Git doesn't know what to do
3. Deletion Conflicts
# Branch A: deletes file.txt
# Branch B: modifies file.txt
# Result: Delete/modify conflict
Anatomy of a Conflict
Conflict Markers
<<<<<<< HEAD
function calculateTotal(items) {
return items.reduce((sum, item) => sum + item.price, 0);
}
=======
function calculateTotal(items) {
let total = 0;
for (let item of items) {
total += item.price;
}
return total;
}
>>>>>>> feature/new-calculation
What the markers mean:
<<<<<<< HEAD: Start of your version (the current branch)=======: Separator between the two versions>>>>>>> feature/new-calculation: End of the other branch’s version
Identifying Conflicts
Diagnostic Commands
# View the state of conflicts
git status
# List files with conflicts
git diff --name-only --diff-filter=U
# View conflict details
git diff
# View conflicts with more context
git diff --conflict=diff3
Typical 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: src/calculator.js
both modified: README.md
no changes added to commit (use "git add" or "git commit -a")
Resolution Strategies
1. Manual Resolution
# 1. Identify the conflicting files
git status
# 2. Open the file and edit it manually
# Remove the <<<<<<, =======, >>>>>>> markers
# Keep the code you want
# 3. Mark as resolved
git add fichier-resolu.js
# 4. Complete the merge
git commit
2. Choosing One Complete Version
# Keep your version (HEAD)
git checkout --ours fichier.js
git add fichier.js
# Keep their version
git checkout --theirs fichier.js
git add fichier.js
# Finalize
git commit
3. Merge Tools
# Configure a merge tool
git config --global merge.tool vimdiff
# Launch the tool
git mergetool
# Other popular tools
git config --global merge.tool vscode
git config --global merge.tool kdiff3
git config --global merge.tool meld
Step-by-Step Resolution
Complete Practical Example
# Situation: Conflict during a merge
git merge feature/user-profile
# Auto-merging src/user.js
# CONFLICT (content): Merge conflict in src/user.js
# Automatic merge failed; fix conflicts and then commit the result.
# 1. Examine the conflict
git status
cat src/user.js
File contents with the conflict:
class User {
constructor(name, email) {
this.name = name;
this.email = email;
<<<<<<< HEAD
this.id = Math.random().toString(36);
this.createdAt = new Date();
=======
this.id = generateUniqueId();
this.timestamp = Date.now();
>>>>>>> feature/user-profile
}
}
# 2. Resolve the conflict (manual editing)
# Decide to combine both approaches
Resolution:
class User {
constructor(name, email) {
this.name = name;
this.email = email;
this.id = generateUniqueId(); // Use the more robust function
this.createdAt = new Date(); // Keep the Date format
this.timestamp = Date.now(); // Also add the timestamp
}
}
# 3. Mark as resolved
git add src/user.js
# 4. Verify that all conflicts are resolved
git status
# 5. Finalize the merge
git commit -m "Merge feature/user-profile
Resolved conflicts in user.js by combining both ID generation
approaches and keeping both timestamp formats for compatibility."
Resolution Tools
VS Code
VS Code provides an intuitive interface for resolving conflicts:
// settings.json
{
"git.mergeEditor": true,
"merge-conflict.autoNavigateNextConflict.enabled": true
}
Features:
- Accept Current Change: Keep your version
- Accept Incoming Change: Keep their version
- Accept Both Changes: Combine both
- Compare Changes: View the differences side by side
GitKraken
Advanced graphical interface:
- Visualization of branches and conflicts
- Built-in merge editor
- Resolution history
Command Line with vimdiff
# Configuration
git config --global merge.tool vimdiff
# Usage
git mergetool
# Navigating in vimdiff
# :diffget LOCAL - Take the local version
# :diffget REMOTE - Take the remote version
# :diffget BASE - Take the base version
Preventing Conflicts
Best Practices
-
Sync frequently
# Regularly pull in changes git fetch origin git merge origin/main -
Short-lived branches
# Avoid long-running branches # Merge small features frequently -
Team communication
# Coordinate changes to the same files # Use GitHub issues for planning -
Rebase before merging
git fetch origin git rebase origin/main # Resolve conflicts one by one git push --force-with-lease origin feature-branch
Code Organization
// Avoid conflicts by structuring your code
// Split features into separate modules
// ❌ Everything in one file
// app.js (500 lines)
// ✅ Separate modules
// auth.js
// user.js
// api.js
// utils.js
Advanced Conflicts
Conflicts During a Rebase
# Start a rebase
git rebase main
# If a conflict occurs
# 1. Resolve the conflict
# 2. Add the resolved files
git add .
# 3. Continue the rebase
git rebase --continue
# Or abort
git rebase --abort
Conflicts with cherry-pick
# Cherry-pick with a conflict
git cherry-pick abc1234
# Resolve and continue
git add .
git cherry-pick --continue
# Or abort
git cherry-pick --abort
Merge vs. Rebase Conflicts
Merge conflicts:
- Resolved all at once
- History preserved
- A merge commit is created
Rebase conflicts:
- Resolved commit by commit
- Linear history
- No merge commit
Practical Exercises
Exercise 1: Simple Conflict
# 1. Create a test repository
mkdir conflict-demo
cd conflict-demo
git init
# 2. Create an initial file
echo "function greet() {
return 'Hello';
}" > greet.js
git add greet.js
git commit -m "Initial greeting function"
# 3. Create two branches with conflicting changes
git checkout -b feature-french
echo "function greet() {
return 'Bonjour';
}" > greet.js
git add greet.js
git commit -m "Add French greeting"
git checkout main
git checkout -b feature-spanish
echo "function greet() {
return 'Hola';
}" > greet.js
git add greet.js
git commit -m "Add Spanish greeting"
# 4. Merge and resolve the conflict
git checkout main
git merge feature-french
git merge feature-spanish
# Conflict expected!
# 5. Resolve by combining the languages
echo "function greet(language = 'en') {
const greetings = {
'en': 'Hello',
'fr': 'Bonjour',
'es': 'Hola'
};
return greetings[language] || greetings['en'];
}" > greet.js
git add greet.js
git commit -m "Resolve conflict by supporting multiple languages"
Exercise 2: Complex Conflict Across Multiple Files
# 1. Create a project with multiple files
echo "# My App" > README.md
echo "const version = '1.0.0';" > version.js
echo "function add(a, b) { return a + b; }" > math.js
git add .
git commit -m "Initial project setup"
# 2. Branch A: Multiple changes
git checkout -b feature-updates
echo "# My Awesome App
Version 2.0 with new features!" > README.md
echo "const version = '2.0.0';" > version.js
echo "function add(a, b) {
if (typeof a !== 'number' || typeof b !== 'number') {
throw new Error('Invalid input');
}
return a + b;
}" > math.js
git add .
git commit -m "Update to version 2.0 with validation"
# 3. Branch B: Different changes
git checkout main
git checkout -b feature-improvements
echo "# My App
Now with better performance!" > README.md
echo "const version = '1.1.0';" > version.js
echo "function add(a, b) {
// Optimized addition
return Number(a) + Number(b);
}" > math.js
git add .
git commit -m "Performance improvements v1.1"
# 4. Merge and resolve all conflicts
git checkout main
git merge feature-updates
git merge feature-improvements
# Resolve each file individually
Team Strategies
Workflow with Minimal Conflicts
# 1. Short-lived feature branches
git checkout -b feature/small-change
# ... quick development ...
git push origin feature/small-change
# ... PR and quick merge ...
# 2. Rebase before the PR
git fetch origin
git rebase origin/main
git push --force-with-lease origin feature/small-change
# 3. Frequently merge main
git checkout feature/long-running
git merge origin/main
# Resolve conflicts as you go
Communicating About Conflicts
# Message template for a resolved conflict
## Conflict resolved in PR #123
**Affected files:**
- src/user.js
- src/auth.js
**Nature of the conflict:**
Simultaneous changes to the authentication methods
**Resolution chosen:**
Combination of both approaches:
- Keeps the validation from feature-a
- Integrates the optimization from feature-b
**Tests performed:**
- [ ] Unit tests pass
- [ ] Integration tests OK
- [ ] Manual validation
cc @team-lead @reviewer
Advanced Troubleshooting
Undoing a Conflict Resolution
# If you made a mistake during resolution
git reset --hard HEAD~1 # Undo the merge commit
git merge feature-branch # Redo the merge
Viewing Conflict History
# View previous merges
git log --merges --oneline
# View the details of a merge
git show commit-hash
# View the conflicts of a specific merge
git log --cc commit-hash
Automatic Resolution
# Configure merge strategies
git config merge.ours.driver true # Always keep our version
git config merge.theirs.driver "cp %B %A" # Always keep their version
# In .gitattributes
*.generated merge=ours
*.config merge=theirs
Additional Resources
Recommended Tools
- Beyond Compare: Professional diff/merge tool
- P4Merge: Free and effective
- Meld: Open source, cross-platform
- KDiff3: Three-way merge
Documentation
Conclusion
Conflict resolution is an essential skill for any developer working on a team. With practice and the right tools, conflicts become a normal, manageable part of the development workflow.
In the next tutorial, we’ll explore the advanced Git workflows used by professional teams.
Estimated reading time: 30 minutes
Level: Intermediate
Previous step: Collaborating with GitHub
Next step: Advanced Git Workflows