1. Courses
  2. Developer Foundations
  3. Git from the Inside
  4. Stop 4

35 minIntermediate

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), (the tip of the branch you are on) and (the tip of the branch you are merging in). Git works through every file and every group of lines, called a , 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 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?

base ours (main) theirs (festival) beans 1.40 beans 1.50 beans 1.40 oil 1.90 oil 1.90 oil 1.90 sugar 1.35 sugar 1.35 sugar 1.30 salt 0.40 salt 0.40 salt 0.40 rice 5.20 rice 5.30 rice 4.99 git merge result beans 1.50 ours only oil 1.90 unchanged sugar 1.30 theirs only salt 0.40 unchanged rice 5.30 or 4.99? CONFLICT both changed
Each row is one line of a price file. Beans changed only on main and sugar changed only on the festival branch, so Git takes those automatically. Rice changed on both sides in different ways, so that one line becomes a conflict. (The unchanged salt line matters: if the sugar and rice edits touched, Git would report one bigger conflict.)

Loading the rest of the lesson…