Merge conflicts have an outsized reputation for being scary, mostly because the first one tends to happen before anyone's explained what the on-screen markers actually mean. Once you can read them, resolving a conflict is a mechanical, low-drama process almost every time.
Why a conflict happens
Git merges automatically whenever it can - it only stops and asks you to resolve something when it genuinely can't decide on its own, which almost always means the same lines of the same file were changed differently on the two branches being combined (or one side edited a file the other side deleted). Git is deliberately conservative here: it would rather stop and ask than silently guess wrong about which version you meant to keep.
Reading the conflict markers
When a conflict happens, Git writes both versions directly into the file, wrapped in markers:
<<<<<<< HEAD const greeting = "Hello there"; ======= const greeting = "Hi, welcome!"; >>>>>>> feature/greeting-update
Everything between <<<<<<< HEAD and the ======= divider is your current branch's version. Everything between the divider and >>>>>>> branch-name is the incoming branch's version. Git hasn't decided anything for you - it's handed you both options, in place, and is waiting for you to edit the file into what it should actually say.
The resolution process
- Run
git status- it lists every file with unresolved conflicts. - Open each conflicted file and find the marker blocks. For each one, decide: keep your version, keep the incoming version, or write something that combines both.
- Delete the
<<<<<<<,=======, and>>>>>>>lines themselves - they're not part of either version and will break your code if left in. - Save the file, then
git addit to mark that specific conflict as resolved. - Once every conflicted file is staged, finish with
git commit(for a merge) orgit rebase --continue(if the conflict came up during a rebase).
git merge --abort or git rebase --abort backs out completely and returns everything to exactly how it was before you started - there's no penalty for bailing out and trying again once you've had a closer look.Tools that make this easier
Most code editors (VS Code included) detect conflict markers automatically and show clickable "Accept Current / Accept Incoming / Accept Both" options right above each block, which is usually faster than hand-editing the markers for anything beyond a one-line conflict. git mergetool launches a dedicated three-way merge tool if you have one configured, useful for conflicts across many files at once.
Reducing how often this happens
Conflicts scale with how long branches live and how large they get before merging - a branch that's three days old and touches one file will almost never conflict; a branch that's three weeks old and touches forty files, almost certainly will. Pulling the target branch into your feature branch regularly while you work (rather than only at the very end) surfaces small conflicts early, when they're easy, instead of one large one at the end, when they're not.