They tried to teach me lots of things at Uni. If I hold my breath and squeeze really hard I'll remember how each component in an MRI machine works. Or why cells are freaking amazing. If we were being really smug we could to talk about why Rousseau was fantastically brillianter than the rest of those guys. (Yes spelling, imaginary words... whatever)
But one simple thing plagued me from the moment that I learnt emacs and git, and I just could not get my head around it. The real question for years was: How does Ediff work?
Well despite my ailment (imaginary or otherwise) I nailed it last week because of beer and jealousy. I present to you, Ediff for the brainically challenged:
disclaimer: I know that my emacs color scheme is horrifyingly kitsch.
Brains are for thinking, what's magit?
Magit is a cool wrapper around git for emacs. I've learnt to love it because hey, what's an OS other than a bootstrap loader for emacs right?
1: fire up magit and get some diffs
M-x magit-status brings up magit, navigate in the magit buffer to the file you want to use ediff with (such as a file that has a merge conflict) and press
e. That should load ediff.
2: Keep the little window highlighted
Ediff gives you a new windown to work with. This is where you give ediff commands
Make sure that it's always the focused, active window. You will rarely need to edit the ediff buffers directly (You can, but it's not always that you do).
I usually press
? to get the little window to show me all of ediffs commands. You will mostly use the "Manipulate" commands.
The white zones are places where changes exist. Those are what we're interested in. Don't fear them (I did).
3: Turn on auto-refinement
Diffs compare zones. By refining, ediff can show you exactly which parts of the zones are different.
@ to turn on auto refinement. Then press
* to refine your buffers if they haven't already.
Notice the image below. There are two buffers in the background, it's a bit busy but you'll see once you pay attention.
4: Stop, wait a minute, fill my cup put some liquor in it.
You should have noticed that we have 2 buffers of interest. Ediff will also sometimes give you 3 if there was a merge conflict (the current branch, the merging branch and the final resulting file. Here we have two. You'll see that later.
The top buffer, A, represents the version of main.css.scss at HEAD in git. It has a red region. This is a zone that was removed/changed. Inside the red zone are two bright red highlighted areas. These are the specific parts of the zone that were removed.
The bottom buffer, B, represents the version of main.css.scss that currently exists in the directory. In it's green zone are two highlighted areas, these are the specific changes/additions.
Here we want to make changes to buffer B by either copying entire zones from A, or manually editing the 'refined' zones to what we need them to be. Or we can leave things alone.
5: Manually Edit
Let's get gritty, edit buffer B by hand. You'll see that buffer B is now active and my cursor is in the highlighted, refined region. I've already changed it, see:
Now go back to the Ediff control window and press
* to refine it (auto refine only works when yo use ediff commands, not manual changes). You see it's re-refined it:
Finish off your edit:
Refining helps you check what's actually different.
6: Move on
Move to the next zone (the big white things sticking out). Press
n in the ediff window.
7: Use a keyboard macro if you want to
(I've moved the ediff window above the main emacs window here in my tiling window manager)
Now I've done the common task via
C-x e, a keyboard macro that changes image-url paths I just created. Notice the bright green? I haven't clicked
* yet to refine again.
8: Oh no I got lost somewhere!
n a bunch of times to go back/forth in zones till you find where you were at again. I said brainically challenged not null.
9: Finished File
If you got into ediff using magit, just press
q in the ediff window. That'll end your ediff session and magit will ask you if you want to save, etc.
If you got into ediff some other way, probably do
x is the buffer you want to save, it's
b here since buffer B is the one we want to keep.
10: What about copying regions?
c to copy into the buffer you're meant to be editing (
c in the case that there are 3 buffers). You'll see what I mean in a moment.
11: 3 Buffers a la Merge Conflict
You can see 3 buffers, A, B and C. The naming is misleading, pay attention
A is the Current buffer, as in what exists in the current branch that you're on. Not the current file in the directory.
B is the Merged buffer, as in what exists on the branch that you're merging in. Not the final merged version of the file.
C is the ... I can't think of it's name. It represents the actual, current (see what i mean...) file that is in the directory, not commited anywhere yet.
You want to make changes to C.
12: Press n to go to your first zone
Notice the big red block top left (application.js.current), big green one top right (application.js.merged), and the sickly green bottom middle. We want some combination of red and/or green zones to fill the yellow zone.
See how the yellow region has the variants, and is named application.js
In this case, i want my Merged file to replace my Current file. As in, the file in my current branch is bad, the file being merged in is good. Press
13: Continue as you need to
Just keep pressing
b or doing manual edits as necessary with a sprinkling of
* and you should be done in no time!
wc to save buffer c, or in this case
q to go back to magit.