@@ -2052,6 +2052,13 @@
partially merged file. Marker will have three sections, one from each
side of the merge and one for the base content.
+ ":mergediff"
+ Uses the internal non-interactive simple merge algorithm for merging
+ files. It will fail if there are any conflicts and leave markers in the
+ partially merged file. The marker will have two sections, one with the
+ content from one side of the merge, and one with a diff from the base
+ content to the content on the other side. (experimental)
+
":other"
Uses the other 'p2()' version of files as the merged version.
@@ -280,6 +280,80 @@
>>>>>>> merge rev
Hop we are done.
+internal:mergediff
+
+ $ hg co -C 1
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cat << EOF > a
+ > Small Mathematical Series.
+ > 1
+ > 2
+ > 3
+ > 4
+ > 4.5
+ > 5
+ > Hop we are done.
+ > EOF
+ $ hg co -m 2 -t internal:mergediff
+ merging a
+ warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
+ 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
+ use 'hg resolve' to retry unresolved file merges
+ [1]
+ $ cat a
+ Small Mathematical Series.
+ 1
+ 2
+ 3
+ <<<<<<<
+ ------- base
+ +++++++ working copy
+ 4
+ +4.5
+ 5
+ +++++++ destination
+ 6
+ 8
+ >>>>>>>
+ Hop we are done.
+Test the same thing as above but modify a bit more so we instead get the working
+copy in full and the diff from base to destination.
+ $ hg co -C 1
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cat << EOF > a
+ > Small Mathematical Series.
+ > 1
+ > 2
+ > 3.5
+ > 4.5
+ > 5.5
+ > Hop we are done.
+ > EOF
+ $ hg co -m 2 -t internal:mergediff
+ merging a
+ warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
+ 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
+ use 'hg resolve' to retry unresolved file merges
+ [1]
+ $ cat a
+ Small Mathematical Series.
+ 1
+ 2
+ <<<<<<<
+ +++++++ working copy
+ 3.5
+ 4.5
+ 5.5
+ ------- base
+ +++++++ destination
+ 3
+ -4
+ -5
+ +6
+ +8
+ >>>>>>>
+ Hop we are done.
+
Add some unconflicting changes on each head, to make sure we really
are merging, unlike :local and :other
@@ -455,6 +455,68 @@
return ctx.node() != nodemod.nullid
+def _mergediff(m3, name_a, name_b, name_base):
+ lines = []
+ conflicts = False
+ for group in m3.merge_groups():
+ if group[0] == b'conflict':
+ base_lines, a_lines, b_lines = group[1:]
+ base_text = b''.join(base_lines)
+ b_blocks = list(
+ mdiff.allblocks(
+ base_text,
+ b''.join(b_lines),
+ lines1=base_lines,
+ lines2=b_lines,
+ )
+ )
+ a_blocks = list(
+ mdiff.allblocks(
+ base_text,
+ b''.join(a_lines),
+ lines1=base_lines,
+ lines2=b_lines,
+ )
+ )
+
+ def matching_lines(blocks):
+ return sum(
+ block[1] - block[0]
+ for block, kind in blocks
+ if kind == b'='
+ )
+
+ def diff_lines(blocks, lines1, lines2):
+ for block, kind in blocks:
+ if kind == b'=':
+ for line in lines1[block[0] : block[1]]:
+ yield b' ' + line
+ else:
+ for line in lines1[block[0] : block[1]]:
+ yield b'-' + line
+ for line in lines2[block[2] : block[3]]:
+ yield b'+' + line
+
+ lines.append(b"<<<<<<<\n")
+ if matching_lines(a_blocks) < matching_lines(b_blocks):
+ lines.append(b"+++++++ %s\n" % name_a)
+ lines.extend(a_lines)
+ lines.append(b"------- %s\n" % name_base)
+ lines.append(b"+++++++ %s\n" % name_b)
+ lines.extend(diff_lines(b_blocks, base_lines, b_lines))
+ else:
+ lines.append(b"------- %s\n" % name_base)
+ lines.append(b"+++++++ %s\n" % name_a)
+ lines.extend(diff_lines(a_blocks, base_lines, a_lines))
+ lines.append(b"+++++++ %s\n" % name_b)
+ lines.extend(b_lines)
+ lines.append(b">>>>>>>\n")
+ conflicts = True
+ else:
+ lines.extend(group[1])
+ return lines, conflicts
+
+
def simplemerge(ui, localctx, basectx, otherctx, **opts):
"""Performs the simplemerge algorithm.
@@ -499,9 +561,15 @@
extrakwargs[b'name_base'] = name_base
extrakwargs[b'minimize'] = False
- lines = m3.merge_lines(
- name_a=name_a, name_b=name_b, **pycompat.strkwargs(extrakwargs)
- )
+ if mode == b'mergediff':
+ lines, conflicts = _mergediff(m3, name_a, name_b, name_base or b'',)
+ else:
+ lines = list(
+ m3.merge_lines(
+ name_a=name_a, name_b=name_b, **pycompat.strkwargs(extrakwargs)
+ )
+ )
+ conflicts = m3.conflicts
# merge flags if necessary
flags = localctx.flags()
@@ -519,5 +587,5 @@
else:
localctx.write(mergedtext, flags)
- if m3.conflicts and not mode == b'union':
+ if conflicts and not mode == b'union':
return 1
@@ -532,6 +532,33 @@
return _imerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels)
+@internaltool(
+ b'mergediff',
+ fullmerge,
+ _(
+ b"warning: conflicts while merging %s! "
+ b"(edit, then use 'hg resolve --mark')\n"
+ ),
+ precheck=_mergecheck,
+)
+def _imerge_diff(
+ repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None
+):
+ """
+ Uses the internal non-interactive simple merge algorithm for merging
+ files. It will fail if there are any conflicts and leave markers in
+ the partially merged file. The marker will have two sections, one with the
+ content from one side of the merge, and one with a diff from the base
+ content to the content on the other side. (experimental)"""
+ if not labels:
+ labels = _defaultconflictlabels
+ if len(labels) < 3:
+ labels.append(b'base')
+ return _merge(
+ repo, mynode, orig, fcd, fco, fca, toolconf, files, labels, b'mergediff'
+ )
+
+
def _imergeauto(
repo,
mynode,