Thread (5 messages) flat view 5 messages, 2 authors, 2021-06-13

Re: [PATCH 7/7] xdiff: make diff3 the default conflictStyle

From: Felipe Contreras <hidden>
Date: 2021-06-11 17:58:07

Possibly related (same subject, not in this thread)

Elijah Newren wrote:
On Fri, Jun 11, 2021 at 8:32 AM Felipe Contreras [off-list ref]
wrote:
quoted
Sergey Organov wrote:
quoted
Junio C Hamano [off-list ref] writes:
quoted
  git init repo &&
  cd repo &&

  echo 1 > content &&
  git add content &&
  git commit -m 1 content &&

  git checkout -b A master &&
  echo A > content &&
  git commit -m A content &&

  git checkout -b B master &&
  echo B > content &&
  git commit -m B content &&

  git checkout -b C A &&
  git rev-parse B >.git/MERGE_HEAD &&
  echo C > content &&
  git commit -m C -a &&

  git checkout -b D A &&
  git rev-parse B >.git/MERGE_HEAD &&
  echo D > content &&
  git commit -m D -a &&

  git -c merge.conflictstyle=diff3 merge -m final C &&
  cat content
Right, here you do not have a unique merge base; you have two of them: A &
B (it's possible to have three or more as well).  To do a three-way merge,
you need a single base commit.  So, whenever you have more than one merge
base, both merge-recursive and merge-ort will merge the merge bases to get
a virtual merge base.  There's always a risk that the merge bases don't
have a unique merge base either, forcing the algorithm to recurse.  This
behavior is where the merge algorithm 'recursive' got its name from (and
which also appears in ort's name -- "Ostensibly Recursive's Twin").

You could decide to just pick one of the merge-bases at random, and yield a
different set of surprises including silently merging in favor of one side
when the two sides did things differently.  That's problematic.

Instead of using a merge base (a recent-as-possible common commit), you
could decide to instead just try to find a unique common base, regardless
of how ancient it is.  Using ancient commits as the base is a step towards
just doing a two-way merge (treating the histories as completely
independent and throwing merge conflicts whenever any files aren't
identical on the two sides).  Sure, it's not as bad, but it does yield
massive amounts of useless conflicts.  So this is problematic too.

The alternative to the above two options was the
make-a-virtual-merge-base-by-merging-merge-bases strategy.  It apparently
was very successful.
OK. That makes sense.
But it does mean that merge bases can have conflict markers in them.
But why? And even if they do, why do they have to be diff3 conflict
markers?

This would be more human-friendly:

  <<<<<<< HEAD
  D
  ||||||| merged common ancestors
  <<<<<<<<< Temporary merge branch 1
  B
  =========
  A
  >>>>>>>>> Temporary merge branch 2
  =======
  C
  >>>>>>> C

Or just put a stub conflict marker:

  <<<<<<< HEAD
  D
  ||||||| merged common ancestors
  <<<<<<<<< Temporary merge >>>>>>>>>
  =======
  C
  >>>>>>> C

Or just use the base of the virtual merge:

  <<<<<<< HEAD
  D
  ||||||| merged common ancestors
  1
  =======
  C
  >>>>>>> C

We don't have to use diff3 all the way.

Cheers.

-- 
Felipe Contreras
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help