It is. I've got a Emacs setup to show 3-ways merge in ediff which differs from the default. I show, side by side, three columns: "variant A", "common ancestor", "variant B" and then, below, the result.
I do really enjoy my wide screen while doing that. I'm literally moving to a 360 columns mode when I do that: 120 columns for each of variant A, common ancestor and variant B. It's the only time I make Emacs that wide.
I like to have the common ancestor in the middle, so I can quickly see where both "variant A" and "variant B" are coming from.
So I'm using Emacs's ediff to do 3-ways merge while showing four versions of the code.
That’s really cool. As an aside I’m convinced there’s no such thing as too much screen space for any kind of cognitive work. Letting the optic nerve offload work from your short term memory is a huge gain.
I’ll still occasionally print out source and lay it out on a table to annotate by hand when I’m learning a complex code base.
> I’ll still occasionally print out source and lay it out on a table to annotate by hand when I’m learning a complex code base.
I've got fond memories of printing programs on continuous form paper (the one with holes on the side that the printer would use to advance the paper) and then reading it to find my bug(s) : )
I basically just slightly modified the code in ediff-setup-windows-plain-merge from ediff-wind.el.
Not too sure how to paste code on HN, here's the modified version which works for me. The orginal ediff-setup-windows-plain-merge may depend on your Emacs version though, so buyer beware (things may have changed and need to be revisited).
Instead of showing:
A B
C D
Ediff control panel
I show:
A B C
D
Ediff control panel
As for Git AFAICT all I have is git config --global merge.conflictStyle diff3.
Compare it to your version of ediff-setup-windows-plain-merge to see what I changed:
The problem with 3-way merge (when it comes to rebasing and merging at least) is that you lose all the information about why "theirs" changed.
You made a modification to the code. They made a conflicting modification. You want to know what they hell they were doing so you know how to rejig your edit. The normal tool to use here would be `git blame` but that just doesn't work. At least in any tool I have used.
If anyone knows of one where it does work I'd love to know!
When I'm confused by a 3-way diff (I personally prefer FileMerge/opendiff on macOS) and need more info I like to use git log to examine the relevant commits using the "..." operator which returns the symmetric difference between two commits (in this case both sides of the merge) and their merge base:
Another trick is doing multiple merges which each include fewer commits. Sometimes the problem is that you're just trying to merge too much at a time. The downside of this is that in files with a lot of churn you may have to deal with conflicts that you might otherwise not. So it's a bit of a two-edged sword.
The new 3 way merge editor in VS Code tries to load the documents for base, yours and theirs from the corresponding commit URI, so that extensions such as gitlens can show the line history for each document - they don't even have to know about the merge editor.
(disclaimer - I work on VS Code and its 3 way merge editor)
I really hate that relative terminology. Call them "working copy", "merging commit" and "common ancestor" or something similarly absolute. And give me the revision/commit id's for each, so it's crystal clear in case I want to check up manually.
Not a dig on the vscode extension, but 3-way diff tools in general.
Yeah I 100% agree. Especially as Git gets it backwards in some cases! It's not even consistent about the names. Sometime I see "current" and "incoming" which is not really any better.
> And give me the revision/commit id's for each
It could show the branch names! `change on master`, `change on myfeature` or whatever.
diff3 is the way to go. When there are not trivial changes, it is hard to resolve conflicts if you do not know where the conflicting changes come from.
I knew quite a few people that do not know that this option even exists. In my opinion it could make the life of engineers a lot better if this was the default.
Then, at least for VCS, there are Darcs and Pijul, which use a theory of patches.
So Pijul manages to have lossless merges by actually storing a directed graph (though of course, you will still need to decide how to flatten that into a displayed file) :
The diff listings are a bit confusing because the line numbers look like they're part of the text. For example in the first diff, '2. salmon 3. tomatoes' is right next to '4. salmon 5. tomatoes' but those aren't highlighted as a change.
You actually need four panels; common ancestor, yours, theirs, and finally the merge-result.
This is how Kdiff3 and Beyond compare does it and it is far superior to just having three panels.
A lot of other tools leave out the base or combine it with the result-panel, making it very hard to see what has changed from each side once you start resolving conflicts.
I think there's a terminology confusion here. I call kdiff3 and BC a three-panel display, because it shows the original and the two changed versions as three panels next to each other. Since the result is shown separately below, I don't include it in the panel count. I only realized that strictly speaking you could also count it as a panel from your post.
> The central pane is a fully-functional editor where the results of resolving conflicts are displayed. Initially, the contents of this pane are the same as the base revision of the file, that is, the revision from which both conflicting versions are derived.
Araxis Merge has been my go-to merge tool for 15 years. Everyone I work with pretty much uses either Araxis or Beyond Compare. BC has some nice features, but I've always found the Araxis UI easier to use.
It'd be nice if there was a good, free merge tool. But so far every one I've tried is inferior. And companies are usually happy to pay for a productivity tool as critical as merge tools.
I've found Meld pretty good for free, but I only use it for hobby stuff so I've never needed to try out the 3-way aspect. But for side-by-side folder and file diffs I've found it decent enough relative to Araxis. And, like Araxis, both sides are editable, something not all diff tools get right. So you can experiment, and/or set up a blank diff and paste stuff in to see what you get.
Main problem I've had is that it's slow for large files. I think it's written in Python.
An outsize annoyance (which is objectively just a minor UX nit) is that the diff setup dialog displays names only, not full paths. Which is silly, because a very common use case for diff tools is diffing two files that have the same name, so I notice this on about 75% of uses.
kdiff3 never failed me, and having separate original, theirs, yours and result panels, I find it much clearer to work with than Meld. Often it even auto-resolves merges that Git couldn't.
My favorite merge tool remains Source Gear’s DiffMerge but it hadn’t been updated in years. I like some of what Kaleidoscope does but it’s not as good at automatic conflict resolution.
What I like about p4merge is that it displays four panels: local/remote/result (what most 3-way merge tools use), but also the common ancestor of local and remote ("base"). It really helps with some more tricky merges.
With that said, after using p4merge for years, I now tend to rely on the built-in merge tool in IntelliJ IDEA. Especially the "magic wand" is very handy.
This was a saviour. I wanted to merge a previously done extensive change, say B for the original file A and also a different kind of change, say C for the same original file A. I had to merge both the changes. Diff3 came as a saviour.
i always want to use vimdiff with git mergetool but i’ve never been able to figure out how to use it when i launch the 3way split. i know there are commands to choose between local/base/remote for each conflict i dont know where my cursor is supposed to be or where i should be using those commands from.
i always end up going back to emacs and just using smerge, with its super straightforward “go to next conflict” and “choose upper or lower” commands
Imagine the world where code is represented as a tree of operations, where every character have unique, immutable address. Diff becomes something way simpler. Welcome to the world of CRDT.
I hope, one day we will have a thing like automerge but as file format with a native OS provided merging.