filemerge._picktool: only pick from nomerge tools for change/delete conflicts
authorSiddharth Agarwal <sid0@fb.com>
Sun, 15 Nov 2015 21:40:15 -0800
changeset 27039 d7517deedf86
parent 27038 58a4eb16e722
child 27040 1bde66b89bb2
filemerge._picktool: only pick from nomerge tools for change/delete conflicts For --tool or HGMERGE, we could have either: (a) proceeded with the particular tool, then failed the merge. (b) chosen to prompt regardless. We're explicitly choosing (b) here, because it's effectively what we've been doing so far and helps maintain an easier-to-use interface. However, in future patches we're going to change the default selection from 'pick changed version' to 'leave unresolved'. That fixes most of the brokenness involved with choice (b).
mercurial/filemerge.py
--- a/mercurial/filemerge.py	Fri Nov 13 23:52:26 2015 -0800
+++ b/mercurial/filemerge.py	Sun Nov 15 21:40:15 2015 -0800
@@ -120,8 +120,11 @@
     exe = _toolstr(ui, tool, "executable", tool)
     return util.findexe(util.expandpath(exe))
 
-def _picktool(repo, ui, path, binary, symlink):
-    def check(tool, pat, symlink, binary):
+def _picktool(repo, ui, path, binary, symlink, changedelete):
+    def supportscd(tool):
+        return tool in internals and internals[tool].mergetype == nomerge
+
+    def check(tool, pat, symlink, binary, changedelete):
         tmsg = tool
         if pat:
             tmsg += " specified for " + pat
@@ -134,6 +137,10 @@
             ui.warn(_("tool %s can't handle symlinks\n") % tmsg)
         elif binary and not _toolbool(ui, tool, "binary"):
             ui.warn(_("tool %s can't handle binary\n") % tmsg)
+        elif changedelete and not supportscd(tool):
+            # the nomerge tools are the only tools that support change/delete
+            # conflicts
+            pass
         elif not util.gui() and _toolbool(ui, tool, "gui"):
             ui.warn(_("tool %s requires a GUI\n") % tmsg)
         else:
@@ -145,21 +152,27 @@
     force = ui.config('ui', 'forcemerge')
     if force:
         toolpath = _findtool(ui, force)
-        if toolpath:
-            return (force, util.shellquote(toolpath))
+        if changedelete and not supportscd(toolpath):
+            return ":prompt", None
         else:
-            # mimic HGMERGE if given tool not found
-            return (force, force)
+            if toolpath:
+                return (force, util.shellquote(toolpath))
+            else:
+                # mimic HGMERGE if given tool not found
+                return (force, force)
 
     # HGMERGE takes next precedence
     hgmerge = os.environ.get("HGMERGE")
     if hgmerge:
-        return (hgmerge, hgmerge)
+        if changedelete and not supportscd(hgmerge):
+            return ":prompt", None
+        else:
+            return (hgmerge, hgmerge)
 
     # then patterns
     for pat, tool in ui.configitems("merge-patterns"):
         mf = match.match(repo.root, '', [pat])
-        if mf(path) and check(tool, pat, symlink, False):
+        if mf(path) and check(tool, pat, symlink, False, changedelete):
             toolpath = _findtool(ui, tool)
             return (tool, util.shellquote(toolpath))
 
@@ -176,17 +189,19 @@
     tools = sorted([(-p, t) for t, p in tools.items() if t not in disabled])
     uimerge = ui.config("ui", "merge")
     if uimerge:
-        if uimerge not in names:
+        # external tools defined in uimerge won't be able to handle
+        # change/delete conflicts
+        if uimerge not in names and not changedelete:
             return (uimerge, uimerge)
         tools.insert(0, (None, uimerge)) # highest priority
     tools.append((None, "hgmerge")) # the old default, if found
     for p, t in tools:
-        if check(t, None, symlink, binary):
+        if check(t, None, symlink, binary, changedelete):
             toolpath = _findtool(ui, t)
             return (t, util.shellquote(toolpath))
 
     # internal merge or prompt as last resort
-    if symlink or binary:
+    if symlink or binary or changedelete:
         return ":prompt", None
     return ":merge", None
 
@@ -535,7 +550,8 @@
     fd = fcd.path()
     binary = fcd.isbinary() or fco.isbinary() or fca.isbinary()
     symlink = 'l' in fcd.flags() + fco.flags()
-    tool, toolpath = _picktool(repo, ui, fd, binary, symlink)
+    changedelete = fcd.isabsent() or fco.isabsent()
+    tool, toolpath = _picktool(repo, ui, fd, binary, symlink, changedelete)
     if tool in internals and tool.startswith('internal:'):
         # normalize to new-style names (':merge' etc)
         tool = tool[len('internal'):]