merge: refactor unknown file conflict checking
authorMatt Mackall <mpm@selenic.com>
Thu, 09 Feb 2012 16:50:19 -0600
changeset 16093 7e30f5f2285f
parent 16092 914bc95e227b
child 16094 0776a6cababe
merge: refactor unknown file conflict checking Previously, we would do a full working directory walk including unknown files to perform a merge. In many cases, this was painful because unknown files greatly outnumbered tracked files and generally had no useful effect on the merge. Here we instead wait until we find a file in the destination that's not tracked locally and detect if it exists and is not ignored. This is usually cheaper but can be -more- expensive in the case where we're adding a huge number of files. On the other hand, the cost of statting the new files should be dwarfed by the cost of eventually writing them. In this version, case collisions are detected implicitly by os.path.exists and wctx[f] lookup.
hgext/largefiles/overrides.py
hgext/largefiles/uisetup.py
mercurial/merge.py
--- a/hgext/largefiles/overrides.py	Thu Feb 09 13:16:20 2012 -0600
+++ b/hgext/largefiles/overrides.py	Thu Feb 09 16:50:19 2012 -0600
@@ -265,13 +265,10 @@
 # The overridden function filters the unknown files by removing any
 # largefiles. This makes the merge proceed and we can then handle this
 # case further in the overridden manifestmerge function below.
-def override_checkunknown(origfn, wctx, mctx, folding):
-    origunknown = wctx.unknown()
-    wctx._unknown = filter(lambda f: lfutil.standin(f) not in wctx, origunknown)
-    try:
-        return origfn(wctx, mctx, folding)
-    finally:
-        wctx._unknown = origunknown
+def override_checkunknownfile(origfn, repo, wctx, mctx, f):
+    if lfutil.standin(f) in wctx:
+        return False
+    return origfn(repo, wctx, mctx, f)
 
 # The manifest merge handles conflicts on the manifest level. We want
 # to handle changes in largefile-ness of files at this level too.
--- a/hgext/largefiles/uisetup.py	Thu Feb 09 13:16:20 2012 -0600
+++ b/hgext/largefiles/uisetup.py	Thu Feb 09 16:50:19 2012 -0600
@@ -64,8 +64,8 @@
                                    overrides.override_update)
     entry = extensions.wrapcommand(commands.table, 'pull',
                                    overrides.override_pull)
-    entry = extensions.wrapfunction(merge, '_checkunknown',
-                                    overrides.override_checkunknown)
+    entry = extensions.wrapfunction(merge, '_checkunknownfile',
+                                    overrides.override_checkunknownfile)
     entry = extensions.wrapfunction(merge, 'manifestmerge',
                                     overrides.override_manifestmerge)
     entry = extensions.wrapfunction(filemerge, 'filemerge',
--- a/mercurial/merge.py	Thu Feb 09 13:16:20 2012 -0600
+++ b/mercurial/merge.py	Thu Feb 09 16:50:19 2012 -0600
@@ -81,22 +81,19 @@
             self.mark(dfile, 'r')
         return r
 
-def _checkunknown(wctx, mctx, folding):
+def _checkunknownfile(repo, wctx, mctx, f):
+    return (not repo.dirstate._ignore(f)
+        and os.path.exists(repo.wjoin(f))
+        and mctx[f].cmp(wctx[f]))
+
+def _checkunknown(repo, wctx, mctx):
     "check for collisions between unknown files and files in mctx"
-    if folding:
-        foldf = util.normcase
-    else:
-        foldf = lambda fn: fn
-    folded = {}
-    for fn in mctx:
-        folded[foldf(fn)] = fn
 
     error = False
-    for fn in wctx.unknown():
-        f = foldf(fn)
-        if f in folded and mctx[folded[f]].cmp(wctx[f]):
+    for f in mctx:
+        if f not in wctx and _checkunknownfile(repo, wctx, mctx, f):
             error = True
-            wctx._repo.ui.warn(_("%s: untracked file differs\n") % fn)
+            wctx._repo.ui.warn(_("%s: untracked file differs\n") % f)
     if error:
         raise util.Abort(_("untracked files in working directory differ "
                            "from files in requested revision"))
@@ -565,7 +562,7 @@
         wc.status(unknown=True) # prime cache
         folding = not util.checkcase(repo.path)
         if not force:
-            _checkunknown(wc, p2, folding)
+            _checkunknown(repo, wc, p2)
         if folding:
             _checkcollision(p2, branchmerge and p1)
         action += _forgetremoved(wc, p2, branchmerge)