Merge Conflicts
Merge conflicts happen when two branches change the same lines of the same file in different ways. Git cannot tell which version you want, so it pauses the merge and asks you to choose. Conflicts feel scary the first time, but the procedure is short and very reliable: open the file, pick the right content, mark the conflict resolved, and continue.
What a conflict looks like
The merge pauses
git merge feature-x # Auto-merging src/login.js # CONFLICT (content): Merge conflict in src/login.js # Automatic merge failed; fix conflicts and then commit the result.
git status confirms
git status # 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/login.js
What is inside a conflicted file
Conflict markers
function greet(name) {
<<<<<<< HEAD
return `Hello, ${name}!`;
=======
return `Hi there, ${name}.`;
>>>>>>> feature-x
}The markers mean:
<<<<<<< HEAD— start of the version from your current branch.=======— separator.>>>>>>> feature-x— end of the version from the branch you are merging in.
The resolution procedure
Open the conflicted file in your editor.
Decide what the final content should be — keep one side, combine the two, or rewrite the whole thing.
Remove all
<<<<<<<,=======, and>>>>>>>lines.Save the file.
Run
git add <file>to mark it resolved.When all conflicts are resolved:
git committo finalise the merge.
Resolution in commands
# 1. Edit src/login.js to your satisfaction (no more <<< or >>>) # 2. Mark it resolved git add src/login.js # 3. Continue the merge git commit # (Git auto-fills a merge commit message — edit if desired)
Checking what is left
git diff --name-only --diff-filter=U # Lists every file that still has conflicts # Or just: git status # Files under "both modified" still need resolving
Aborting a merge
Bail out completely
git merge --abort # Restores the repo to exactly how it was before 'git merge'
Useful when you realise the merge is going to be too painful and you want to think about it first (maybe rebase or split into smaller changes).
Resolution helpers
Pick a whole side
# Take the version from the current branch (HEAD) git checkout --ours src/login.js # Take the version from the incoming branch git checkout --theirs src/login.js # Then mark resolved git add src/login.js
Using a merge tool
Launch the configured visual merge tool
git mergetool # Opens a side-by-side diff for each conflicted file # Choose hunks, save, and the tool marks them resolved
Verifying before you commit
# Make sure no markers slipped through git diff --check # Reports any remaining conflict markers # Run your tests! Conflicts that compile are still wrong if behaviour broke.
Why conflicts happen — common patterns
Both branches edited the same function — most common, especially in long-running feature branches.
Lockfiles (
package-lock.json,yarn.lock,Gemfile.lock) — easiest to regenerate: pick--theirsor--ours, then re-run the install command.Both branches renamed the same file differently — Git flags both and asks you to pick.
Both branches deleted the same file differently — a “delete/modify” conflict.
Reducing conflict pain
Keep feature branches short-lived — fewer divergent commits, fewer conflicts.
Rebase or merge
maininto your branch frequently so conflicts surface in small batches.Coordinate large refactors so two people are not editing the same files simultaneously.
Turn on
git config --global rerere.enabled true— Git will remember your conflict resolutions and replay them automatically next time.