# HG changeset patch # User Pierre-Yves David # Date 2011-10-15 18:12:32 # Node ID 6cb6064f1d50c9bdb2371f6dd3fb323ef5e5051c # Parent b12362ab13e7af92ca17fb717dc308f44196ea5b 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. diff --git a/hgext/rebase.py b/hgext/rebase.py --- a/hgext/rebase.py +++ b/hgext/rebase.py @@ -15,7 +15,7 @@ http://mercurial.selenic.com/wiki/Rebase ''' 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 @@ command = cmdutil.command(cmdtable) _('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 @@ def rebase(ui, repo, **opts): 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 @@ def rebase(ui, repo, **opts): 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 @@ def rebase(ui, repo, **opts): 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 @@ def buildstate(repo, dest, rebaseset, de 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) diff --git a/tests/bundles/rebase-revset.hg b/tests/bundles/rebase-revset.hg new file mode 100644 index 0000000000000000000000000000000000000000..2a016a38aab1229a00cbd1425942c67a02c9a98c GIT binary patch literal 1844 zc$@(=2g~?KM=>x$T4*^jL0KkKSxR?b#sC0pfB*mg+kgN6|NsC0|NsC0|NsBn|KH2^ z|9}7g{r~>%bG6U~yTcOz8rgu1l_4calTD~?A*ZO&$Qm>TnI52IXaEC7jR47@^)xg9 zXvw2PKmZJbK=e%j00w}`pa3xjhD{AJJwyNi8UO$Q007CL0B8UJ0002N8X6h^00000 z01X-d0001J4GbE9XbGbzQ&2PjGyv0000T#;Gy#)CMw$Qs(8-_ypa3)t0MktdgFqSp z27mwopa4Js0iXZ?000b{00w{n0000C5uu@=00000007aT00006fY8AuNlz4do{v*O zG-4VLQ$PdM$OAwCXa<4l13)x105Jg2&}aYv0000qXa<1OKnBzXgC>WV2j(-n-fu^i z%kIwU+D?1g_p~#`FU^{3cc$aqi88`Kvupv33A|KE7J;$>y9a?3WLgZ#Fj$7-BiPW6!=`$XEg(~Al<0_vihQmv zMa!9NNm6B&ty;Bfsd{~@u=L^C|2YET1Z#C%k<21sht|`^hYhNi`=V0LB6Lg&mH@>c zRBlV^If|SrZva~y(TYrwoih`4EYpcMwV(oFl%u|#F zG9TuRXW>^SX@x>~0?2|zfyhKv)n(#ymk8ZesssL1eDRjB8R6;F6%Uy$c1vsy8Gp#H14( zcs+_cAjSo*BWIaI9w&<=T63!6o;j*6%tcDMGp5LxG@p6`6$)8^v2vTF#)%v+AQbkkgz3bJg(|L75=yr5 zZY-H>PZ(PeliJxOhrx5Eb>TsfYZ((ILI#sWoT6qSl|{g!H}P(e8W5cieW(EmxFv@d z9&A!h8z?YMn^JE@54A_5n6{=B^u|=eOPpDAZd)@30s?HA$>5t;&aQ5T{yNL*S9ie9&;GRGWyoFukAKK4H1ZliyUE>Fzx{n5p0GSb%bIO!-ozWPlNg!H*Vd& z^Sz}-ITe$47)^^px8V5{BzDhyi1d2DM9lAiDy_4qlfEIKHy2=AmDdxm$Yy^?!6t}t zxJSYKsGy*srk?xT3F)0%IxUr5rET0cpRS^gg`6#B?)?`9*cN9t6E8=1f`$I1=#3OpUHns3^AvW%_Fb5tpKqHE2IQ+o8?`B=RxSQwocz%cTO&}ko^ z8xQboPIGcF)<6TO)%P%v1)>kNs`BFGhaSMM8GzK&d}3N|cG}Zk&%BOgl86|14rGI$^+eJ*NQVc!x5@-ft3fzT3EaZN674d0O}4QV7H+#GSQGl3l5uw) z(qWIvJ4lc=<&3BgK>~}xD@(f^l_mQZ&X7AV#BhD#p|Z@dPVUg*pG8njtTb7f?lI9e zEA1RXgVp{y5O7TzLCS5>*+oDs^g)0yR0w#B!RpQi-o)baOzy%8CwebrSb32&F9|;_ z7kh|xNDpg8PN0K)qC-N6M$rTZK@8{ufR`e+D7X&<_%kY|p(q9PI3?t^MxuB>%7|N0 zT*X5TtP4y(T@^z-Dv+c@Dx*jxSd$x0qx-^R;wa$H%$Tb_B_H6I#5yDCD1zEW6Ti^3 i%A$xhR+3w2FY&?9Mr7(gtnqHY;_gVN3K9uU>-fMt$~1)l diff --git a/tests/test-rebase-parameters.t b/tests/test-rebase-parameters.t --- a/tests/test-rebase-parameters.t +++ b/tests/test-rebase-parameters.t @@ -67,7 +67,7 @@ These fail: [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 diff --git a/tests/test-rebase-scenario-global.t b/tests/test-rebase-scenario-global.t --- a/tests/test-rebase-scenario-global.t +++ b/tests/test-rebase-scenario-global.t @@ -269,4 +269,240 @@ C onto A - rebase onto an ancestor: |/ 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 ..