How to Survive and Even Enjoy Merge Conflicts with vimdiff
The Only ~10 Commands You Need to Escape Alive
The Moment of Crisis
You type:
git merge featureGit stares back at you and mutters:
CONFLICT (content): Merge conflict in hello.txt
Automatic merge failed; fix conflicts and then commit the result.Normally, you might open hello.txt in nano or Emacs, delete the conflict markers (<<<<<<<, =======, >>>>>>>), and patch things together. But let’s say your environment is wired to use vimdiff as the merge tool.
You sigh, mutter something unrepeatable about Vim, and type:
git mergetoolAnd suddenly your terminal splits into three or four panes. Welcome to vimdiff.
What You’re Looking At
- Left pane: YOUR branch (OURS).
- Right pane: The other branch (THEIRS).
- Bottom (or middle): The MERGED buffer — this is the version you’ll actually commit.
The colored highlights show where the conflicts live. At first, it looks like a modern art piece. Don’t panic.
The Workflow, Step by Step
Step 1: Move Between Panes
Think of it as a tiling window manager. To move around, prefix with Ctrl-w:
- left →
Ctrl-w h - right →
Ctrl-w l - down/up →
Ctrl-w j/Ctrl-w k
Your main focus is the MERGED pane, because that’s where your edits live.
Step 2: Look at the Conflict
Let’s say the conflict is this line:
- OURS says:
This line is **super important**.- THEIRS says:
This line is not that important, actually.In the MERGED pane you’ll see markers if you haven’t started resolving:
<<<<<<<
This line is **super important**.
=======
This line is not that important, actually.
>>>>>>>Step 3: Decide How to Resolve
Option A: Just Take One Side
If you like OURS, type in the MERGED pane:
:diffget LOCALIf you prefer THEIRS:
:diffget REMOTEShortcut versions exist (:diffget 2, :diffget 3) depending on window order, but LOCAL/REMOTE is safer.
Option B: Edit by Hand
Sometimes neither version is quite right. That’s when you channel your inner text surgeon:
- enter insert mode, type what you want →
i - back to normal mode →
Esc - delete a whole line (great for nuking those <<<<<<< markers) →
dd - undo last action →
u - redo →
Ctrl-r
You stitch together the best of both worlds:
This line is important (and here’s why).Step 4: Save Your Work
Once the MERGED pane looks the way you want:
:wqBack in the shell:
git add hello.txt
git commitConflict resolved.
Why Use vimdiff at All?
You might be wondering: why bother with this fancy terminal acrobatics when you could just hack away in nano or Emacs?
- Clarity: You see OURS and THEIRS side by side. Much harder to lose track.
- Precision: With
:diffgetyou can pull in exactly the hunk you want. - Speed: Once you learn the half-dozen survival commands, you’ll resolve conflicts faster than scrolling around raw conflict markers.
It’s like learning to drive stick shift: painful for the first half-hour, but then you feel a strange sense of control.
Example Sessions
To get more familiar with the usage, let's look at the usage in example sessions.
1) Manual edit: example session (step-by-step)
The conflicted file looks like this when opened (via
git mergetool --tool=vimdiff)
Hello world!
<<<<<<< HEAD
This line is **super important**.
=======
This line is not that important, actually.
>>>>>>> feature
Goodbye.Goal
Keep the strong phrasing, but soften it slightly, and of course remove the conflict markers.
Session flow in vimdiff
- Move to the MERGED buffer (usually the bottom or the leftmost pane)
- Use window moves if needed:
Ctrl-w h/j/k/l.
- Jump to the conflict block
- next conflict block →
]c - previous conflict block →
[c
- Enter insert mode to edit
- Put cursor on the line you want to change.
- enter insert mode (type normally) →
i - Example edit: change
This line is **super important**.- to
This line is important (and here’s why).- Delete lines you don’t want (incl. markers)
- Press
Esc(leave insert mode). - On a marker line like
<<<<<<< HEAD, delete the whole line:dd - Do the same for
=======and>>>>>>>feature lines:ddon each. - Also delete the unwanted alternative line (e.g. “not that important”): move to it and
dd.
- Clean up whitespace / join lines if needed
- delete one character under cursor →
x - join the current line with the next →
J - undo the last change (use liberally if you slip!) →
u - redo →
Ctrl-r
- Save and quit
:wq(write + quit)- Back in shell:
git add <file>and continue your merge/commit.
Resulting file after your manual edit:
Hello world!
This line is important (and here’s why).
Goodbye.2) Vim manual-edit cheat sheet (merge-conflict edition)
Pane movement (vimdiff)
move between left/right/down/up panes Ctrl-w h/l/j/k
jump to next conflict ]c
jump to previous conflict [cModes
insert mode (type text) i
back to normal mode EscSave / quit
write (save) :w
write and quit :wq
quit discarding changes :q!Line & text edits
delete (cut) current line dd
delete character under cursor x
replace single character with <char> r <char>
join current line with next J
undo u
redo Ctrl-rCopy/paste (yank/put)
yank (copy) current line yy
put (paste) after cursor/line p
put (paste) before cursor/line PSearch & replace (handy in conflicts)
search for next conflict start /<<<<<<<
next match n
previous match N
remove all separators (example) :%s/=======//g
remove markers (example) :%s/<<<<<<<\|>>>>>>>//g (Use the search-and-replace examples carefully; it’s often safer to edit per block.)
Selecting blocks (if you prefer visual edits)
start character-wise selection v
start line-wise selection V
delete selection d
yank selection yDiff-specific quick picks (optional, if parts are fine)
take OURS for current hunk :diffget LOCAL
take THEIRS for current hunk :diffget REMOTE
recompute diffs after manual edits :diffupdateMinimal mental model
- Get to the MERGED pane → fix the text you want → delete the conflict markers (
<<<<<<<,=======,>>>>>>>) → save (:wq) →git add→ continue. - If you mess up: undo (
u) and try again. - Use
]c/[cto hop conflict to conflict, andddto delete bad/marker lines.
The Minimal Cheat Sheet
Stick this on your desk until muscle memory kicks in:
move between panes Ctrl-w h/l/j/k
jump to next/prev conflict ]c / [c
take OURS (your branch) :diffget LOCAL
take THEIRS (incoming branch) :diffget REMOTE
insert mode for manual edits i
exit insert mode Esc
delete current line / char dd / x
undo / redo u / Ctrl-r
save / save + quit / quit :w / :wq / :q!When to Actually Use It
Use vimdiff when:
- Both sides rewrote the same code and you need to carefully compare.
- You’re tired of juggling conflict markers by hand.
- You want a quick, reliable way to choose OURS or THEIRS without mistakes.
If it’s just a trivial conflict, nano or Emacs is fine. But if the conflict is messy — vimdiff is your best terminal-only scalpel.
And there you are. An Emacs user, forced into Vim, who walks out not only alive but victorious. You may never love Vim, but the next time Git drags you into vimdiff, you’ll know exactly what to do — calmly, directly, efficiently.
vimdiff Merge Conflict Survival Card
|
Explanation |
Command |
! |
|---|---|---|
|
Launch vimdiff merge after conflict |
git mergetool --tool=vimdiff |
Start here |
|
Move to left / right / up / down window |
Ctrl-w h / l / k / j |
Navigate panes |
|
Jump to next / previous conflict |
]c / [c |
Quick conflict travel |
|
Take OURS (your branch) |
:diffget LOCAL |
Keep your version |
|
Take THEIRS (incoming branch) |
:diffget REMOTE |
Keep their version |
|
Take left / right pane explicitly |
:diffget 2 / :diffget 3 |
If LOCAL/REMOTE unclear |
|
Enter insert mode (manual edit) |
i |
Start typing |
|
Exit insert mode |
Esc |
Return to normal mode |
|
Delete current line |
dd |
Remove markers or unwanted lines |
|
Delete character under cursor |
x |
Fine-grained cleanup |
|
Undo last change |
u |
Safety net |
|
Redo undone change |
Ctrl-r |
Double safety |
|
Join current line with next |
J |
Merge lines |
|
Yank (copy) current line |
yy |
Copy text |
|
Paste after cursor |
p |
Paste text |
|
Save changes |
:w |
Write buffer |
|
Save and quit |
:wq |
Done editing |
|
Quit without saving |
:q! |
Abort changes |
|
Recompute diffs after edits |
:diffupdate |
Refresh highlighting |
With just this card, you can walk into a vimdiff conflict cold and walk out with a clean merge.Do you like this kind of thinking?
- Follow me on Medium: @gwangjinkim for deep dives on Python, Lisp, system design, and developer thinking, and much more
- Subscribe on Substack: gwangjinkim.substack.com — coming soon with early essays, experiments & newsletters (just getting started).
- Visit my Ghost blog (here): everyhub.org — with hands-on tech tutorials and tools (most of them I cross-post here in medium, but not all of them).
Follow anywhere that fits your style — or all three if you want front-row seats to what’s coming next.