@@ -8,7 +8,7 @@
from node import nullid, nullrev, hex, bin
from i18n import _
from mercurial import obsolete
-import error, util, filemerge, copies, subrepo, worker, dicthelpers
+import error, util, filemerge, copies, subrepo, worker, dicthelpers, scmutil
import errno, os, shutil
class mergestate(object):
@@ -138,7 +138,7 @@
return actions
-def _checkcollision(repo, wmf, actions, prompts):
+def _checkcollision(repo, wmf, actions, prompts, casesensitive):
# build provisional merged manifest up
pmmf = set(wmf)
@@ -185,14 +185,36 @@
assert op, m
op(f, None)
- # check case-folding collision in provisional merged manifest
- foldmap = {}
- for f in sorted(pmmf):
- fold = util.normcase(f)
- if fold in foldmap:
- raise util.Abort(_("case-folding collision between %s and %s")
- % (f, foldmap[fold]))
- foldmap[fold] = f
+ if casesensitive:
+ normcase = None
+ def check(f, nf):
+ if nf in dirs:
+ raise util.Abort(_("collision between file %s and "
+ "other directory") % (f))
+ else:
+ normcase = util.normcase
+ foldmap = {}
+ def check(f, nf):
+ if nf in dirs:
+ raise util.Abort(_("collision between file %s and "
+ "other directory") % (f))
+ if nf in foldmap:
+ raise util.Abort(_("case-folding collision between %s and %s")
+ % (f, foldmap[nf]))
+ foldmap[nf] = f
+
+ # check collision in provisional merged manifest
+ if normcase:
+ def normiter():
+ for f in pmmf:
+ yield normcase(f)
+ dirs = scmutil.dirs(normiter())
+ for f in sorted(pmmf):
+ check(f, normcase(f))
+ else:
+ dirs = scmutil.dirs(pmmf)
+ for f in sorted(pmmf):
+ check(f, f)
def manifestmerge(repo, wctx, p2, pa, branchmerge, force, partial,
acceptremote=False):
@@ -350,13 +372,15 @@
raise util.Abort(_("untracked files in working directory differ "
"from files in requested revision"))
- if not util.checkcase(repo.path):
- # check collision between files only in p2 for clean update
- if (not branchmerge and
- (force or not wctx.dirty(missing=True, branch=False))):
- _checkcollision(repo, m2, [], [])
- else:
- _checkcollision(repo, m1, actions, prompts)
+ checkcase = util.checkcase(repo.path)
+ if (not branchmerge and
+ (force or not wctx.dirty(missing=True, branch=False))):
+ if not checkcase:
+ # check is not needed on case sensitive filesystem,
+ # because clean updating should not cause collision
+ _checkcollision(repo, m2, [], [], checkcase)
+ else:
+ _checkcollision(repo, m1, actions, prompts, checkcase)
for f, m in sorted(prompts):
if m == "cd":
@@ -62,7 +62,7 @@
$ hg manifest -r2
back
back/test
-#if symlink
+#if symlink no-icasefs
$ hg update -Cr2
abort: path 'back/test' traverses symbolic link 'back'
[255]
@@ -191,6 +191,29 @@
M x
C A
+Test for issue29: collision between file and directory, of which names
+are different from each other only in the letter case, should be
+detected on case insensitive filesystem.
+
+ $ hg update -q --clean 2
+ $ mkdir X
+ $ echo X/X > X/X
+ $ hg add X/X
+ $ hg commit -m '#5'
+ $ hg manifest -r 5
+ A
+ X/X
+ $ hg manifest -r 3
+ a
+ x
+ $ hg merge 3
+ abort: collision between file x and other directory
+ [255]
+ $ hg update -q --clean 3
+ $ hg merge 5
+ abort: collision between file x and other directory
+ [255]
+
$ cd ..
@@ -173,4 +173,27 @@
$ hg revert -r -2 b
$ hg up -q -- -2
+Test for issue29
+
+ $ hg update -q -C 2
+ $ mkdir c
+ $ echo c/c > c/c
+ $ hg add c/c
+ $ hg ci -m "add c/c"
+ $ hg manifest -r 5
+ a
+ b
+ c/c
+ $ hg manifest -r 3
+ a
+ b
+ c
+ $ hg merge 3
+ abort: collision between file c and other directory
+ [255]
+ $ hg update -q -C 3
+ $ hg merge 5
+ abort: collision between file c and other directory
+ [255]
+
$ cd ..