@@ -205,11 +205,12 @@ def _premerge(repo, toolconf, files, lab
"(edit conflicts, then use 'hg resolve --mark')\n"))
def _imerge(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 partially merged file. Markers will have two sections, one for each side
+ of merge."""
tool, toolpath, binary, symlink = toolconf
if symlink:
repo.ui.warn(_('warning: internal:merge cannot merge symlinks '
'for %s\n') % fcd.path())
return False, 1
@@ -221,10 +222,25 @@ def _imerge(repo, mynode, orig, fcd, fco
r = simplemerge.simplemerge(ui, a, b, c, label=labels, no_minimal=True)
return True, r
return False, 0
+@internaltool('merge3', True,
+ _("merging %s incomplete! "
+ "(edit conflicts, then use 'hg resolve --mark')\n"))
+def _imerge3(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. Marker will have three sections, one from each
+ side of the merge and one for the base content."""
+ if not labels:
+ labels = _defaultconflictlabels
+ if len(labels) < 3:
+ labels.append('base')
+ return _imerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels)
+
@internaltool('tagmerge', True,
_("automatic tag merging of %s failed! "
"(use 'hg resolve --tool internal:merge' or another merge "
"tool of your choice)\n"))
def _itagmerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
@@ -311,27 +327,31 @@ def _formatconflictmarker(repo, ctx, tem
'{ifeq(branch, "default", "", "{branch} ")}' +
'- {author|user}: {desc|firstline}')
_defaultconflictlabels = ['local', 'other']
-def _formatlabels(repo, fcd, fco, labels):
+def _formatlabels(repo, fcd, fco, fca, labels):
"""Formats the given labels using the conflict marker template.
Returns a list of formatted labels.
"""
cd = fcd.changectx()
co = fco.changectx()
+ ca = fca.changectx()
ui = repo.ui
template = ui.config('ui', 'mergemarkertemplate', _defaultconflictmarker)
template = templater.parsestring(template, quoted=False)
- tmpl = templater.templater(None, cache={ 'conflictmarker' : template })
+ tmpl = templater.templater(None, cache={'conflictmarker': template})
- pad = max(len(labels[0]), len(labels[1]))
+ pad = max(len(l) for l in labels)
- return [_formatconflictmarker(repo, cd, tmpl, labels[0], pad),
- _formatconflictmarker(repo, co, tmpl, labels[1], pad)]
+ newlabels = [_formatconflictmarker(repo, cd, tmpl, labels[0], pad),
+ _formatconflictmarker(repo, co, tmpl, labels[1], pad)]
+ if len(labels) > 2:
+ newlabels.append(_formatconflictmarker(repo, ca, tmpl, labels[2], pad))
+ return newlabels
def filemerge(repo, mynode, orig, fcd, fco, fca, labels=None):
"""perform a 3-way merge in the working directory
mynode = parent node before merge
@@ -390,11 +410,11 @@ def filemerge(repo, mynode, orig, fcd, f
markerstyle = ui.config('ui', 'mergemarkers', 'basic')
if not labels:
labels = _defaultconflictlabels
if markerstyle != 'basic':
- labels = _formatlabels(repo, fcd, fco, labels)
+ labels = _formatlabels(repo, fcd, fco, fca, labels)
needcheck, r = func(repo, mynode, orig, fcd, fco, fca, toolconf,
(a, b, c, back), labels=labels)
if not needcheck:
if r:
@@ -413,17 +413,20 @@ def simplemerge(ui, local, base, other,
raise util.Abort(msg)
return text
name_a = local
name_b = other
+ name_base = None
labels = opts.get('label', [])
if len(labels) > 0:
name_a = labels[0]
if len(labels) > 1:
name_b = labels[1]
if len(labels) > 2:
- raise util.Abort(_("can only specify two labels."))
+ name_base = labels[2]
+ if len(labels) > 3:
+ raise util.Abort(_("can only specify three labels."))
try:
localtext = readfile(local)
basetext = readfile(base)
othertext = readfile(other)
@@ -436,14 +439,22 @@ def simplemerge(ui, local, base, other,
out = opener(os.path.basename(local), "w", atomictemp=True)
else:
out = sys.stdout
reprocess = not opts.get('no_minimal')
+ if reprocess and name_base:
+ msg = _("display of base incompatible conflict minimization")
+ raise util.Abort(msg, hint=_("add --no-minimal"))
+
m3 = Merge3Text(basetext, localtext, othertext)
+ extrakwargs = {}
+ if name_base is not None:
+ extrakwargs['base_marker'] = '|||||||'
+ extrakwargs['name_base'] = name_base
for line in m3.merge_lines(name_a=name_a, name_b=name_b,
- reprocess=reprocess):
+ reprocess=reprocess, **extrakwargs):
out.write(line)
if not opts.get('print'):
out.close()
@@ -196,5 +196,39 @@ Verify basic conflict markers
3
4
5
>>>>>>> other
Hop we are done.
+
+internal:merge3
+
+ $ hg up -q --clean .
+
+ $ hg merge 1 --tool internal:merge3
+ merging a
+ warning: conflicts during merge.
+ merging a incomplete! (edit conflicts, 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 or 'hg update -C .' to abandon
+ [1]
+ $ cat a
+ Small Mathematical Series.
+ <<<<<<< local
+ 1
+ 2
+ 3
+ 6
+ 8
+ ||||||| base
+ One
+ Two
+ Three
+ Four
+ Five
+ =======
+ 1
+ 2
+ 3
+ 4
+ 5
+ >>>>>>> other
+ Hop we are done.
@@ -195,11 +195,11 @@ 2 labels
[1]
too many labels
$ python simplemerge -p -L foo -L bar -L baz conflict-local base conflict-other
- abort: can only specify two labels.
+ abort: display of base incompatible conflict minimization
[255]
binary file
$ python -c "f = file('binary-local', 'w'); f.write('\x00'); f.close()"