--- a/hgext/convert/__init__.py Mon Nov 05 08:41:22 2007 +0100
+++ b/hgext/convert/__init__.py Mon Nov 05 13:20:24 2007 -0800
@@ -344,7 +344,7 @@
The 'include' directive causes a file, or all files under a
directory, to be included in the destination repository, and the
- exclussion of all other files and dirs not explicitely included.
+ exclusion of all other files and dirs not explicitely included.
The 'exclude' directive causes files or directories to be omitted.
The 'rename' directive renames a file or directory. To rename from a
subdirectory into the root of the repository, use '.' as the path to
--- a/mercurial/cmdutil.py Mon Nov 05 08:41:22 2007 +0100
+++ b/mercurial/cmdutil.py Mon Nov 05 13:20:24 2007 -0800
@@ -266,14 +266,15 @@
mapping[abs] = rel, exact
if repo.ui.verbose or not exact:
repo.ui.status(_('adding %s\n') % ((pats and rel) or abs))
- if repo.dirstate[abs] != 'r' and not util.lexists(target):
+ if repo.dirstate[abs] != 'r' and (not util.lexists(target)
+ or (os.path.isdir(target) and not os.path.islink(target))):
remove.append(abs)
mapping[abs] = rel, exact
if repo.ui.verbose or not exact:
repo.ui.status(_('removing %s\n') % ((pats and rel) or abs))
if not dry_run:
+ repo.remove(remove)
repo.add(add)
- repo.remove(remove)
if similarity > 0:
for old, new, score in findrenames(repo, add, remove, similarity):
oldrel, oldexact = mapping[old]
--- a/mercurial/dirstate.py Mon Nov 05 08:41:22 2007 +0100
+++ b/mercurial/dirstate.py Mon Nov 05 13:20:24 2007 -0800
@@ -50,7 +50,8 @@
elif name == '_dirs':
self._dirs = {}
for f in self._map:
- self._incpath(f)
+ if self[f] != 'r':
+ self._incpath(f)
return self._dirs
elif name == '_ignore':
files = [self._join('.hgignore')]
@@ -205,14 +206,25 @@
d = f[:c]
if d in self._dirs:
break
- if d in self._map:
+ if d in self._map and self[d] != 'r':
raise util.Abort(_('file %r in dirstate clashes with %r') %
(d, f))
self._incpath(f)
+ def _changepath(self, f, newstate):
+ # handle upcoming path changes
+ oldstate = self[f]
+ if oldstate not in "?r" and newstate in "?r":
+ self._decpath(f)
+ return
+ if oldstate in "?r" and newstate not in "?r":
+ self._incpathcheck(f)
+ return
+
def normal(self, f):
'mark a file normal and clean'
self._dirty = True
+ self._changepath(f, 'n')
s = os.lstat(self._join(f))
self._map[f] = ('n', s.st_mode, s.st_size, s.st_mtime, 0)
if self._copymap.has_key(f):
@@ -221,6 +233,7 @@
def normallookup(self, f):
'mark a file normal, but possibly dirty'
self._dirty = True
+ self._changepath(f, 'n')
self._map[f] = ('n', 0, -1, -1, 0)
if f in self._copymap:
del self._copymap[f]
@@ -228,6 +241,7 @@
def normaldirty(self, f):
'mark a file normal, but dirty'
self._dirty = True
+ self._changepath(f, 'n')
self._map[f] = ('n', 0, -2, -1, 0)
if f in self._copymap:
del self._copymap[f]
@@ -235,7 +249,7 @@
def add(self, f):
'mark a file added'
self._dirty = True
- self._incpathcheck(f)
+ self._changepath(f, 'a')
self._map[f] = ('a', 0, -1, -1, 0)
if f in self._copymap:
del self._copymap[f]
@@ -243,8 +257,8 @@
def remove(self, f):
'mark a file removed'
self._dirty = True
+ self._changepath(f, 'r')
self._map[f] = ('r', 0, 0, 0, 0)
- self._decpath(f)
if f in self._copymap:
del self._copymap[f]
@@ -252,6 +266,7 @@
'mark a file merged'
self._dirty = True
s = os.lstat(self._join(f))
+ self._changepath(f, 'm')
self._map[f] = ('m', s.st_mode, s.st_size, s.st_mtime, 0)
if f in self._copymap:
del self._copymap[f]
@@ -260,13 +275,15 @@
'forget a file'
self._dirty = True
try:
+ self._changepath(f, '?')
del self._map[f]
- self._decpath(f)
except KeyError:
self._ui.warn(_("not in dirstate: %s!\n") % f)
def clear(self):
self._map = {}
+ if "_dirs" in self.__dict__:
+ delattr(self, "_dirs");
self._copymap = {}
self._pl = [nullid, nullid]
self._dirty = True
@@ -522,7 +539,7 @@
try:
st = lstat(_join(fn))
except OSError, inst:
- if inst.errno != errno.ENOENT:
+ if inst.errno not in (errno.ENOENT, errno.ENOTDIR):
raise
st = None
# We need to re-check that it is a valid file
--- a/mercurial/merge.py Mon Nov 05 08:41:22 2007 +0100
+++ b/mercurial/merge.py Mon Nov 05 13:20:24 2007 -0800
@@ -401,7 +401,10 @@
act("update permissions", "e", f, m2.flags(f))
# contents same, check mode bits
elif m1.flags(f) != m2.flags(f):
- if overwrite or fmerge(f) != m1.flags(f):
+ # are we clobbering?
+ # is remote's version newer?
+ # or are we going back?
+ if overwrite or fmerge(f) != m1.flags(f) or backwards:
act("update permissions", "e", f, m2.flags(f))
elif f in copied:
continue
--- a/mercurial/util.py Mon Nov 05 08:41:22 2007 +0100
+++ b/mercurial/util.py Mon Nov 05 13:20:24 2007 -0800
@@ -720,7 +720,7 @@
except OSError, err:
# EINVAL can be raised as invalid path syntax under win32.
# They must be ignored for patterns can be checked too.
- if err.errno not in (errno.ENOENT, errno.EINVAL):
+ if err.errno not in (errno.ENOENT, errno.ENOTDIR, errno.EINVAL):
raise
else:
if stat.S_ISLNK(st.st_mode):
--- a/tests/test-convert.out Mon Nov 05 08:41:22 2007 +0100
+++ b/tests/test-convert.out Mon Nov 05 13:20:24 2007 -0800
@@ -3,6 +3,7 @@
Convert a foreign SCM repository to a Mercurial one.
Accepted source formats:
+ - Mercurial
- CVS
- Darcs
- git
@@ -19,8 +20,8 @@
basename of the source with '-hg' appended. If the destination
repository doesn't exist, it will be created.
- If <revmapfile> isn't given, it will be put in a default location
- (<dest>/.hg/shamap by default). The <revmapfile> is a simple text
+ If <MAPFILE> isn't given, it will be put in a default location
+ (<dest>/.hg/shamap by default). The <MAPFILE> is a simple text
file that maps each source commit ID to the destination ID for
that revision, like so:
<source ID> <destination ID>
@@ -46,11 +47,12 @@
rename from/file to/file
The 'include' directive causes a file, or all files under a
- directory, to be included in the destination repository. The
- 'exclude' directive causes files or directories to be omitted.
- The 'rename' directive renames a file or directory. To rename
- from a subdirectory into the root of the repository, use '.' as
- the path to rename to.
+ directory, to be included in the destination repository, and the
+ exclusion of all other files and dirs not explicitely included.
+ The 'exclude' directive causes files or directories to be omitted.
+ The 'rename' directive renames a file or directory. To rename from a
+ subdirectory into the root of the repository, use '.' as the path to
+ rename to.
options:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-issue660 Mon Nov 05 13:20:24 2007 -0800
@@ -0,0 +1,89 @@
+#!/bin/sh
+# http://www.selenic.com/mercurial/bts/issue660
+
+
+hg init a
+cd a
+echo a > a
+mkdir b
+echo b > b/b
+hg commit -A -m "a is file, b is dir"
+
+echo % file replaced with directory
+
+rm a
+mkdir a
+echo a > a/a
+
+echo % should fail - would corrupt dirstate
+hg add a/a
+
+echo % removing shadow
+hg rm --after a
+
+echo % should succeed - shadow removed
+hg add a/a
+
+echo % directory replaced with file
+
+rm -r b
+echo b > b
+
+echo % should fail - would corrupt dirstate
+hg add b
+
+echo % removing shadow
+hg rm --after b/b
+
+echo % should succeed - shadow removed
+hg add b
+
+echo % look what we got
+hg st
+
+echo % revert reintroducing shadow - should fail
+rm -r a b
+hg revert b/b
+
+echo % revert all - should succeed
+hg revert --all
+hg st
+
+echo % addremove
+
+rm -r a b
+mkdir a
+echo a > a/a
+echo b > b
+
+hg addremove
+hg st
+
+echo % commit
+hg ci -A -m "a is dir, b is file"
+hg st --all
+
+echo % long directory replaced with file
+
+mkdir d
+mkdir d/d
+echo d > d/d/d
+hg commit -A -m "d is long directory"
+rm -r d
+echo d > d
+
+echo % should fail - would corrupt dirstate
+hg add d
+
+echo % removing shadow
+hg rm --after d/d/d
+
+echo % should succeed - shadow removed
+hg add d
+
+#echo % update should work
+#
+#hg up -r 0
+#hg up -r 1
+
+exit 0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-issue660.out Mon Nov 05 13:20:24 2007 -0800
@@ -0,0 +1,42 @@
+adding a
+adding b/b
+% file replaced with directory
+% should fail - would corrupt dirstate
+abort: file 'a' in dirstate clashes with 'a/a'
+% removing shadow
+% should succeed - shadow removed
+% directory replaced with file
+% should fail - would corrupt dirstate
+abort: directory 'b' already in dirstate
+% removing shadow
+% should succeed - shadow removed
+% look what we got
+A a/a
+A b
+R a
+R b/b
+% revert reintroducing shadow - should fail
+abort: file 'b' in dirstate clashes with 'b/b'
+% revert all - should succeed
+undeleting a
+forgetting a/a
+forgetting b
+undeleting b/b
+% addremove
+removing a
+adding a/a
+adding b
+removing b/b
+A a/a
+A b
+R a
+R b/b
+% commit
+C a/a
+C b
+% long directory replaced with file
+adding d/d/d
+% should fail - would corrupt dirstate
+abort: directory 'd' already in dirstate
+% removing shadow
+% should succeed - shadow removed