##// END OF EJS Templates
dirstate: preserve path components case on renames (issue3402)...
Patrick Mezard -
r16542:e596a631 stable
parent child Browse files
Show More
@@ -268,6 +268,11 b' def copy(ui, repo, pats, opts, rename=Fa'
268 # otarget: ossep
268 # otarget: ossep
269 def copyfile(abssrc, relsrc, otarget, exact):
269 def copyfile(abssrc, relsrc, otarget, exact):
270 abstarget = scmutil.canonpath(repo.root, cwd, otarget)
270 abstarget = scmutil.canonpath(repo.root, cwd, otarget)
271 if '/' in abstarget:
272 # We cannot normalize abstarget itself, this would prevent
273 # case only renames, like a => A.
274 abspath, absname = abstarget.rsplit('/', 1)
275 abstarget = repo.dirstate.normalize(abspath) + '/' + absname
271 reltarget = repo.pathto(abstarget, cwd)
276 reltarget = repo.pathto(abstarget, cwd)
272 target = repo.wjoin(abstarget)
277 target = repo.wjoin(abstarget)
273 src = repo.wjoin(abssrc)
278 src = repo.wjoin(abssrc)
@@ -408,32 +408,48 b' class dirstate(object):'
408 self._droppath(f)
408 self._droppath(f)
409 del self._map[f]
409 del self._map[f]
410
410
411 def _normalize(self, path, isknown):
411 def _normalize(self, path, isknown, ignoremissing=False, exists=None):
412 normed = util.normcase(path)
412 normed = util.normcase(path)
413 folded = self._foldmap.get(normed, None)
413 folded = self._foldmap.get(normed, None)
414 if folded is None:
414 if folded is None:
415 if isknown or not os.path.lexists(os.path.join(self._root, path)):
415 if isknown:
416 folded = path
416 folded = path
417 else:
417 else:
418 # recursively normalize leading directory components
418 if exists is None:
419 # against dirstate
419 exists = os.path.lexists(os.path.join(self._root, path))
420 if '/' in normed:
420 if not exists:
421 d, f = normed.rsplit('/', 1)
421 # Maybe a path component exists
422 d = self._normalize(d, isknown)
422 if not ignoremissing and '/' in path:
423 r = self._root + "/" + d
423 d, f = path.rsplit('/', 1)
424 folded = d + "/" + util.fspath(f, r)
424 d = self._normalize(d, isknown, ignoremissing, None)
425 folded = d + "/" + f
426 else:
427 # No path components, preserve original case
428 folded = path
425 else:
429 else:
426 folded = util.fspath(normed, self._root)
430 # recursively normalize leading directory components
427 self._foldmap[normed] = folded
431 # against dirstate
432 if '/' in normed:
433 d, f = normed.rsplit('/', 1)
434 d = self._normalize(d, isknown, ignoremissing, True)
435 r = self._root + "/" + d
436 folded = d + "/" + util.fspath(f, r)
437 else:
438 folded = util.fspath(normed, self._root)
439 self._foldmap[normed] = folded
428
440
429 return folded
441 return folded
430
442
431 def normalize(self, path, isknown=False):
443 def normalize(self, path, isknown=False, ignoremissing=False):
432 '''
444 '''
433 normalize the case of a pathname when on a casefolding filesystem
445 normalize the case of a pathname when on a casefolding filesystem
434
446
435 isknown specifies whether the filename came from walking the
447 isknown specifies whether the filename came from walking the
436 disk, to avoid extra filesystem access
448 disk, to avoid extra filesystem access.
449
450 If ignoremissing is True, missing path are returned
451 unchanged. Otherwise, we try harder to normalize possibly
452 existing path components.
437
453
438 The normalized case is determined based on the following precedence:
454 The normalized case is determined based on the following precedence:
439
455
@@ -443,7 +459,7 b' class dirstate(object):'
443 '''
459 '''
444
460
445 if self._checkcase:
461 if self._checkcase:
446 return self._normalize(path, isknown)
462 return self._normalize(path, isknown, ignoremissing)
447 return path
463 return path
448
464
449 def clear(self):
465 def clear(self):
@@ -575,7 +591,7 b' class dirstate(object):'
575 normalize = self._normalize
591 normalize = self._normalize
576 skipstep3 = False
592 skipstep3 = False
577 else:
593 else:
578 normalize = lambda x, y: x
594 normalize = lambda x, y, z: x
579
595
580 files = sorted(match.files())
596 files = sorted(match.files())
581 subrepos.sort()
597 subrepos.sort()
@@ -596,7 +612,7 b' class dirstate(object):'
596
612
597 # step 1: find all explicit files
613 # step 1: find all explicit files
598 for ff in files:
614 for ff in files:
599 nf = normalize(normpath(ff), False)
615 nf = normalize(normpath(ff), False, True)
600 if nf in results:
616 if nf in results:
601 continue
617 continue
602
618
@@ -646,7 +662,7 b' class dirstate(object):'
646 continue
662 continue
647 raise
663 raise
648 for f, kind, st in entries:
664 for f, kind, st in entries:
649 nf = normalize(nd and (nd + "/" + f) or f, True)
665 nf = normalize(nd and (nd + "/" + f) or f, True, True)
650 if nf not in results:
666 if nf not in results:
651 if kind == dirkind:
667 if kind == dirkind:
652 if not ignore(nf):
668 if not ignore(nf):
@@ -32,6 +32,42 b' Case-changing renames should work:'
32 $ hg mv a A
32 $ hg mv a A
33 $ hg mv A a
33 $ hg mv A a
34 $ hg st
34 $ hg st
35
36 test changing case of path components
37
38 $ mkdir D
39 $ echo b > D/b
40 $ hg ci -Am addb D/b
41 $ hg mv D/b d/b
42 D/b: not overwriting - file exists
43 $ hg mv D/b d/c
44 $ hg st
45 A D/c
46 R D/b
47 $ mv D temp
48 $ mv temp d
49 $ hg st
50 A D/c
51 R D/b
52 $ hg revert -aq
53 $ rm d/c
54 $ echo c > D/c
55 $ hg add D/c
56 $ hg st
57 A D/c
58 $ hg ci -m addc D/c
59 $ hg mv d/b d/e
60 moving D/b to D/e
61 $ hg st
62 A D/e
63 R D/b
64 $ hg revert -aq
65 $ rm d/e
66 $ hg mv d/b D/B
67 moving D/b to D/B
68 $ hg st
69 A D/B
70 R D/b
35 $ cd ..
71 $ cd ..
36
72
37 test case collision between revisions (issue912)
73 test case collision between revisions (issue912)
General Comments 0
You need to be logged in to leave comments. Login now