diff --git a/hgext/convert/subversion.py b/hgext/convert/subversion.py --- a/hgext/convert/subversion.py +++ b/hgext/convert/subversion.py @@ -709,6 +709,13 @@ class svn_source(converter_source): from_revnum, to_revnum = to_revnum, from_revnum self.child_cset = None + + def isdescendantof(parent, child): + if not child or not parent or not child.startswith(parent): + return False + subpath = child[len(parent):] + return len(subpath) > 1 and subpath[0] == '/' + def parselogentry(orig_paths, revnum, author, date, message): """Return the parsed commit object or None, and True if the revision is a branch root. @@ -732,10 +739,21 @@ class svn_source(converter_source): if root_paths: path, ent = root_paths[-1] if ent.copyfrom_path: + # If dir was moved while one of its file was removed + # the log may look like: + # A /dir (from /dir:x) + # A /dir/a (from /dir/a:y) + # A /dir/b (from /dir/b:z) + # ... + # for all remaining children. + # Let's take the highest child element from rev as source. + copies = [(p,e) for p,e in orig_paths[:-1] + if isdescendantof(ent.copyfrom_path, e.copyfrom_path)] + fromrev = max([e.copyfrom_rev for p,e in copies] + [ent.copyfrom_rev]) branched = True newpath = ent.copyfrom_path + self.module[len(path):] # ent.copyfrom_rev may not be the actual last revision - previd = self.latest(newpath, ent.copyfrom_rev) + previd = self.latest(newpath, fromrev) if previd is not None: prevmodule, prevnum = self.revsplit(previd)[1:] if prevnum >= self.startrev: diff --git a/tests/test-convert-svn-branches.out b/tests/test-convert-svn-branches.out --- a/tests/test-convert-svn-branches.out +++ b/tests/test-convert-svn-branches.out @@ -117,8 +117,8 @@ o branch=old3 11 branch trunk@1 into ol | | | | o | branch= 3 change a files: a | | | -+---o branch=old 2 branch trunk, remove c files: a b -| | +| | o branch=old 2 branch trunk, remove c files: +| |/ | o branch= 1 hello files: a b c |/ o branch= 0 init projA files: