Merge Conflicts & Resolution

Difficulty: Beginner

Question

How do merge conflicts happen? Walk me through resolving a conflict step by step.

Answer

Merge conflicts occur when Git cannot automatically reconcile differences between two branches. This happens when the same lines of the same file were modified differently in each branch. Git does not know which version to keep, so it pauses and asks you to resolve it manually.

Common conflict scenarios: 1. Two people edit the same line in the same file 2. One person edits a file that another person deleted 3. Both branches add different content at the same location

Git marks conflicts in the file with special markers: <<<<<<< (your changes), ======= (separator), and >>>>>>> (incoming changes). Your job is to edit the file to contain exactly what you want, remove the markers, then stage and commit.

The best strategy is to prevent conflicts by communicating with your team, keeping branches short-lived, and merging main into your feature branch frequently.

Code examples

Resolving a Merge Conflict

# Attempt to merge feature into main
git checkout main
git merge feature/auth
# Auto-merging src/app.ts
# CONFLICT (content): Merge conflict in src/app.ts
# Automatic merge failed; fix conflicts and then commit.

# Check which files have conflicts
git status
# Unmerged paths:
#   both modified:   src/app.ts

# The conflict markers in src/app.ts look like:
<<<<<<< HEAD
const port = 3000;
app.listen(port);
=======
const PORT = process.env.PORT || 8080;
app.listen(PORT);
>>>>>>> feature/auth

# Resolution: Edit the file to keep what you want
const PORT = process.env.PORT || 3000;
app.listen(PORT);
# (Removed ALL conflict markers)

# Stage the resolved file
git add src/app.ts

# Complete the merge
git commit -m "Merge feature/auth: use env PORT with fallback"

# If you want to abort the merge entirely
git merge --abort  # returns to state before merge

The key steps: identify conflicts (git status), edit files to resolve (remove markers), git add resolved files, git commit. Use git merge --abort if you want to start over.

Using Merge Tools

# Configure a merge tool
git config --global merge.tool vscode
git config --global mergetool.vscode.cmd 'code --wait $MERGED'

# Launch merge tool for conflicts
git mergetool
# Opens each conflicted file in your configured tool
# Three-way merge view:
#   LOCAL  (your branch)  |  BASE (common ancestor)  |  REMOTE (incoming)
#                          MERGED (result)

# VS Code built-in merge editor shows:
# Accept Current Change  (keep yours)
# Accept Incoming Change (keep theirs)
# Accept Both Changes    (keep both)
# Compare Changes        (side by side)

# After resolving in the tool:
git add .
git commit

# Clean up .orig backup files
git config --global mergetool.keepBackup false

# Reuse recorded resolution (rerere)
git config --global rerere.enabled true
# Git remembers how you resolved a conflict
# and auto-applies the same resolution next time

Merge tools provide a visual three-way merge. VS Code's built-in merge editor is excellent. Enable rerere to auto-resolve repeated conflicts.

Preventing and Managing Conflicts

# Strategy 1: Keep your branch up to date
git checkout feature/auth
git merge main  # or: git rebase main
# Resolving small conflicts often is easier than one big conflict

# Strategy 2: Check for conflicts before merging
git merge --no-commit --no-ff feature/auth
# Performs merge but does NOT commit
git diff --staged  # review the result
git merge --abort  # cancel if needed
# OR
git commit         # finalize if happy

# Strategy 3: Use merge strategies
git merge -X ours feature/auth    # prefer our changes on conflict
git merge -X theirs feature/auth  # prefer their changes on conflict
# WARNING: these auto-resolve, which can discard valid changes

# Rebase conflict resolution
git rebase main
# CONFLICT in src/app.ts
# Fix the file, then:
git add src/app.ts
git rebase --continue
# If multiple commits conflict, repeat for each
# To abort: git rebase --abort

# See common ancestor of two branches
git merge-base main feature/auth
# Returns the commit hash where branches diverged

Frequent small merges from main into your feature branch prevent large conflicts. Use --no-commit to preview merge results before committing.

Key points

Concepts covered

Merge Conflicts, Conflict Resolution, git mergetool, Three-Way Merge, Abort