Mercurial > hg
changeset 15270:6cb6064f1d50
rebase: add --rev option to rebase
This option allow a strict set of revision to be specified instead of using -s
or -b. Rebase will refuse start if striping rebased changeset will strip non
rebased changeset. Rebase will refuse to work on set with multiple root.
author | Pierre-Yves David <pierre-yves.david@ens-lyon.org> |
---|---|
date | Sat, 15 Oct 2011 20:12:32 +0200 |
parents | b12362ab13e7 |
children | 84d4a4ce45fd |
files | hgext/rebase.py tests/bundles/rebase-revset.hg tests/test-rebase-parameters.t tests/test-rebase-scenario-global.t |
diffstat | 4 files changed, 269 insertions(+), 8 deletions(-) [+] |
line wrap: on
line diff
--- a/hgext/rebase.py Sat Oct 15 12:57:47 2011 -0500 +++ b/hgext/rebase.py Sat Oct 15 20:12:32 2011 +0200 @@ -15,7 +15,7 @@ ''' from mercurial import hg, util, repair, merge, cmdutil, commands, bookmarks -from mercurial import extensions, patch +from mercurial import extensions, patch, scmutil from mercurial.commands import templateopts from mercurial.node import nullrev from mercurial.lock import release @@ -34,6 +34,9 @@ _('rebase from the base of the specified changeset ' '(up to greatest common ancestor of base and dest)'), _('REV')), + ('r', 'rev', [], + _('rebase these revisions'), + _('REV')), ('d', 'dest', '', _('rebase onto the specified changeset'), _('REV')), ('', 'collapse', False, _('collapse the rebased changesets')), @@ -119,6 +122,7 @@ destf = opts.get('dest', None) srcf = opts.get('source', None) basef = opts.get('base', None) + revf = opts.get('rev', []) contf = opts.get('continue') abortf = opts.get('abort') collapsef = opts.get('collapse', False) @@ -156,7 +160,13 @@ else: if srcf and basef: raise util.Abort(_('cannot specify both a ' + 'source and a base')) + if revf and basef: + raise util.Abort(_('cannot specify both a' 'revision and a base')) + if revf and srcf: + raise util.Abort(_('cannot specify both a' + 'revision and a source')) if detachf: if not srcf: raise util.Abort( @@ -167,24 +177,39 @@ cmdutil.bailifchanged(repo) if not destf: - # Destination defaults to the latest revision in the current branch + # Destination defaults to the latest revision in the + # current branch branch = repo[None].branch() dest = repo[branch] else: dest = repo[destf] + rebaseset = None if srcf: revsetargs = ('(%r)::', srcf) + elif revf: + rebaseset = scmutil.revrange(repo, revf) + if not keepf and rebaseset: + try: + repo.set('children(%ld) - %ld', + rebaseset, rebaseset).next() + except StopIteration: + pass # empty revset is what we look for + else: + msg = _("can't remove original changesets with" + " unrebased descendants") + hint = _('use --keep to keep original changesets') + raise util.Abort(msg, hint=hint) else: base = basef or '.' revsetargs = ('(children(ancestor(%r, %d)) and ::(%r))::', base, dest, base) - - rebaseset = [c.rev() for c in repo.set(*revsetargs)] + if rebaseset is None: + rebaseset = [c.rev() for c in repo.set(*revsetargs)] if rebaseset: result = buildstate(repo, dest, rebaseset, detachf) else: - repo.ui.debug(_('base is ancestor of destination')) + repo.ui.debug('base is ancestor of destination') result = None if not result: # Empty state built, nothing to rebase @@ -545,9 +570,9 @@ detachset = set() roots = list(repo.set('roots(%ld)', rebaseset)) if not roots: - raise util.Abort( _('no matching revisions')) + raise util.Abort(_('no matching revisions')) if len(roots) > 1: - raise util.Abort( _("can't rebase multiple roots")) + raise util.Abort(_("can't rebase multiple roots")) root = roots[0] commonbase = root.ancestor(dest)
--- a/tests/test-rebase-parameters.t Sat Oct 15 12:57:47 2011 -0500 +++ b/tests/test-rebase-parameters.t Sat Oct 15 20:12:32 2011 +0200 @@ -67,7 +67,7 @@ [255] $ hg rebase --base 5 --source 4 - abort: cannot specify both a revision and a base + abort: cannot specify both a source and a base [255] $ hg rebase
--- a/tests/test-rebase-scenario-global.t Sat Oct 15 12:57:47 2011 -0500 +++ b/tests/test-rebase-scenario-global.t Sat Oct 15 20:12:32 2011 +0200 @@ -269,4 +269,240 @@ |/ o 0: 'A' + $ cd .. +Test for revset + +We need a bit different graph +All destination are B + + $ hg init ah + $ cd ah + $ hg unbundle $TESTDIR/bundles/rebase-revset.hg + adding changesets + adding manifests + adding file changes + added 9 changesets with 9 changes to 9 files (+2 heads) + (run 'hg heads' to see heads, 'hg merge' to merge) + $ hg tglog + o 8: 'I' + | + o 7: 'H' + | + o 6: 'G' + | + | o 5: 'F' + | | + | o 4: 'E' + |/ + o 3: 'D' + | + o 2: 'C' + | + | o 1: 'B' + |/ + o 0: 'A' + + $ cd .. + + +Simple case with keep: + +Source on have two descendant heads but ask for one + + $ hg clone -q -u . ah ah1 + $ cd ah1 + $ hg rebase -r '2::8' -d 1 + abort: can't remove original changesets with unrebased descendants + (use --keep to keep original changesets) + [255] + $ hg rebase -r '2::8' -d 1 --keep + $ hg tglog + @ 13: 'I' + | + o 12: 'H' + | + o 11: 'G' + | + o 10: 'D' + | + o 9: 'C' + | + | o 8: 'I' + | | + | o 7: 'H' + | | + | o 6: 'G' + | | + | | o 5: 'F' + | | | + | | o 4: 'E' + | |/ + | o 3: 'D' + | | + | o 2: 'C' + | | + o | 1: 'B' + |/ + o 0: 'A' + + + $ cd .. + +Base on have one descendant heads we ask for but common ancestor have two + + $ hg clone -q -u . ah ah2 + $ cd ah2 + $ hg rebase -r '3::8' -d 1 + abort: can't remove original changesets with unrebased descendants + (use --keep to keep original changesets) + [255] + $ hg rebase -r '3::8' -d 1 --keep + $ hg tglog + @ 12: 'I' + | + o 11: 'H' + | + o 10: 'G' + | + o 9: 'D' + |\ + | | o 8: 'I' + | | | + | | o 7: 'H' + | | | + | | o 6: 'G' + | | | + | | | o 5: 'F' + | | | | + | | | o 4: 'E' + | | |/ + | | o 3: 'D' + | |/ + | o 2: 'C' + | | + o | 1: 'B' + |/ + o 0: 'A' + + + $ cd .. + +rebase subset + + $ hg clone -q -u . ah ah3 + $ cd ah3 + $ hg rebase -r '3::7' -d 1 + abort: can't remove original changesets with unrebased descendants + (use --keep to keep original changesets) + [255] + $ hg rebase -r '3::7' -d 1 --keep + $ hg tglog + @ 11: 'H' + | + o 10: 'G' + | + o 9: 'D' + |\ + | | o 8: 'I' + | | | + | | o 7: 'H' + | | | + | | o 6: 'G' + | | | + | | | o 5: 'F' + | | | | + | | | o 4: 'E' + | | |/ + | | o 3: 'D' + | |/ + | o 2: 'C' + | | + o | 1: 'B' + |/ + o 0: 'A' + + + $ cd .. + +rebase subset with multiple head + + $ hg clone -q -u . ah ah4 + $ cd ah4 + $ hg rebase -r '3::(7+5)' -d 1 + abort: can't remove original changesets with unrebased descendants + (use --keep to keep original changesets) + [255] + $ hg rebase -r '3::(7+5)' -d 1 --keep + $ hg tglog + @ 13: 'H' + | + o 12: 'G' + | + | o 11: 'F' + | | + | o 10: 'E' + |/ + o 9: 'D' + |\ + | | o 8: 'I' + | | | + | | o 7: 'H' + | | | + | | o 6: 'G' + | | | + | | | o 5: 'F' + | | | | + | | | o 4: 'E' + | | |/ + | | o 3: 'D' + | |/ + | o 2: 'C' + | | + o | 1: 'B' + |/ + o 0: 'A' + + + $ cd .. + +More advanced tests + +rebase on ancestor with revset + + $ hg clone -q -u . ah ah5 + $ cd ah5 + $ hg rebase -r '6::' -d 2 + saved backup bundle to $TESTTMP/ah5/.hg/strip-backup/3d8a618087a7-backup.hg + $ hg tglog + @ 8: 'I' + | + o 7: 'H' + | + o 6: 'G' + | + | o 5: 'F' + | | + | o 4: 'E' + | | + | o 3: 'D' + |/ + o 2: 'C' + | + | o 1: 'B' + |/ + o 0: 'A' + + $ cd .. + + +rebase with multiple root. +We rebase E and G on B +We would expect heads are I, F if it was supported + + $ hg clone -q -u . ah ah6 + $ cd ah6 + $ hg rebase -r '(4+6)::' -d 1 + abort: can't rebase multiple roots + [255] + $ cd ..