changeset 38793:6c8e3c847977

resolve: add option to warn/abort on -m with unresolved conflict markers When a user is dropped out of Mercurial to a terminal to resolve files, we emit messages like: conflicts while merging file1! (edit, then use 'hg resolve --mark') conflicts while merging file2! (edit, then use 'hg resolve --mark') We don't mention a file name in the hint, so some users might do something like `$EDITOR file1; hg resolve --mark`, see that it says "(no more unresolved files)" and forget to deal with file2 before running the next command. Even if we did mention a file name in the hint, it's too easy to forget it (maybe the merge spans a couple days or something). This option lets us inform the user that they might have missed something. In the scenario above, the output would be something like: warning: the following files still have conflict markers: file2 (no more unresolved files) Differential Revision: https://phab.mercurial-scm.org/D4035
author Kyle Lippincott <spectral@google.com>
date Thu, 26 Jul 2018 17:11:03 -0700
parents afb442f58cbf
children 1d01cf0416a5
files mercurial/commands.py mercurial/configitems.py mercurial/filemerge.py tests/test-resolve.t
diffstat 4 files changed, 74 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/commands.py	Mon Jul 02 18:39:48 2018 -0700
+++ b/mercurial/commands.py	Thu Jul 26 17:11:03 2018 -0700
@@ -35,6 +35,7 @@
     error,
     exchange,
     extensions,
+    filemerge,
     formatter,
     graphmod,
     hbisect,
@@ -4594,6 +4595,9 @@
         runconclude = False
 
         tocomplete = []
+        hasconflictmarkers = []
+        if mark:
+            markcheck = ui.config('experimental', 'resolve.mark-check')
         for f in ms:
             if not m(f):
                 continue
@@ -4629,6 +4633,12 @@
                 continue
 
             if mark:
+                if markcheck:
+                    with repo.wvfs(f) as fobj:
+                        fdata = fobj.read()
+                    if filemerge.hasconflictmarkers(fdata) and \
+                        ms[f] != mergemod.MERGE_RECORD_RESOLVED:
+                        hasconflictmarkers.append(f)
                 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED)
             elif unmark:
                 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED)
@@ -4663,6 +4673,13 @@
                         if inst.errno != errno.ENOENT:
                             raise
 
+        if hasconflictmarkers:
+            ui.warn(_('warning: the following files still have conflict '
+                      'markers:\n  ') + '\n  '.join(hasconflictmarkers) + '\n')
+            if markcheck == 'abort' and not all:
+                raise error.Abort(_('conflict markers detected'),
+                                  hint=_('use --all to mark anyway'))
+
         for f in tocomplete:
             try:
                 # resolve file
--- a/mercurial/configitems.py	Mon Jul 02 18:39:48 2018 -0700
+++ b/mercurial/configitems.py	Thu Jul 26 17:11:03 2018 -0700
@@ -931,6 +931,9 @@
     default=True,
     alias=[('format', 'aggressivemergedeltas')],
 )
+coreconfigitem('experimental', 'resolve.mark-check',
+    default=None,
+)
 coreconfigitem('server', 'bookmarks-pushkey-compat',
     default=True,
 )
--- a/mercurial/filemerge.py	Mon Jul 02 18:39:48 2018 -0700
+++ b/mercurial/filemerge.py	Thu Jul 26 17:11:03 2018 -0700
@@ -916,14 +916,17 @@
         _haltmerge()
     # default action is 'continue', in which case we neither prompt nor halt
 
+def hasconflictmarkers(data):
+    return bool(re.search("^(<<<<<<< .*|=======|>>>>>>> .*)$", data,
+                          re.MULTILINE))
+
 def _check(repo, r, ui, tool, fcd, files):
     fd = fcd.path()
     unused, unused, unused, back = files
 
     if not r and (_toolbool(ui, tool, "checkconflicts") or
                   'conflicts' in _toollist(ui, tool, "check")):
-        if re.search("^(<<<<<<< .*|=======|>>>>>>> .*)$", fcd.data(),
-                     re.MULTILINE):
+        if hasconflictmarkers(fcd.data()):
             r = 1
 
     checked = False
--- a/tests/test-resolve.t	Mon Jul 02 18:39:48 2018 -0700
+++ b/tests/test-resolve.t	Thu Jul 26 17:11:03 2018 -0700
@@ -373,4 +373,53 @@
 
   $ hg resolve -l
 
+resolve -m can be configured to look for remaining conflict markers
+  $ hg up -qC 2
+  $ hg merge -q --tool=internal:merge 1
+  warning: conflicts while merging file1! (edit, then use 'hg resolve --mark')
+  warning: conflicts while merging file2! (edit, then use 'hg resolve --mark')
+  [1]
+  $ hg resolve -l
+  U file1
+  U file2
+  $ echo 'remove markers' > file1
+  $ hg --config experimental.resolve.mark-check=abort resolve -m
+  warning: the following files still have conflict markers:
+    file2
+  abort: conflict markers detected
+  (use --all to mark anyway)
+  [255]
+  $ hg resolve -l
+  U file1
+  U file2
+Try with --all from the hint
+  $ hg --config experimental.resolve.mark-check=abort resolve -m --all
+  warning: the following files still have conflict markers:
+    file2
+  (no more unresolved files)
+  $ hg resolve -l
+  R file1
+  R file2
+  $ hg resolve --unmark
+  $ hg resolve -l
+  U file1
+  U file2
+  $ hg --config experimental.resolve.mark-check=warn resolve -m
+  warning: the following files still have conflict markers:
+    file2
+  (no more unresolved files)
+  $ hg resolve -l
+  R file1
+  R file2
+If the file is already marked as resolved, we don't warn about it
+  $ hg resolve --unmark file1
+  $ hg resolve -l
+  U file1
+  R file2
+  $ hg --config experimental.resolve.mark-check=warn resolve -m
+  (no more unresolved files)
+  $ hg resolve -l
+  R file1
+  R file2
+
   $ cd ..