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
--- 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: