diff -r 38fe86fb16e3 -r 66d954e76ffb hgext/rebase.py --- a/hgext/rebase.py Sun Jan 31 13:30:17 2010 +0100 +++ b/hgext/rebase.py Sat Feb 06 10:51:50 2010 +0100 @@ -22,6 +22,8 @@ from mercurial.i18n import _ import os, errno +nullmerge = -2 + def rebase(ui, repo, **opts): """move changeset (and descendants) to a different branch @@ -53,6 +55,7 @@ extrafn = opts.get('extrafn') keepf = opts.get('keep', False) keepbranchesf = opts.get('keepbranches', False) + detachf = opts.get('detach', False) if contf or abortf: if contf and abortf: @@ -62,6 +65,10 @@ raise error.ParseError( 'rebase', _('cannot use collapse with continue or abort')) + if detachf: + raise error.ParseError( + 'rebase', _('cannot use detach with continue or abort')) + if srcf or basef or destf: raise error.ParseError('rebase', _('abort and continue do not allow specifying revisions')) @@ -75,8 +82,16 @@ if srcf and basef: raise error.ParseError('rebase', _('cannot specify both a ' 'revision and a base')) + if detachf: + if not srcf: + raise error.ParseError( + 'rebase', _('detach requires a revision to be specified')) + if basef: + raise error.ParseError( + 'rebase', _('cannot specify a base with detach')) + cmdutil.bail_if_changed(repo) - result = buildstate(repo, destf, srcf, basef) + result = buildstate(repo, destf, srcf, basef, detachf) if not result: # Empty state built, nothing to rebase ui.status(_('nothing to rebase\n')) @@ -140,10 +155,10 @@ state, targetancestors) commitmsg = 'Collapsed revision' for rebased in state: - if rebased not in skipped: + if rebased not in skipped and state[rebased] != nullmerge: commitmsg += '\n* %s' % repo[rebased].description() commitmsg = ui.edit(commitmsg, repo.ui.username()) - concludenode(repo, rev, p1, external, commitmsg=commitmsg, + newrev = concludenode(repo, rev, p1, external, commitmsg=commitmsg, extra=extrafn) if 'qtip' in repo.tags(): @@ -151,11 +166,13 @@ if not keepf: # Remove no more useful revisions - if set(repo.changelog.descendants(min(state))) - set(state): - ui.warn(_("warning: new changesets detected on source branch, " - "not stripping\n")) - else: - repair.strip(ui, repo, repo[min(state)].node(), "strip") + rebased = [rev for rev in state if state[rev] != nullmerge] + if rebased: + if set(repo.changelog.descendants(min(rebased))) - set(state): + ui.warn(_("warning: new changesets detected on source branch, " + "not stripping\n")) + else: + repair.strip(ui, repo, repo[min(rebased)].node(), "strip") clearstatus(repo) ui.status(_("rebase completed\n")) @@ -260,7 +277,10 @@ if P1n in targetancestors: p1 = target elif P1n in state: - p1 = state[P1n] + if state[P1n] == nullmerge: + p1 = target + else: + p1 = state[P1n] else: # P1n external p1 = target p2 = P1n @@ -379,9 +399,10 @@ clearstatus(repo) repo.ui.status(_('rebase aborted\n')) -def buildstate(repo, dest, src, base): +def buildstate(repo, dest, src, base, detach): 'Define which revisions are going to be rebased and where' targetancestors = set() + detachset = set() if not dest: # Destination defaults to the latest revision in the current branch @@ -400,6 +421,12 @@ if commonbase == repo[dest]: raise util.Abort(_('source is descendant of destination')) source = repo[src].rev() + if detach: + # We need to keep track of source's ancestors up to the common base + srcancestors = set(repo.changelog.ancestors(source)) + baseancestors = set(repo.changelog.ancestors(commonbase.rev())) + detachset = srcancestors - baseancestors + detachset.remove(commonbase.rev()) else: if base: cwd = repo[base].rev() @@ -426,6 +453,7 @@ repo.ui.debug('rebase onto %d starting from %d\n' % (dest, source)) state = dict.fromkeys(repo.changelog.descendants(source), nullrev) + state.update(dict.fromkeys(detachset, nullmerge)) state[source] = nullrev return repo['.'].rev(), repo[dest].rev(), state @@ -468,9 +496,11 @@ ('', 'collapse', False, _('collapse the rebased changesets')), ('', 'keep', False, _('keep original changesets')), ('', 'keepbranches', False, _('keep original branch names')), + ('', 'detach', False, _('force detaching of source from its original ' + 'branch')), ('c', 'continue', False, _('continue an interrupted rebase')), ('a', 'abort', False, _('abort an interrupted rebase')),] + templateopts, - _('hg rebase [-s REV | -b REV] [-d REV] [--collapse] [--keep] ' - '[--keepbranches] | [-c] | [-a]')), + _('hg rebase [-s REV | -b REV] [-d REV] [--collapse] [--detach] ' + '[--keep] [--keepbranches] | [-c] | [-a]')), }