Lesson 5 of 30
What actually triggers a conflict, how to read the markers Git drops into your file, and how to get out cleanly — including bailing out entirely.
18 min read
Every option explains itself — why the right one is right, and why each wrong one is wrong. Miss one and it comes back later on a spaced-repetition schedule.
This topic is about judgment and practical tradeoffs more than a single right answer — a mock interview is the better way to test yourself on it.
Be interviewed on this →Hints without spoilers, and a plain explanation of why a wrong answer was wrong — answered only from this lesson. Free account, no card.
Sign up freeWhat interviewers actually ask about this, and what a strong answer has to cover.
A strong answer covers
Likely follow-ups
A merge conflict happens when Git tries to combine two branches and finds the same region of the same file changed differently on each side, with no way to pick a winner automatically. Git is good at auto-merging when changes touch different lines or different files — it only stops and asks you when it genuinely can't tell which version is "right."
When that happens, Git doesn't fail the merge and roll everything back. It pauses mid-merge, writes both versions directly into the conflicted file using conflict markers, and leaves it to you to decide what the final content should be. The merge is left in an unfinished state — git status will keep reminding you until you resolve every conflicted file and commit.
Say main and feature/rate-limit both touched the same line in a config file, independently.
$ git checkout main
$ git merge feature/rate-limit
Auto-merging config.js
CONFLICT (content): Merge conflict in config.js
Automatic merge failed; fix conflicts and then commit the result.
Open config.js and Git has inserted markers right at the disputed line:
const RATE_LIMIT = {
<<<<<<< HEAD
requestsPerMinute: 100,
=======
requestsPerMinute: 250,
>>>>>>> feature/rate-limit
windowMs: 60000,
};
Read this literally: everything between <<<<<<< HEAD and ======= is what's currently on your branch (main). Everything between ======= and >>>>>>> feature/rate-limit is what's coming in from the branch you're merging. Nothing here is a suggestion — both versions are real content that existed on their respective branches; Git just can't decide which one you want.
git status mid-conflict tells you exactly what's unresolved:
$ git status
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: config.js
Resolve by hand — decide the real value, delete all three marker lines, save:
const RATE_LIMIT = {
requestsPerMinute: 250,
windowMs: 60000,
};
Then stage it and finish the merge exactly like a normal commit:
$ git add config.js
$ git status
All conflicts fixed but you are still merging.
(use "git commit" to conclude merge)
$ git commit
Merge branch 'feature/rate-limit'
git add on a conflicted file means something slightly different here than usual — it's telling Git "this file's conflict is resolved," not just "stage the current content." No new message is required; Git pre-fills a merge commit message naming both branches.
If halfway through you realize this merge is the wrong call entirely — wrong branch, wrong time, need to go talk to someone first — back out completely:
$ git merge --abort
That resets the working directory and staging area back to exactly how they looked before the merge started, as if you'd never run it. It only works while the merge is still unresolved — once you commit, --abort isn't available anymore.
main and feature both edited line 2 of calc.js, independently, after splitting from the same commit.
<<<<<<<, =======, and >>>>>>> are not comments Git will strip later — if you git add and commit the file with the markers still in it, they become permanent, real content in the codebase.git merge --abort only works mid-conflict. Once the merge commit is made, undoing it means git revert (adds a new commit undoing the change) or git reset (rewrites history) — not --abort, which needs an unfinished merge to abort.A merge conflict is fundamentally a three-way diff — common ancestor, your side, their side — the same structure behind any collaborative-editing conflict resolution (Google Docs, CRDTs, database merge replication). Git just surfaces that three-way comparison as plain text markers instead of hiding it behind a UI.