Show More
@@ -0,0 +1,89 b'' | |||||
|
1 | #!/bin/sh | |||
|
2 | # http://www.selenic.com/mercurial/bts/issue660 | |||
|
3 | ||||
|
4 | ||||
|
5 | hg init a | |||
|
6 | cd a | |||
|
7 | echo a > a | |||
|
8 | mkdir b | |||
|
9 | echo b > b/b | |||
|
10 | hg commit -A -m "a is file, b is dir" | |||
|
11 | ||||
|
12 | echo % file replaced with directory | |||
|
13 | ||||
|
14 | rm a | |||
|
15 | mkdir a | |||
|
16 | echo a > a/a | |||
|
17 | ||||
|
18 | echo % should fail - would corrupt dirstate | |||
|
19 | hg add a/a | |||
|
20 | ||||
|
21 | echo % removing shadow | |||
|
22 | hg rm --after a | |||
|
23 | ||||
|
24 | echo % should succeed - shadow removed | |||
|
25 | hg add a/a | |||
|
26 | ||||
|
27 | echo % directory replaced with file | |||
|
28 | ||||
|
29 | rm -r b | |||
|
30 | echo b > b | |||
|
31 | ||||
|
32 | echo % should fail - would corrupt dirstate | |||
|
33 | hg add b | |||
|
34 | ||||
|
35 | echo % removing shadow | |||
|
36 | hg rm --after b/b | |||
|
37 | ||||
|
38 | echo % should succeed - shadow removed | |||
|
39 | hg add b | |||
|
40 | ||||
|
41 | echo % look what we got | |||
|
42 | hg st | |||
|
43 | ||||
|
44 | echo % revert reintroducing shadow - should fail | |||
|
45 | rm -r a b | |||
|
46 | hg revert b/b | |||
|
47 | ||||
|
48 | echo % revert all - should succeed | |||
|
49 | hg revert --all | |||
|
50 | hg st | |||
|
51 | ||||
|
52 | echo % addremove | |||
|
53 | ||||
|
54 | rm -r a b | |||
|
55 | mkdir a | |||
|
56 | echo a > a/a | |||
|
57 | echo b > b | |||
|
58 | ||||
|
59 | hg addremove | |||
|
60 | hg st | |||
|
61 | ||||
|
62 | echo % commit | |||
|
63 | hg ci -A -m "a is dir, b is file" | |||
|
64 | hg st --all | |||
|
65 | ||||
|
66 | echo % long directory replaced with file | |||
|
67 | ||||
|
68 | mkdir d | |||
|
69 | mkdir d/d | |||
|
70 | echo d > d/d/d | |||
|
71 | hg commit -A -m "d is long directory" | |||
|
72 | rm -r d | |||
|
73 | echo d > d | |||
|
74 | ||||
|
75 | echo % should fail - would corrupt dirstate | |||
|
76 | hg add d | |||
|
77 | ||||
|
78 | echo % removing shadow | |||
|
79 | hg rm --after d/d/d | |||
|
80 | ||||
|
81 | echo % should succeed - shadow removed | |||
|
82 | hg add d | |||
|
83 | ||||
|
84 | #echo % update should work | |||
|
85 | # | |||
|
86 | #hg up -r 0 | |||
|
87 | #hg up -r 1 | |||
|
88 | ||||
|
89 | exit 0 |
@@ -0,0 +1,42 b'' | |||||
|
1 | adding a | |||
|
2 | adding b/b | |||
|
3 | % file replaced with directory | |||
|
4 | % should fail - would corrupt dirstate | |||
|
5 | abort: file 'a' in dirstate clashes with 'a/a' | |||
|
6 | % removing shadow | |||
|
7 | % should succeed - shadow removed | |||
|
8 | % directory replaced with file | |||
|
9 | % should fail - would corrupt dirstate | |||
|
10 | abort: directory 'b' already in dirstate | |||
|
11 | % removing shadow | |||
|
12 | % should succeed - shadow removed | |||
|
13 | % look what we got | |||
|
14 | A a/a | |||
|
15 | A b | |||
|
16 | R a | |||
|
17 | R b/b | |||
|
18 | % revert reintroducing shadow - should fail | |||
|
19 | abort: file 'b' in dirstate clashes with 'b/b' | |||
|
20 | % revert all - should succeed | |||
|
21 | undeleting a | |||
|
22 | forgetting a/a | |||
|
23 | forgetting b | |||
|
24 | undeleting b/b | |||
|
25 | % addremove | |||
|
26 | removing a | |||
|
27 | adding a/a | |||
|
28 | adding b | |||
|
29 | removing b/b | |||
|
30 | A a/a | |||
|
31 | A b | |||
|
32 | R a | |||
|
33 | R b/b | |||
|
34 | % commit | |||
|
35 | C a/a | |||
|
36 | C b | |||
|
37 | % long directory replaced with file | |||
|
38 | adding d/d/d | |||
|
39 | % should fail - would corrupt dirstate | |||
|
40 | abort: directory 'd' already in dirstate | |||
|
41 | % removing shadow | |||
|
42 | % should succeed - shadow removed |
@@ -266,14 +266,15 b' def addremove(repo, pats=[], opts={}, dr' | |||||
266 | mapping[abs] = rel, exact |
|
266 | mapping[abs] = rel, exact | |
267 | if repo.ui.verbose or not exact: |
|
267 | if repo.ui.verbose or not exact: | |
268 | repo.ui.status(_('adding %s\n') % ((pats and rel) or abs)) |
|
268 | repo.ui.status(_('adding %s\n') % ((pats and rel) or abs)) | |
269 |
if repo.dirstate[abs] != 'r' and not util.lexists(target) |
|
269 | if repo.dirstate[abs] != 'r' and (not util.lexists(target) | |
|
270 | or (os.path.isdir(target) and not os.path.islink(target))): | |||
270 | remove.append(abs) |
|
271 | remove.append(abs) | |
271 | mapping[abs] = rel, exact |
|
272 | mapping[abs] = rel, exact | |
272 | if repo.ui.verbose or not exact: |
|
273 | if repo.ui.verbose or not exact: | |
273 | repo.ui.status(_('removing %s\n') % ((pats and rel) or abs)) |
|
274 | repo.ui.status(_('removing %s\n') % ((pats and rel) or abs)) | |
274 | if not dry_run: |
|
275 | if not dry_run: | |
|
276 | repo.remove(remove) | |||
275 | repo.add(add) |
|
277 | repo.add(add) | |
276 | repo.remove(remove) |
|
|||
277 | if similarity > 0: |
|
278 | if similarity > 0: | |
278 | for old, new, score in findrenames(repo, add, remove, similarity): |
|
279 | for old, new, score in findrenames(repo, add, remove, similarity): | |
279 | oldrel, oldexact = mapping[old] |
|
280 | oldrel, oldexact = mapping[old] |
@@ -50,7 +50,8 b' class dirstate(object):' | |||||
50 | elif name == '_dirs': |
|
50 | elif name == '_dirs': | |
51 | self._dirs = {} |
|
51 | self._dirs = {} | |
52 | for f in self._map: |
|
52 | for f in self._map: | |
53 |
self |
|
53 | if self[f] != 'r': | |
|
54 | self._incpath(f) | |||
54 | return self._dirs |
|
55 | return self._dirs | |
55 | elif name == '_ignore': |
|
56 | elif name == '_ignore': | |
56 | files = [self._join('.hgignore')] |
|
57 | files = [self._join('.hgignore')] | |
@@ -205,14 +206,25 b' class dirstate(object):' | |||||
205 | d = f[:c] |
|
206 | d = f[:c] | |
206 | if d in self._dirs: |
|
207 | if d in self._dirs: | |
207 | break |
|
208 | break | |
208 | if d in self._map: |
|
209 | if d in self._map and self[d] != 'r': | |
209 | raise util.Abort(_('file %r in dirstate clashes with %r') % |
|
210 | raise util.Abort(_('file %r in dirstate clashes with %r') % | |
210 | (d, f)) |
|
211 | (d, f)) | |
211 | self._incpath(f) |
|
212 | self._incpath(f) | |
212 |
|
213 | |||
|
214 | def _changepath(self, f, newstate): | |||
|
215 | # handle upcoming path changes | |||
|
216 | oldstate = self[f] | |||
|
217 | if oldstate not in "?r" and newstate in "?r": | |||
|
218 | self._decpath(f) | |||
|
219 | return | |||
|
220 | if oldstate in "?r" and newstate not in "?r": | |||
|
221 | self._incpathcheck(f) | |||
|
222 | return | |||
|
223 | ||||
213 | def normal(self, f): |
|
224 | def normal(self, f): | |
214 | 'mark a file normal and clean' |
|
225 | 'mark a file normal and clean' | |
215 | self._dirty = True |
|
226 | self._dirty = True | |
|
227 | self._changepath(f, 'n') | |||
216 | s = os.lstat(self._join(f)) |
|
228 | s = os.lstat(self._join(f)) | |
217 | self._map[f] = ('n', s.st_mode, s.st_size, s.st_mtime, 0) |
|
229 | self._map[f] = ('n', s.st_mode, s.st_size, s.st_mtime, 0) | |
218 | if self._copymap.has_key(f): |
|
230 | if self._copymap.has_key(f): | |
@@ -221,6 +233,7 b' class dirstate(object):' | |||||
221 | def normallookup(self, f): |
|
233 | def normallookup(self, f): | |
222 | 'mark a file normal, but possibly dirty' |
|
234 | 'mark a file normal, but possibly dirty' | |
223 | self._dirty = True |
|
235 | self._dirty = True | |
|
236 | self._changepath(f, 'n') | |||
224 | self._map[f] = ('n', 0, -1, -1, 0) |
|
237 | self._map[f] = ('n', 0, -1, -1, 0) | |
225 | if f in self._copymap: |
|
238 | if f in self._copymap: | |
226 | del self._copymap[f] |
|
239 | del self._copymap[f] | |
@@ -228,6 +241,7 b' class dirstate(object):' | |||||
228 | def normaldirty(self, f): |
|
241 | def normaldirty(self, f): | |
229 | 'mark a file normal, but dirty' |
|
242 | 'mark a file normal, but dirty' | |
230 | self._dirty = True |
|
243 | self._dirty = True | |
|
244 | self._changepath(f, 'n') | |||
231 | self._map[f] = ('n', 0, -2, -1, 0) |
|
245 | self._map[f] = ('n', 0, -2, -1, 0) | |
232 | if f in self._copymap: |
|
246 | if f in self._copymap: | |
233 | del self._copymap[f] |
|
247 | del self._copymap[f] | |
@@ -235,7 +249,7 b' class dirstate(object):' | |||||
235 | def add(self, f): |
|
249 | def add(self, f): | |
236 | 'mark a file added' |
|
250 | 'mark a file added' | |
237 | self._dirty = True |
|
251 | self._dirty = True | |
238 |
self._ |
|
252 | self._changepath(f, 'a') | |
239 | self._map[f] = ('a', 0, -1, -1, 0) |
|
253 | self._map[f] = ('a', 0, -1, -1, 0) | |
240 | if f in self._copymap: |
|
254 | if f in self._copymap: | |
241 | del self._copymap[f] |
|
255 | del self._copymap[f] | |
@@ -243,8 +257,8 b' class dirstate(object):' | |||||
243 | def remove(self, f): |
|
257 | def remove(self, f): | |
244 | 'mark a file removed' |
|
258 | 'mark a file removed' | |
245 | self._dirty = True |
|
259 | self._dirty = True | |
|
260 | self._changepath(f, 'r') | |||
246 | self._map[f] = ('r', 0, 0, 0, 0) |
|
261 | self._map[f] = ('r', 0, 0, 0, 0) | |
247 | self._decpath(f) |
|
|||
248 | if f in self._copymap: |
|
262 | if f in self._copymap: | |
249 | del self._copymap[f] |
|
263 | del self._copymap[f] | |
250 |
|
264 | |||
@@ -252,6 +266,7 b' class dirstate(object):' | |||||
252 | 'mark a file merged' |
|
266 | 'mark a file merged' | |
253 | self._dirty = True |
|
267 | self._dirty = True | |
254 | s = os.lstat(self._join(f)) |
|
268 | s = os.lstat(self._join(f)) | |
|
269 | self._changepath(f, 'm') | |||
255 | self._map[f] = ('m', s.st_mode, s.st_size, s.st_mtime, 0) |
|
270 | self._map[f] = ('m', s.st_mode, s.st_size, s.st_mtime, 0) | |
256 | if f in self._copymap: |
|
271 | if f in self._copymap: | |
257 | del self._copymap[f] |
|
272 | del self._copymap[f] | |
@@ -260,13 +275,15 b' class dirstate(object):' | |||||
260 | 'forget a file' |
|
275 | 'forget a file' | |
261 | self._dirty = True |
|
276 | self._dirty = True | |
262 | try: |
|
277 | try: | |
|
278 | self._changepath(f, '?') | |||
263 | del self._map[f] |
|
279 | del self._map[f] | |
264 | self._decpath(f) |
|
|||
265 | except KeyError: |
|
280 | except KeyError: | |
266 | self._ui.warn(_("not in dirstate: %s!\n") % f) |
|
281 | self._ui.warn(_("not in dirstate: %s!\n") % f) | |
267 |
|
282 | |||
268 | def clear(self): |
|
283 | def clear(self): | |
269 | self._map = {} |
|
284 | self._map = {} | |
|
285 | if "_dirs" in self.__dict__: | |||
|
286 | delattr(self, "_dirs"); | |||
270 | self._copymap = {} |
|
287 | self._copymap = {} | |
271 | self._pl = [nullid, nullid] |
|
288 | self._pl = [nullid, nullid] | |
272 | self._dirty = True |
|
289 | self._dirty = True | |
@@ -522,7 +539,7 b' class dirstate(object):' | |||||
522 | try: |
|
539 | try: | |
523 | st = lstat(_join(fn)) |
|
540 | st = lstat(_join(fn)) | |
524 | except OSError, inst: |
|
541 | except OSError, inst: | |
525 |
if inst.errno |
|
542 | if inst.errno not in (errno.ENOENT, errno.ENOTDIR): | |
526 | raise |
|
543 | raise | |
527 | st = None |
|
544 | st = None | |
528 | # We need to re-check that it is a valid file |
|
545 | # We need to re-check that it is a valid file |
@@ -720,7 +720,7 b' class path_auditor(object):' | |||||
720 | except OSError, err: |
|
720 | except OSError, err: | |
721 | # EINVAL can be raised as invalid path syntax under win32. |
|
721 | # EINVAL can be raised as invalid path syntax under win32. | |
722 | # They must be ignored for patterns can be checked too. |
|
722 | # They must be ignored for patterns can be checked too. | |
723 | if err.errno not in (errno.ENOENT, errno.EINVAL): |
|
723 | if err.errno not in (errno.ENOENT, errno.ENOTDIR, errno.EINVAL): | |
724 | raise |
|
724 | raise | |
725 | else: |
|
725 | else: | |
726 | if stat.S_ISLNK(st.st_mode): |
|
726 | if stat.S_ISLNK(st.st_mode): |
General Comments 0
You need to be logged in to leave comments.
Login now