changeset 34548:b4955650eb57

merge: add merge action 'pr' to rename files during update Add a new merge action to handle a path conflict by renaming the conflicting file to a safe name. The rename is just to avoid problems on the filesystem. The conflict is still considered unresolved until the user marks the original path as resolved. Differential Revision: https://phab.mercurial-scm.org/D777
author Mark Thomas <mbthomas@fb.com>
date Mon, 02 Oct 2017 14:05:30 -0700
parents 81aebcc73beb
children a991e1d6bc82
files mercurial/merge.py mercurial/sparse.py
diffstat 2 files changed, 27 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/merge.py	Mon Oct 02 14:05:30 2017 -0700
+++ b/mercurial/merge.py	Mon Oct 02 14:05:30 2017 -0700
@@ -1263,7 +1263,7 @@
         z += 1
         progress(_updating, z, item=f, total=numupdates, unit=_files)
 
-    # remove in parallel (must come before getting)
+    # remove in parallel (must come before resolving path conflicts and getting)
     prog = worker.worker(repo.ui, 0.001, batchremove, (repo, wctx),
                          actions['r'])
     for i, item in prog:
@@ -1271,6 +1271,18 @@
         progress(_updating, z, item=item, total=numupdates, unit=_files)
     removed = len(actions['r'])
 
+    # resolve path conflicts (must come before getting)
+    for f, args, msg in actions['pr']:
+        repo.ui.debug(" %s: %s -> pr\n" % (f, msg))
+        f0, = args
+        if wctx[f0].lexists():
+            repo.ui.note(_("moving %s to %s\n") % (f0, f))
+            wctx[f].audit()
+            wctx[f].write(wctx.filectx(f0).data(), wctx.filectx(f0).flags())
+            wctx[f0].remove()
+        z += 1
+        progress(_updating, z, item=f, total=numupdates, unit=_files)
+
     # We should flush before forking into worker processes, since those workers
     # flush when they complete, and we don't want to duplicate work.
     wctx.flushall()
@@ -1443,6 +1455,17 @@
     for f, args, msg in actions.get('f', []):
         repo.dirstate.drop(f)
 
+    # resolve path conflicts
+    for f, args, msg in actions.get('pr', []):
+        f0, = args
+        origf0 = repo.dirstate.copied(f0) or f0
+        repo.dirstate.add(f)
+        repo.dirstate.copy(origf0, f)
+        if f0 == origf0:
+            repo.dirstate.remove(f0)
+        else:
+            repo.dirstate.drop(f0)
+
     # re-add
     for f, args, msg in actions.get('a', []):
         repo.dirstate.add(f)
@@ -1678,7 +1701,7 @@
 
         if updatecheck == 'noconflict':
             for f, (m, args, msg) in actionbyfile.iteritems():
-                if m not in ('g', 'k', 'e', 'r'):
+                if m not in ('g', 'k', 'e', 'r', 'pr'):
                     msg = _("conflicting changes")
                     hint = _("commit or update --clean to discard changes")
                     raise error.Abort(msg, hint=hint)
@@ -1714,7 +1737,7 @@
 
         # Convert to dictionary-of-lists format
         actions = dict((m, [])
-                       for m in 'a am f g cd dc r dm dg m e k p'.split())
+                       for m in 'a am f g cd dc r dm dg m e k p pr'.split())
         for f, (m, args, msg) in actionbyfile.iteritems():
             if m not in actions:
                 actions[m] = []
--- a/mercurial/sparse.py	Mon Oct 02 14:05:30 2017 -0700
+++ b/mercurial/sparse.py	Mon Oct 02 14:05:30 2017 -0700
@@ -487,7 +487,7 @@
 
     # Apply changes to disk
     typeactions = dict((m, [])
-                       for m in 'a f g am cd dc r dm dg m e k p'.split())
+                       for m in 'a f g am cd dc r dm dg m e k p pr'.split())
     for f, (m, args, msg) in actions.iteritems():
         if m not in typeactions:
             typeactions[m] = []