0%
Tutorial 7 of 10
70% complete

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.

mainfeature-afeature-bInitialModify line 5Modify line 5 differentlyCONFLICT!

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

  1. Sync frequently

    # Regularly pull in changes
    git fetch origin
    git merge origin/main
  2. Short-lived branches

    # Avoid long-running branches
    # Merge small features frequently
  3. Team communication

    # Coordinate changes to the same files
    # Use GitHub issues for planning
  4. 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

  • 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