# HG changeset patch # User David Schleimer # Date 1384647419 28800 # Node ID c6f7a8cfeca9fd362b71c36936a35f36b13a34d0 # Parent 28116a204b6a44ad9fd2d2b1decff5a4f371ec39 pull: correctly handle replacing the root of a branch with a non-copied directory Prior to this diff, we would either crash, or continue past the replacement without actually recording the change. This could lead to later failing varify if the state before and after weren't identical. diff --git a/hgsubversion/editor.py b/hgsubversion/editor.py --- a/hgsubversion/editor.py +++ b/hgsubversion/editor.py @@ -401,6 +401,10 @@ class HgEditor(svnwrap.Editor): br_path, branch = self.meta.split_branch_path(path)[:2] if br_path is not None: if not copyfrom_path and not br_path: + # This handles the case where a branch root is + # replaced without copy info. It will show up as a + # deletion and then an add. + self.meta.closebranches.discard(branch) self.current.emptybranches[branch] = True else: self.current.emptybranches[branch] = False diff --git a/hgsubversion/replay.py b/hgsubversion/replay.py --- a/hgsubversion/replay.py +++ b/hgsubversion/replay.py @@ -97,7 +97,8 @@ def _convert_rev(ui, meta, svn, r, tbdel p, b = meta.split_branch_path(f)[:2] if b not in branch_batches: branch_batches[b] = [] - branch_batches[b].append((p, f)) + if p: + branch_batches[b].append((p, f)) closebranches = {} for branch in tbdelta['branches'][1]: @@ -193,13 +194,14 @@ def _convert_rev(ui, meta, svn, r, tbdel continue parent_ctx = meta.repo.changectx(ha) + files = [] def del_all_files(*args): raise IOError(errno.ENOENT, 'deleting all files') - # True here meant nuke all files, shouldn't happen with branch closing - if current.emptybranches[branch]: # pragma: no cover - raise hgutil.Abort('Empty commit to an open branch attempted. ' - 'Please report this issue.') + # True here means nuke all files. This happens when you + # replace a branch root with an empty directory + if current.emptybranches[branch]: + files = meta.repo[ha].files() extra = meta.genextra(rev.revnum, branch) meta.mapbranch(extra) @@ -207,7 +209,7 @@ def _convert_rev(ui, meta, svn, r, tbdel current_ctx = context.memctx(meta.repo, (ha, node.nullid), util.getmessage(ui, rev), - [], + files, del_all_files, meta.authors[rev.author], date, diff --git a/hgsubversion/svnmeta.py b/hgsubversion/svnmeta.py --- a/hgsubversion/svnmeta.py +++ b/hgsubversion/svnmeta.py @@ -490,8 +490,8 @@ class SVNMeta(object): # action of 'D'. We mark the branch as deleted. # 5. It's the parent directory of one or more # already-known branches, so we mark them as deleted. - # 6. It's a branch being replaced by another branch - the - # action will be 'R'. + # 6. It's a branch being replaced by another branch or a new + # directory - the action will be 'R'. fi, br = self.split_branch_path(p)[:2] if fi is not None: if fi == '': @@ -501,15 +501,16 @@ class SVNMeta(object): # Check the replacing source is not an ancestor # branch of the branch being replaced, this # would just be a revert. - cfi, cbr = self.split_branch_path( - paths[p].copyfrom_path, paths[p].copyfrom_rev)[:2] - if cfi == '': - cctx = self.repo[self.get_parent_revision( - paths[p].copyfrom_rev + 1, cbr)] - ctx = self.repo[self.get_parent_revision( - revision.revnum, br)] - if cctx and util.isancestor(ctx, cctx): - continue + if paths[p].copyfrom_path: + cfi, cbr = self.split_branch_path( + paths[p].copyfrom_path, paths[p].copyfrom_rev)[:2] + if cfi == '': + cctx = self.repo[self.get_parent_revision( + paths[p].copyfrom_rev + 1, cbr)] + ctx = self.repo[self.get_parent_revision( + revision.revnum, br)] + if cctx and util.isancestor(ctx, cctx): + continue parent = self._determine_parent_branch( p, paths[p].copyfrom_path, paths[p].copyfrom_rev, revision.revnum)