# HG changeset patch # User Augie Fackler # Date 1230002471 21600 # Node ID 58ae90a65f411f11768b92737ad93101a3b3a35e # Parent 04800fda7af5b21682e5cea2644d3a9c891d4468 push: Improved the rebasing logic for push so that it doesn't break with keeping branch names during rebase. diff --git a/push_cmd.py b/push_cmd.py --- a/push_cmd.py +++ b/push_cmd.py @@ -39,8 +39,16 @@ def push_revisions_to_subversion(ui, rep return 1 base_n = old_ctx.parents()[0].node() old_children = repo[base_n].children() + svnbranch = repo[base_n].branch() + oldtip = base_n + samebranchchildren = [c for c in repo[oldtip].children() if c.branch() == svnbranch + and c.node() in svn_commit_hashes] + while samebranchchildren: + oldtip = samebranchchildren[0].node() + samebranchchildren = [c for c in repo[oldtip].children() if c.branch() == svnbranch + and c.node() in svn_commit_hashes] # 2. Commit oldest revision that needs to be pushed - base_revision = svn_commit_hashes[old_ctx.parents()[0].node()][0] + base_revision = svn_commit_hashes[base_n][0] commit_from_rev(ui, repo, old_ctx, hge, svn_url, base_revision) # 3. Fetch revisions from svn r = fetch_command.fetch_revisions(ui, svn_url, hg_repo_path, @@ -48,16 +56,20 @@ def push_revisions_to_subversion(ui, rep assert not r or r == 0 # 4. Find the new head of the target branch repo = hg.repository(ui, hge.path) - base_c = repo[base_n] - replacement = [c for c in base_c.children() if c not in old_children - and c.branch() == old_ctx.branch()] - assert len(replacement) == 1 + oldtipctx = repo[oldtip] + replacement = [c for c in oldtipctx.children() if c not in old_children + and c.branch() == oldtipctx.branch()] + assert len(replacement) == 1, 'Replacement node came back as: %r' % replacement replacement = replacement[0] # 5. Rebase all children of the currently-pushing rev to the new branch heads = repo.heads(old_ctx.node()) for needs_transplant in heads: + def extrafn(ctx, extra): + if ctx.node() == oldest: + return + extra['branch'] = ctx.branch() hg.clean(repo, needs_transplant) - utility_commands.rebase_commits(ui, repo, hg_repo_path, **opts) + utility_commands.rebase_commits(ui, repo, hg_repo_path, extrafn=extrafn, **opts) repo = hg.repository(ui, hge.path) if needs_transplant in outgoing: hg.clean(repo, repo['tip'].node()) @@ -126,7 +138,7 @@ def _getdirchanges(svn, branchpath, pare deleted.append(d) return added, deleted - + def commit_from_rev(ui, repo, rev_ctx, hg_editor, svn_url, base_revision): """Build and send a commit from Mercurial to Subversion. @@ -140,7 +152,7 @@ def commit_from_rev(ui, repo, rev_ctx, h if parent_branch and parent_branch != 'default': branch_path = 'branches/%s' % parent_branch - addeddirs, deleteddirs = _getdirchanges(svn, branch_path, parent, + addeddirs, deleteddirs = _getdirchanges(svn, branch_path, parent, rev_ctx, rev_ctx.files()) deleteddirs = set(deleteddirs) @@ -221,7 +233,7 @@ def commit_from_rev(ui, repo, rev_ctx, h new_target_files += addeddirs + deleteddirs try: svn.commit(new_target_files, rev_ctx.description(), file_data, - base_revision, set(addeddirs), set(deleteddirs), + base_revision, set(addeddirs), set(deleteddirs), props, newcopies) except core.SubversionException, e: if hasattr(e, 'apr_err') and e.apr_err == 160028: diff --git a/tests/test_push_command.py b/tests/test_push_command.py --- a/tests/test_push_command.py +++ b/tests/test_push_command.py @@ -114,10 +114,48 @@ class PushTests(test_util.TestBase): self.pushrevisions() tip = self.repo['tip'] self.assertNotEqual(tip.node(), old_tip) - self.assertEqual(tip.parents()[0].node(), expected_parent) + self.assertEqual(node.hex(tip.parents()[0].node()), + node.hex(expected_parent)) self.assertEqual(tip['adding_file'].data(), 'foo') self.assertEqual(tip.branch(), 'default') + def test_push_two_revs_different_local_branch(self): + def filectxfn(repo, memctx, path): + return context.memfilectx(path=path, + data=path, + islink=False, + isexec=False, + copied=False) + oldtiphash = self.repo['default'].node() + ctx = context.memctx(self.repo, + (self.repo[0].node(), revlog.nullid, ), + 'automated test', + ['gamma', ], + filectxfn, + 'testy', + '2008-12-21 16:32:00 -0500', + {'branch': 'localbranch', }) + newhash = self.repo.commitctx(ctx) + ctx = context.memctx(self.repo, + (newhash, revlog.nullid), + 'automated test2', + ['delta', ], + filectxfn, + 'testy', + '2008-12-21 16:32:00 -0500', + {'branch': 'localbranch', }) + newhash = self.repo.commitctx(ctx) + repo = self.repo + hg.update(repo, newhash) + push_cmd.push_revisions_to_subversion(ui.ui(), + repo=repo, + svn_url=test_util.fileurl(self.repo_path), + hg_repo_path=self.wc_path) + self.assertEqual(self.repo['tip'].parents()[0].parents()[0].node(), oldtiphash) + self.assertEqual(self.repo['tip'].files(), ['delta', ]) + self.assertEqual(self.repo['tip'].manifest().keys(), + ['alpha', 'beta', 'gamma', 'delta']) + def test_push_two_revs(self): # set up some work for us self.test_push_to_default(commit=False) diff --git a/utility_commands.py b/utility_commands.py --- a/utility_commands.py +++ b/utility_commands.py @@ -78,7 +78,7 @@ def print_parent_revision(ui, repo, hg_r @util.register_subcommand('rebase') -def rebase_commits(ui, repo, hg_repo_path, **opts): +def rebase_commits(ui, repo, hg_repo_path, extrafn=None, **opts): """Rebases current unpushed revisions onto Subversion head This moves a line of development from making its own head to the top of @@ -86,10 +86,12 @@ def rebase_commits(ui, repo, hg_repo_pat rebase on top of the current top of Subversion work, you should probably run 'hg svn pull' before running this. """ - def extrafn(ctx, extra): - """defined here so we can add things easily. - """ - extra['branch'] = ctx.branch() + if extrafn is None: + def extrafn2(ctx, extra): + """defined here so we can add things easily. + """ + extra['branch'] = ctx.branch() + extrafn = extrafn2 hge = hg_delta_editor.HgChangeReceiver(hg_repo_path, ui_=ui) svn_commit_hashes = dict(zip(hge.revmap.itervalues(),