The merge editor
Intermediate VS Code UI
Why this matters
Conflicts are the moment people abandon a graphical tool and ask for help. VS Code's merge editor is genuinely good at this, and it shows the one thing the raw markers hide: what the line looked like before either side changed it.
What happens when a merge conflicts
A merge that cannot be resolved automatically leaves the repository mid-merge (Section 11). VS Code shows:
- The conflicted files under a Merge Changes section in the Source Control view.
- The conflict markers in the file, with inline actions above each block.
- A Resolve in Merge Editor button at the top of the file.
Nothing has been decided yet, and nothing is broken. The merge is paused, waiting for you.
The inline actions
Above each conflicting block, VS Code offers four CodeLens actions:
| Action | Keeps |
|---|---|
| Accept Current Change | Your branch's version |
| Accept Incoming Change | The other branch's version |
| Accept Both Changes | Both, one after the other |
| Compare Changes | Opens a diff of the two, deciding nothing |
These are enough when the answer is obvious: one side is clearly right, or both belong. They are not enough when the correct result is a sentence neither side wrote, which is common in documentation.
The merge editor
Click Resolve in Merge Editor for the three-pane view:
| Pane | Is |
|---|---|
| Incoming (left) | The version from the branch being merged in |
| Current (right) | The version on the branch you are on |
| Result (bottom) | The file that will be committed |
Each conflicting block has checkboxes in the top panes: tick one, or both, and the Result updates. The Result pane is an ordinary editor, so you can also type something neither side wrote, which is usually the right answer when two people rewrote the same sentence.
When every conflict is decided, Complete Merge stages the file and closes the editor. The file moves from Merge Changes to Staged Changes, and the merge is finished by committing.
Finishing, or escaping
| Situation | Action |
|---|---|
| All conflicts resolved | Complete Merge, then commit from the Source Control view |
| Several conflicted files | Resolve each; the merge is not done until all are staged |
| You want out | Command Palette → Git: Abort Merge |
| You want out of a rebase | Git: Abort Rebase, or the Abort action in the Source Control view |
Aborting returns you exactly to where you were (lesson 12.6). It is a perfectly respectable choice when the right resolution needs a conversation.
Reading the result before committing
After resolving, before committing, click the file under Staged Changes and read the diff. Two things go wrong at this stage and both are visible there:
- A leftover marker: a stray
<<<<<<<or=======that was not removed. The linter or the build usually catches it, embarrassingly and later. - A half-resolved sentence that reads oddly because it combines two wordings.
That check takes ten seconds and it is the difference between resolving a conflict and appearing to.
How to do it
The same conflict, in commands:
$ git status # which files are unmerged
$ git diff # the conflict, with markers
# edit the file
$ git add docs/faq.md
$ git commit # finishes the mergeTurning on the better marker style makes the terminal view much closer to the merge editor's (lesson 11.2):
$ git config --global merge.conflictstyle zdiff3- The file's inline actions: Accept Current Change, Accept Incoming Change, Accept Both Changes, Compare Changes
- Resolve in Merge Editor for the three-pane view, then Complete Merge
- Git: Abort Merge and Git: Abort Rebase in the Command Palette
- The setting
git.mergeEditorcontrols whether the merge editor opens by default
IntelliJ's three-way merge dialog shows the same three versions with the base in the middle, and it has been the reference implementation of this idea for years. See lesson 16.7.
Simple conflicts can be resolved in the browser on the merge request, with an inline editor. Anything involving judgement is better done locally, and GitLab says so, offering the commands (lesson 11.4).
The same: a web editor for simple conflicts, and instructions for resolving locally otherwise.
Common mistakes
- Assuming "Current" is always yours. During a rebase it is not.
- Accepting one side to make the conflict go away, and losing the other person's change silently.
- Leaving a marker in the file.
- Committing without reading the staged diff.
- Fixing a conflict you do not understand. Ask the other author;
git lognames them (lesson 11.6).
Try it yourself
Goal: resolve a real conflict in the merge editor.
- On your practice project, create two branches that change the same line of
docs/faq.mddifferently, and commit both. - Merge one into the other from VS Code (Git: Merge Branch…) and watch Merge Changes appear.
- Try the inline actions first: click Accept Both Changes and read the result.
- Undo that, click Resolve in Merge Editor, and this time type a third wording into the Result pane.
- Complete Merge, read the staged diff, and commit.
Expected result: one conflict resolved two ways, with a final version that says what you meant rather than what either branch happened to say.
Show solution
Step 4 is the reason the merge editor exists. Most documentation conflicts are two people improving the same sentence, and the correct resolution is neither version: it is the one you write while looking at both. The Result pane being editable is what makes that a thirty-second job.