# HG changeset patch # User Matt Mackall # Date 2012-02-09 22:50:19 # Node ID 7e30f5f2285f09fa28bdcc3228a3d0fc7c7906db # Parent 914bc95e227bf4328f72c7c13bf80f01f942266c 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. diff --git a/hgext/largefiles/overrides.py b/hgext/largefiles/overrides.py --- a/hgext/largefiles/overrides.py +++ b/hgext/largefiles/overrides.py @@ -265,13 +265,10 @@ def override_update(orig, ui, repo, *pat # 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. diff --git a/hgext/largefiles/uisetup.py b/hgext/largefiles/uisetup.py --- a/hgext/largefiles/uisetup.py +++ b/hgext/largefiles/uisetup.py @@ -64,8 +64,8 @@ def uisetup(ui): 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', diff --git a/mercurial/merge.py b/mercurial/merge.py --- a/mercurial/merge.py +++ b/mercurial/merge.py @@ -81,22 +81,19 @@ class mergestate(object): 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 @@ def update(repo, node, branchmerge, forc 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)