[PATCH 1 of 1] rebase: add a --rev option to rebase
Matt Mackall
mpm at selenic.com
Sat Oct 15 09:24:16 CDT 2011
On Wed, 2011-10-12 at 23:42 +0200, Pierre-Yves David wrote:
> # HG changeset patch
> # User Pierre-Yves David <pierre-yves.david at ens-lyon.org>
> # Date 1318455664 -7200
> # Node ID 4fae86ab22887c43473df899dd27a93d9fadb247
> # Parent b7a59f645f0e67bd424b0e9ceef1f8f6ffa7900d
> rebase: add a --rev option to rebase
>
> This option allows to specify a strict subset of changeset to rebase.
> Rebase will fail if the revset contains ancestors of destination. Only
> changeset in the set will be rebased not their descendants. Using revset
> in rebase implies two new cases to handle:
> - rebasing revset with multiple head,
> - changeset rebased without they descendant and no --keep option.
> Later commit are dedicated to handle them properly.
This looks promising.
We probably need to warn about any changesets we would normally strip
but can't because they have unrebased ancestors.
> diff --git a/hg b/hg
> --- a/hg
> +++ b/hg
> @@ -36,3 +36,4 @@
> mercurial.util.setbinary(fp)
>
> mercurial.dispatch.run()
> +
???
> diff --git a/hgext/rebase.py b/hgext/rebase.py
> --- a/hgext/rebase.py
> +++ b/hgext/rebase.py
> @@ -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
> @@ -36,6 +36,8 @@
> _('REV')),
> ('d', 'dest', '',
> _('rebase onto the specified changeset'), _('REV')),
> + ('r', 'rev', [],
> + _('rebase the specified revision only'), _('REV')),
> ('', 'collapse', False, _('collapse the rebased changesets')),
> ('m', 'message', '',
> _('use text as collapse commit message'), _('TEXT')),
> @@ -119,6 +121,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)
> @@ -143,7 +146,7 @@
> _('cannot use collapse with continue or abort'))
> if detachf:
> raise util.Abort(_('cannot use detach with continue or abort'))
> - if srcf or basef or destf:
> + if srcf or basef or destf or revf:
> raise util.Abort(
> _('abort and continue do not allow specifying revisions'))
> if opts.get('tool', False):
> @@ -157,6 +160,12 @@
> if srcf and basef:
> raise util.Abort(_('cannot specify both a '
> 'revision and a base'))
s/revision/source/
> + if revf and basef:
> + raise util.Abort(_('cannot specify both a'
> + 'revset and a base'))
s/revset/revision/
> + if revf and srcf:
> + raise util.Abort(_('cannot specify both a'
> + 'revset and a source revision'))
> if detachf:
> if not srcf:
> raise util.Abort(
> @@ -164,8 +173,15 @@
> if basef:
> raise util.Abort(_('cannot specify a base with detach'))
>
> + if revf:
> + revs = [int(c) for c in scmutil.revrange(repo, revf)]
> + if not revs:
> + raise util.Abort( _('empty revset'))
'no matching revisions'
> + else:
> + revs = None
> +
> cmdutil.bailifchanged(repo)
> - result = buildstate(repo, destf, srcf, basef, detachf)
> + result = buildstate(repo, destf, srcf, basef, detachf, revs)
So.. to do this right, we should convert the whole thing to revset-based
logic. That is, at the earliest point, we take all of our flags that
specify which changesets to rebase and calculate a revset from them.
Then only pass around that set, rather than track all the incompatible
flags and do further special-case logic on them. This will make the code
simpler than it was when you started.
So before we even get here, we should calculate the set for --source or
--base.. and get rid of those options in the rest of the code. The
buildstate function should only get revs.
> if not result:
> # Empty state built, nothing to rebase
> ui.status(_('nothing to rebase\n'))
> @@ -507,7 +523,7 @@
> repo.ui.warn(_('rebase aborted\n'))
> return 0
>
> -def buildstate(repo, dest, src, base, detach):
> +def buildstate(repo, dest, src, base, detach, revs=None):
> 'Define which revisions are going to be rebased and where'
> targetancestors = set()
> detachset = set()
> @@ -526,7 +542,9 @@
> [s.node for s in repo.mq.applied]):
> raise util.Abort(_('cannot rebase onto an applied mq patch'))
>
> - if src:
> + if src or revs:
> + if not src:
> + src = min(revs)
..and this whole clause goes away.
> commonbase = repo[src].ancestor(repo[dest])
> if commonbase == repo[src]:
> raise util.Abort(_('source is ancestor of destination'))
> @@ -543,6 +561,7 @@
> baseancestors = set(repo.changelog.ancestors(commonbase.rev()))
> detachset = srcancestors - baseancestors
> detachset.discard(commonbase.rev())
> +
?
> else:
> if base:
> cwd = repo[base].rev()
> @@ -568,7 +587,9 @@
> source = min(rebasingbranch)
>
> repo.ui.debug('rebase onto %d starting from %d\n' % (dest, source))
> - state = dict.fromkeys(repo.changelog.descendants(source), nullrev)
> + if revs is None:
> + revs = repo.changelog.descendants(source)
And so does this.
> + state = dict.fromkeys(revs, nullrev)
> state.update(dict.fromkeys(detachset, nullmerge))
> state[source] = nullrev
> return repo['.'].rev(), repo[dest].rev(), state
> 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$aq<fb at XzbT&3d4QXhz`|#Mh7v|}1`;hGLq@={izXdT
> zu)|icwGbj;p2$c&diFyg1uO|rAZqT~fd)gxI%WaWEWkRhKtk4H5CT&y2`E-ypV at 4X
> z<$;&>i88`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(TYrwo<qHWSj?)QnO^-UT=6Z at J$q&>ih`4EYpcMwV(oFl%u|#F
> zG9TuRXW>^SX at x>~0?2|zfyh<Gt}}wU24M_|^6dOf2p;#~C*6v2Nvg`u3#^PoP%bxD
> zTm6|R#;pbbX+`p_JG*&>Kv)n(#ymk8ZesssL1eDRjB8R6;F6%Uy$c1vsy8Gp#H14(
> zcs+_cAjSo*BWIaI9w&<=T<e=Dqa~UEY;?UzRZ5UmW?&I37!U)Nbm~@xLZo+Mv?BuG
> z3=oURWrr4CWU&z`ur1VqIX1>63!6o;j*6%tcD<wDFhPj!Fb6|W^D024VKBfwWQGMQ
> z;T2v~XsxuuR=&cx&4R>MGp5LxG at p6`6$)8^v2vTF#)%v+AQbkkgz3bJg(|L75=yr5
> zZY-H>PZ(PeliJxOhrx5Eb>TsfYZ((ILI#sWoT6qSl|{g!H}P(e8W5cieW(EmxFv at d
> z9&A!h8z?YMn^JE at 54A_5n6{=B^u|=eOPpDAZd)@30s?HA$>5t;&aQ<i9S8|hlp at BZ
> z5<280i8vHVvVbs+kHUE#f(w!z+{O}n*tG+-uVtM!zmd<FV>5T{y<y%V92hM)s at _Y!
> z{SdwiBK{)6g5rHHIHBujf$S#HISGLyWwILPTc}mp`6*Jw#4XK^YUiT(RbE)DJa3vb
> z)t>NL*S9ie9&;GRGWyoFukAKK4H1ZliyUE>Fzx{n5p0GSb%bIO!-ozWPlNg!H*Vd&
> z^Sz}-ITe$47)^^px8V5{BzDhyi1d2DM9lAiDy_4qlfEIKHy2=AmDdxm$Yy^?!6t}t
> zxJS<oA>YKsGy*srk?xT3F)0%IxUr5rET0cpRS^gg`6#B?)?`9*c<Ye0qYHw`?5I1L
> ziflr0so`L9k<{|kPn<qv!V?)yt at hm0&2=cqOzkyEQ3*SqEv%hH22M{RTk}Q-F#QFx
> zohc`#Ru$5Zk5|W|5KGh>N<m^(y4!sd3-OA{RRu8lDrE0^i9OkC6F_si#$yFa$GUYF
> zJ{DM-MT*r5py~l+qm|2Dk<D}I92lM9THksJZ@{}}TjWA8WNAuSB)N@)tb^1~QxN#n
> z>9t6E8=1f`$I1=#3OpUHns3^AvW%_Fb5tpKqHE2IQ+o8?`B=RxSQwocz%cTO&}ko^
> z8xQboPIGcF)<6TO)%P%v1)>kNs`BFG<e!{n at 6598$HV-XB|(+2ugwR`WGcbtTSIUT
> z!u9)`o>haSMM8<X68rRXm(?8<GsIIInlv_vMJgQ8*@(K at AlDY-(7@;*6k;b!bZDDT
> zqO24z%!46Yc|%}taAM&_vvUtahFT(R95HKkEhEeB5S>GzK&d}3N|cG}Zk&%<aC1lf
> z4>BOgl86|14rGI$^+eJ*NQVc!x5 at -ft3fzT3EaZN674d0O}4QV7H+#GSQGl3l5uw)
> z(qWIvJ4lc=<&3BgK>~}xD@(f^l_mQZ&X7AV#BhD#p|Z at dPVUg*pG8njtTb7f?lI9e
> zEA1RXgVp{y5O7TzLCS5>*+oDs^g)0yR0w#B!RpQi-o)baOzy%8CwebrSb32&F9|;_
> z7kh|xNDpg8PN0K)qC-N6M$rTZK at 8{ufR`e+D7X&<_%kY|p(q9PI3?t^MxuB>%7|N0
> zT*X5TtP4y(T@^z-Dv+c at 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-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,212 @@
> |/
> 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 --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 --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 --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 --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 test
> +
> +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'
> +
> +
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel at selenic.com
> http://selenic.com/mailman/listinfo/mercurial-devel
--
Mathematics is the supreme nostalgia of our time.
More information about the Mercurial-devel
mailing list