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