Understanding and Resolving Conflicts
Conflicts happen when Git can't automatically merge changes. Learning to resolve them confidently is essential for team collaboration.
When Conflicts Occur
Conflicts happen when:
- Two branches modify the same line differently
- One branch deletes a file another branch modified
- Both branches add files with the same name
Git handles many situations automatically, but when it can't determine the correct result, it asks you to decide.
Anatomy of a Conflict
When a conflict occurs, Git marks the file:
1<<<<<<< HEAD2This is the content from your current branch3=======4This is the content from the branch being merged5>>>>>>> feature-branch
Marker Meanings
| Marker | Meaning |
|---|---|
<<<<<<< HEAD | Start of your current branch's version |
======= | Separator between versions |
>>>>>>> branch | End of incoming branch's version |
Three-Way Conflicts (During Rebase)
Sometimes you see three sections:
1<<<<<<< HEAD2Your changes3||||||| parent of abc1234Original content (common ancestor)5=======6Their changes7>>>>>>> abc123
The middle section shows the original, helping you understand what each side changed.
Resolution Strategies
Keep One Version
Sometimes you want to accept one side completely:
bash1# Keep your version2$ git checkout --ours file.txt34# Keep their version5$ git checkout --theirs file.txt
Manual Merge
Edit the file to combine both changes:
Before:
1<<<<<<< HEAD2function greet() {3 return "Hello!";4}5=======6function greet(name) {7 return `Hi ${name}!`;8}9>>>>>>> feature
After (manual resolution):
1function greet(name = "World") {2 return `Hello, ${name}!`;3}
Remove conflict markers and create the desired result.
Use a Merge Tool
Visual merge tools can help:
bash1$ git mergetool
Configure your preferred tool:
bash1$ git config --global merge.tool vscode2$ git config --global mergetool.vscode.cmd 'code --wait $MERGED'
Popular merge tools:
- VS Code (built-in)
- Sublime Merge
- Beyond Compare
- Meld (Linux)
- Kaleidoscope (macOS)
Conflict During Merge
bash1$ git merge feature-branch2Auto-merging app.js3CONFLICT (content): Merge conflict in app.js4Automatic merge failed; fix conflicts and then commit the result.
Resolution Steps
-
Identify conflicts:
bash1$ git status2Unmerged paths:3 both modified: app.js -
Edit conflicted files:
bash1$ vim app.js2# Remove markers, create correct content -
Stage resolutions:
bash1$ git add app.js -
Complete merge:
bash1$ git commit2# Editor opens with merge commit message
Abort Merge
If you want to start over:
bash1$ git merge --abort
Conflict During Rebase
bash1$ git rebase main2CONFLICT (content): Merge conflict in app.js3error: could not apply abc123... Add feature
Resolution Steps
-
Fix conflicts in files
-
Stage resolutions:
bash1$ git add app.js -
Continue rebase:
bash1$ git rebase --continue -
Repeat for each conflicting commit
Skip or Abort
bash1# Skip this commit (dangerous: loses changes)2$ git rebase --skip34# Cancel rebase entirely5$ git rebase --abort
Rerere: Remember Resolutions
Enable rerere to remember how you resolved conflicts:
bash1$ git config --global rerere.enabled true
Next time Git sees the same conflict, it auto-resolves:
bash1$ git rebase main2Resolved 'app.js' using previous resolution.
Review what rerere recorded:
bash1$ git rerere diff
Conflict Prevention
Stay Updated
Regularly sync with main to minimize divergence:
bash1$ git fetch origin2$ git rebase origin/main
Small, Focused Changes
Large changes = more conflict potential. Small PRs merge easier.
Communicate with Team
If you know you'll modify heavily-used files, coordinate with teammates.
Common Conflict Scenarios
Binary Files
Git can't merge binary files. Choose one:
bash1$ git checkout --ours image.png2# or3$ git checkout --theirs image.png4$ git add image.png
Deleted vs Modified
One branch deleted a file, another modified it:
bash1$ git status2deleted by them: config.json34# Keep the file5$ git add config.json67# Accept deletion8$ git rm config.json
Renamed Files
If detection fails, Git sees it as delete + create:
bash1# Check rename detection2$ git diff --name-status main3R100 old-name.js new-name.js
Key Takeaway
Conflicts are normal in collaborative development. Read the markers carefully, understand what each side changed, and create a resolution that preserves the intent of both changes. Enable rerere to avoid resolving the same conflicts repeatedly.