changeset 40528:86dfae98a3a2

merge-tools: when calling external merge tool, describe the resolve inputs It is a common complaint that a user will be running some operation (histedit, rebase, evolve, etc.), get into a merge-conflict situation, and not understand what they are seeing - it is possible that the merge tool is configured to display the hash, but it's difficult for most merge tools to display a good snippet of the description. In the worst case, configuring this template will lead to output that is immediately covered by a terminal application, maybe the user can hit ctrl-z to see it. In the common case, the output will be in a terminal window and a GUI program will start, and it should be possible to view both the terminal and the GUI program at the same time. Differential Revision: https://phab.mercurial-scm.org/D5094
author Kyle Lippincott <spectral@google.com>
date Sat, 13 Oct 2018 07:49:20 -0700
parents 592feb3f88b1
children 176c26a21123
files mercurial/configitems.py mercurial/filemerge.py mercurial/help/config.txt tests/test-merge-tools.t
diffstat 4 files changed, 77 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/configitems.py	Fri Oct 26 21:46:37 2018 +0900
+++ b/mercurial/configitems.py	Sat Oct 13 07:49:20 2018 -0700
@@ -1193,6 +1193,9 @@
 coreconfigitem('ui', 'patch',
     default=None,
 )
+coreconfigitem('ui', 'pre-merge-tool-output-template',
+    default=None,
+)
 coreconfigitem('ui', 'portablefilenames',
     default='warn',
 )
--- a/mercurial/filemerge.py	Fri Oct 26 21:46:37 2018 +0900
+++ b/mercurial/filemerge.py	Sat Oct 13 07:49:20 2018 -0700
@@ -13,7 +13,11 @@
 import shutil
 
 from .i18n import _
-from .node import nullid, short
+from .node import (
+    hex,
+    nullid,
+    short,
+)
 
 from . import (
     encoding,
@@ -27,6 +31,7 @@
     tagmerge,
     templatekw,
     templater,
+    templateutil,
     util,
 )
 
@@ -536,6 +541,44 @@
     raise error.InMemoryMergeConflictsError('in-memory merge does not support '
                                             'external merge tools')
 
+def _describemerge(ui, repo, mynode, fcl, fcb, fco, env, toolpath, args):
+    tmpl = ui.config('ui', 'pre-merge-tool-output-template')
+    if not tmpl:
+        return
+
+    mappingdict = templateutil.mappingdict
+    props = {'ctx': fcl.changectx(),
+             'node': hex(mynode),
+             'path': fcl.path(),
+             'local': mappingdict({'ctx': fcl.changectx(),
+                                   'fctx': fcl,
+                                   'node': hex(mynode),
+                                   'name': _('local'),
+                                   'islink': 'l' in fcl.flags(),
+                                   'label': env['HG_MY_LABEL']}),
+             'base': mappingdict({'ctx': fcb.changectx(),
+                                  'fctx': fcb,
+                                  'name': _('base'),
+                                  'islink': 'l' in fcb.flags(),
+                                  'label': env['HG_BASE_LABEL']}),
+             'other': mappingdict({'ctx': fco.changectx(),
+                                   'fctx': fco,
+                                   'name': _('other'),
+                                   'islink': 'l' in fco.flags(),
+                                   'label': env['HG_OTHER_LABEL']}),
+             'toolpath': toolpath,
+             'toolargs': args}
+
+    # TODO: make all of this something that can be specified on a per-tool basis
+    tmpl = templater.unquotestring(tmpl)
+
+    # Not using cmdutil.rendertemplate here since it causes errors importing
+    # things for us to import cmdutil.
+    tres = formatter.templateresources(ui, repo)
+    t = formatter.maketemplater(ui, tmpl, defaults=templatekw.keywords,
+                                resources=tres)
+    ui.status(t.renderdefault(props))
+
 def _xmerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
     tool, toolpath, binary, symlink, scriptfn = toolconf
     if fcd.isabsent() or fco.isabsent():
@@ -584,6 +627,7 @@
         if scriptfn is None:
             cmd = toolpath + ' ' + args
             repo.ui.debug('launching merge tool: %s\n' % cmd)
+            _describemerge(ui, repo, mynode, fcd, fca, fco, env, toolpath, args)
             r = ui.system(cmd, cwd=repo.root, environ=env,
                           blockedtag='mergetool')
         else:
--- a/mercurial/help/config.txt	Fri Oct 26 21:46:37 2018 +0900
+++ b/mercurial/help/config.txt	Sat Oct 13 07:49:20 2018 -0700
@@ -2296,6 +2296,16 @@
 
       On Windows, this configuration option is ignored and the command aborted.
 
+``pre-merge-tool-output-template``
+    A template that is printed before executing an external merge tool. This can
+    be used to print out additional context that might be useful to have during
+    the conflict resolution, such as the description of the various commits
+    involved or bookmarks/tags.
+
+    Additional information is available in the ``local`, ``base``, and ``other``
+    dicts. For example: ``{local.label}``, ``{base.name}``, or
+    ``{other.islink}``.
+
 ``quiet``
     Reduce the amount of output printed.
     (default: False)
--- a/tests/test-merge-tools.t	Fri Oct 26 21:46:37 2018 +0900
+++ b/tests/test-merge-tools.t	Sat Oct 13 07:49:20 2018 -0700
@@ -1946,6 +1946,25 @@
   0000: 00 01 02 03                                     |....|
   $ hg merge --abort -q
 
+Check that the extra information is printed correctly
+
+  $ hg merge 9 \
+  >   --config merge-tools.testecho.executable='echo' \
+  >   --config merge-tools.testecho.args='merge runs here ...' \
+  >   --config merge-tools.testecho.binary=True \
+  >   --config ui.merge=testecho \
+  >   --config ui.pre-merge-tool-output-template='\n{label("extmerge.running_merge_tool", "Running merge tool for {path} ({toolpath}):")}\n{separate("\n", extmerge_section(local), extmerge_section(base), extmerge_section(other))}\n' \
+  >   --config 'templatealias.extmerge_section(sect)="- {pad("{sect.name} ({sect.label})", 20, left=True)}: {revset(sect.node)%"{rev}:{shortest(node,8)} {desc|firstline} {separate(" ", tags, bookmarks, branch)}"}"'
+  merging b
+  
+  Running merge tool for b (*/bin/echo): (glob)
+  - local (working copy): 10:2d1f533d add binary file (#2) tip default
+  -          base (base): -1:00000000  default
+  -    other (merge rev): 9:1e7ad7d7 add binary file (#1) default
+  merge runs here ...
+  0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+  (branch merge, don't forget to commit)
+
 Check that debugpicktool examines which merge tool is chosen for
 specified file as expected