[HN Gopher] Merging with diff3: the "three-way merge"
___________________________________________________________________
Merging with diff3: the "three-way merge"
Author : fortran77
Score : 81 points
Date : 2023-01-28 14:36 UTC (8 hours ago)
(HTM) web link (blog.jcoglan.com)
(TXT) w3m dump (blog.jcoglan.com)
| munhitsu wrote:
| [dead]
| forrestthewoods wrote:
| 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.
| natmaka wrote:
| Emacs 'ediff' is quite convenient.
| https://www.gnu.org/software/emacs/manual/html_node/ediff/Me...
| TacticalCoder wrote:
| 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.
| User23 wrote:
| 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.
| TacticalCoder wrote:
| > 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) : )
| Razengan wrote:
| Literally scrolling
| Icathian wrote:
| Mind sharing that? Merge resolver view is the _only_ thing I
| 'm still opening vscode for and I'd be very happy to finally
| kill that off.
| TacticalCoder wrote:
| 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: (defun
| ediff-setup-windows-plain-merge (buf-A buf-B buf-C control-
| buffer) ;; skip dedicated and unsplittable frames
| (ediff-destroy-control-frame control-buffer) (let
| ((window-min-height 1) (with-Ancestor-p
| (with-current-buffer control-buffer
| ediff-merge-with-ancestor-job)) split-
| window-function merge-window-share merge-
| window-lines (buf-Ancestor (with-current-
| buffer control-buffer
| ediff-ancestor-buffer)) wind-A wind-B
| wind-C wind-Ancestor) (with-current-buffer
| control-buffer (setq merge-window-share
| ediff-merge-window-share ;; this lets
| us have local versions of ediff-split-window-function
| split-window-function ediff-split-window-function))
| (delete-other-windows) (set-window-dedicated-p
| (selected-window) nil) (split-window-
| vertically) (ediff-select-lowest-window)
| (ediff-setup-control-buffer control-buffer)
| ;; go to the upper window and split it betw A, B, and
| possibly C (other-window 1) (setq
| merge-window-lines (max 2 (round (*
| (window-height) merge-window-share)))) (switch-
| to-buffer buf-A) (setq wind-A (selected-
| window)) (split-window-vertically (max
| 2 (- (window-height) merge-window-lines))) (if
| (eq (selected-window) wind-A) (other-window
| 1)) (setq wind-C (selected-window))
| (switch-to-buffer buf-C) (select-
| window wind-A) (funcall split-window-function)
| (if (eq (selected-window) wind-A) (other-
| window 1)) (switch-to-buffer buf-B)
| (setq wind-B (selected-window)) (when
| (and ediff-show-ancestor with-Ancestor-p)
| (select-window wind-B) (split-window-
| horizontally) (when (eq (selected-window)
| wind-B) (other-window 1))
| (switch-to-buffer buf-Ancestor) (setq wind-
| Ancestor (selected-window))) (balance-
| windows-area) (with-current-buffer
| control-buffer (setq ediff-window-A wind-A
| ediff-window-B wind-B ediff-window-C
| wind-C ediff-window-Ancestor wind-
| Ancestor)) (ediff-select-lowest-
| window) (minimize-window) (ediff-
| setup-control-buffer control-buffer) ))
| IshKebab wrote:
| 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!
| js2 wrote:
| 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: git log -p HEAD...MERGE_HEAD
| --path/to/file
|
| https://www.git-scm.com/docs/git-log
|
| 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.
| mambru wrote:
| IIRC vscode with gitlens extension shows blame on hover, also
| for the conflicting lines.
| acdha wrote:
| 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.
| b3morales wrote:
| 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.
| samsquire wrote:
| I implemented this in Python based on his guide to the Myers
| algorithm.
|
| https://GitHub.com/samsquire/text-diff
|
| It's not complete and the colouring is probably not the right way
| round.
| mkoubaa wrote:
| Am I the only one that prefers manually resolving conflicts in a
| text editor? It sucks but I can't imagine a GUI that sucks less
| spyremeown wrote:
| Try any of the recommendations here (my poison is Meld). It's
| actually one of the few tasks where I really, really do prefer
| a GUI over text.
| bmn__ wrote:
| <https://apps.kde.org/kdiff3> is partially a text editor, try
| it out and develop an appreciation for it.
| softfalcon wrote:
| Nope! I've done this for years now. It made the most sense to
| me.
|
| Some people are at a loss as to how I can resolve a conflict
| without any tools (other than git + text edit) though, feels
| like a super power!
| tome wrote:
| Ah, I wrote an article on resolving diff3 conflicts by hand:
| http://h2.jaguarpaw.co.uk/posts/git-rebase-conflicts/
| secondcoming wrote:
| p4merge is one of the first tools I download when I have to set
| up a new environment.
| darekkay wrote:
| 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.
| politician wrote:
| Shoutout to kdiff3.
| joncp wrote:
| Totally. The newest version is 8 years old and it still works
| great.
| pdhborges wrote:
| Kdiff3 is still developed. You can download newer versions
| here: https://download.kde.org/stable/kdiff3/
| BaculumMeumEst wrote:
| 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
| BlueTemplar wrote:
| 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) :
|
| https://jneem.github.io/pijul/
|
| And because it uses more information about the history, it is
| able to do smarter merges (if I am not mistaken, even compared to
| the OP ?) :
|
| https://tahoe-lafs.org/~zooko/badmerge/simple.html
|
| https://pijul.org/faq
| ChrisCinelli wrote:
| 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.
| loeg wrote:
| Yeah, it's one of the first things I change in .gitconfig or
| .hgrc: [merge] conflictstyle = diff3
| kmarc wrote:
| \git mergetool\ runs your favourite editor/difftool to do a 3way
| merge. I found vim to be a perfect tool for doing this
___________________________________________________________________
(page generated 2023-01-28 23:00 UTC)