merge: check created file dirs for path conflicts only once (issue5716) stable 4.4.2
authorMark Thomas <mbthomas@fb.com>
Fri, 24 Nov 2017 12:53:58 -0800
branchstable
changeset 35172 a92b9f8e11ba
parent 35171 b85962350bb3
child 35173 b9a0d9aa7a37
merge: check created file dirs for path conflicts only once (issue5716) In large repositories, updates involving the creation of many files check the same directories repeatedly in the wctx manifest. Move these checks out to a separate loop to avoid repeated checks hitting the manifest. Differential Revision: https://phab.mercurial-scm.org/D1226
mercurial/merge.py
--- a/mercurial/merge.py	Fri Nov 24 12:53:58 2017 -0800
+++ b/mercurial/merge.py	Fri Nov 24 12:53:58 2017 -0800
@@ -915,34 +915,21 @@
     # can't be updated to cleanly.
     invalidconflicts = set()
 
+    # The set of directories that contain files that are being created.
+    createdfiledirs = set()
+
     # The set of files deleted by all the actions.
     deletedfiles = set()
 
     for f, (m, args, msg) in actions.items():
         if m in ('c', 'dc', 'm', 'cm'):
             # This action may create a new local file.
+            createdfiledirs.update(util.finddirs(f))
             if mf.hasdir(f):
                 # The file aliases a local directory.  This might be ok if all
                 # the files in the local directory are being deleted.  This
                 # will be checked once we know what all the deleted files are.
                 remoteconflicts.add(f)
-            for p in util.finddirs(f):
-                if p in mf:
-                    if p in mctx:
-                        # The file is in a directory which aliases both a local
-                        # and a remote file.  This is an internal inconsistency
-                        # within the remote manifest.
-                        invalidconflicts.add(p)
-                    else:
-                        # The file is in a directory which aliases a local file.
-                        # We will need to rename the local file.
-                        localconflicts.add(p)
-                if p in actions and actions[p][0] in ('c', 'dc', 'm', 'cm'):
-                    # The file is in a directory which aliases a remote file.
-                    # This is an internal inconsistency within the remote
-                    # manifest.
-                    invalidconflicts.add(p)
-
         # Track the names of all deleted files.
         if m == 'r':
             deletedfiles.add(f)
@@ -954,6 +941,24 @@
             f2, flags = args
             deletedfiles.add(f2)
 
+    # Check all directories that contain created files for path conflicts.
+    for p in createdfiledirs:
+        if p in mf:
+            if p in mctx:
+                # A file is in a directory which aliases both a local
+                # and a remote file.  This is an internal inconsistency
+                # within the remote manifest.
+                invalidconflicts.add(p)
+            else:
+                # A file is in a directory which aliases a local file.
+                # We will need to rename the local file.
+                localconflicts.add(p)
+        if p in actions and actions[p][0] in ('c', 'dc', 'm', 'cm'):
+            # The file is in a directory which aliases a remote file.
+            # This is an internal inconsistency within the remote
+            # manifest.
+            invalidconflicts.add(p)
+
     # Rename all local conflicting files that have not been deleted.
     for p in localconflicts:
         if p not in deletedfiles: