Merge conflicts without panic
A merge conflict is Git saying "two people changed the same lines, and I will not guess which one is right". It is normal, it is local to your machine, and every step is undoable. This lesson shows exactly why conflicts happen, how to read the markers, how to resolve them in VS Code, and how to make them rarer.
By the end you can
- Predict which changes conflict and which merge cleanly, using the three-way merge
- Read conflict markers, including the base section shown by
zdiff3 - Resolve a conflict in VS Code's editor or merge editor, test it, and finish the merge
- Back out with
git merge --abort, or take one side of a whole file - Handle lockfile conflicts, reduce conflicts with team habits, and parse conflict markers in code
The everyday picture
In a grocery store, the morning staff member changes the shelf tag for a 5 kg bag of rice from $5.20 to $5.30, because the distribution centre (DC) sent a new price list. In the afternoon, a second staff member, working from the festival promotion sheet, changes the same tag to $4.99. In the evening the manager finds two notes for one tag. She cannot just take the newer one. The new price list and the festival promotion might both be correct, and the right price might be a third number. Someone who understands both changes must decide.
Notice what did not need the manager. The morning staff also changed the beans tag, and the afternoon staff changed the sugar tag. Those were different tags, so both changes simply stand. Git works the same way. It combines changes to different places by itself, and stops only when two branches changed the same lines differently.
Why conflicts happen: the three-way merge
You saw in Branches and merging that a merge between two branches that have both moved compares three snapshots: the merge base (the last commit both branches share), ours (the tip of the branch you are on) and theirs (the tip of the branch you are merging in). Git works through every file and every group of lines, called a hunk, and applies one rule:
- If only one side changed a hunk compared with the base, take that side. Nobody disagrees.
- If both sides made the identical change, take it once.
- If both sides changed the same hunk in different ways, mark a conflict and stop.
The base is what makes this work. Without it, Git would only see that two files differ, and would have no idea who changed what. With it, Git knows that main changed the rounding line and the festival branch did not, so main's version must be the new one.
"Same lines" includes lines that touch. If one branch edits line 2 and the other edits line 3, with nothing unchanged in between, Git treats them as one overlapping hunk and reports a conflict. With at least one unchanged line between the two edits, the merge goes through cleanly. Git works on lines of text. It does not understand JavaScript, so it will happily combine two changes that are each fine but break the code together. That is why you always run the tests after a merge, even a clean one.
Quick check
Since the merge base, main changed line 12 of prices.js and the festival branch changed line 13, the very next line. What happens when you merge?
Git needs at least one unchanged line between two edits to keep them apart. Adjacent edits form one region that both sides changed, so Git stops and shows the whole block. Git never decides by commit time.