Mercurial > hg
changeset 6906:808f03f61ebe
Add rebase extension
author | Stefano Tortarolo <stefano.tortarolo@gmail.com> |
---|---|
date | Mon, 18 Aug 2008 21:16:31 +0200 |
parents | 248e54a9456e |
children | 6dcbe191a9b5 |
files | hgext/rebase.py tests/test-rebase-abort tests/test-rebase-abort.out tests/test-rebase-collapse tests/test-rebase-collapse.out tests/test-rebase-conflicts tests/test-rebase-conflicts.out tests/test-rebase-interruptions tests/test-rebase-interruptions.out tests/test-rebase-issue-noparam-single-rev tests/test-rebase-issue-noparam-single-rev.out tests/test-rebase-mq tests/test-rebase-mq-skip tests/test-rebase-mq-skip.out tests/test-rebase-mq.out tests/test-rebase-parameters tests/test-rebase-parameters.out tests/test-rebase-pull tests/test-rebase-pull.out tests/test-rebase-scenario-global tests/test-rebase-scenario-global.out |
diffstat | 21 files changed, 1892 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hgext/rebase.py Mon Aug 18 21:16:31 2008 +0200 @@ -0,0 +1,401 @@ +# rebase.py - rebasing feature for mercurial +# +# Copyright 2008 Stefano Tortarolo <stefano.tortarolo at gmail dot com> +# +# This software may be used and distributed according to the terms +# of the GNU General Public License, incorporated herein by reference. + +''' Rebasing feature + +This extension lets you rebase changesets in an existing Mercurial repository. + +For more information: +http://www.selenic.com/mercurial/wiki/index.cgi/RebaseProject +''' + +from mercurial import util, repair, merge, cmdutil, dispatch, commands +from mercurial.commands import templateopts +from mercurial.node import nullrev +from mercurial.i18n import _ +import os, errno + +def rebase(ui, repo, **opts): + """move changeset (and descendants) to a different branch + + Rebase uses repeated merging to graft changesets from one part of history + onto another. This can be useful for linearizing local changes relative to + a master development tree. + + If a rebase is interrupted to manually resolve a merge, it can be continued + with --continue or aborted with --abort. + """ + originalwd = target = source = None + external = nullrev + state = skipped = {} + + lock = wlock = None + try: + lock = repo.lock() + wlock = repo.wlock() + + # Validate input and define rebasing points + destf = opts.get('dest', None) + srcf = opts.get('source', None) + basef = opts.get('base', None) + contf = opts.get('continue') + abortf = opts.get('abort') + collapsef = opts.get('collapse', False) + if contf or abortf: + if contf and abortf: + raise dispatch.ParseError('rebase', + _('cannot use both abort and continue')) + if collapsef: + raise dispatch.ParseError('rebase', + _('cannot use collapse with continue or abort')) + + if (srcf or basef or destf): + raise dispatch.ParseError('rebase', + _('abort and continue do not allow specifying revisions')) + + originalwd, target, state, collapsef, external = restorestatus(repo) + if abortf: + abort(repo, originalwd, target, state) + return + else: + if srcf and basef: + raise dispatch.ParseError('rebase', _('cannot specify both a ' + 'revision and a base')) + cmdutil.bail_if_changed(repo) + result = buildstate(repo, destf, srcf, basef, collapsef) + if result: + originalwd, target, state, external = result + else: # Empty state built, nothing to rebase + repo.ui.status(_('nothing to rebase\n')) + return + + # Rebase + targetancestors = list(repo.changelog.ancestors(target)) + targetancestors.append(target) + + for rev in util.sort(state): + if state[rev] == -1: + storestatus(repo, originalwd, target, state, collapsef, + external) + rebasenode(repo, rev, target, state, skipped, targetancestors, + collapsef) + ui.note(_('rebase merging completed\n')) + + if collapsef: + p1, p2 = defineparents(repo, min(state), target, + state, targetancestors) + concludenode(repo, rev, p1, external, state, collapsef, + last=True, skipped=skipped) + + if 'qtip' in repo.tags(): + updatemq(repo, state, skipped, **opts) + + if not opts.get('keep'): + # Remove no more useful revisions + if (util.set(repo.changelog.descendants(min(state))) + - util.set(state.keys())): + ui.warn(_("warning: new changesets detected on source branch, " + "not stripping\n")) + else: + repair.strip(repo.ui, repo, repo[min(state)].node(), "strip") + + clearstatus(repo) + ui.status(_("rebase completed\n")) + if skipped: + ui.note(_("%d revisions have been skipped\n") % len(skipped)) + finally: + del lock, wlock + +def concludenode(repo, rev, p1, p2, state, collapse, last=False, skipped={}): + """Skip commit if collapsing has been required and rev is not the last + revision, commit otherwise + """ + repo.dirstate.setparents(repo[p1].node(), repo[p2].node()) + + if collapse and not last: + return None + + # Commit, record the old nodeid + m, a, r = repo.status()[:3] + newrev = nullrev + try: + if last: + commitmsg = 'Collapsed revision' + for rebased in state: + if rebased not in skipped: + commitmsg += '\n* %s' % repo[rebased].description() + commitmsg = repo.ui.edit(commitmsg, repo.ui.username()) + else: + commitmsg = repo[rev].description() + # Commit might fail if unresolved files exist + newrev = repo.commit(m+a+r, + text=commitmsg, + user=repo[rev].user(), + date=repo[rev].date(), + extra={'rebase_source': repo[rev].hex()}) + return newrev + except util.Abort: + # Invalidate the previous setparents + repo.dirstate.invalidate() + raise + +def rebasenode(repo, rev, target, state, skipped, targetancestors, collapse): + 'Rebase a single revision' + repo.ui.debug(_("rebasing %d:%s\n") % (rev, repo[rev].node())) + + p1, p2 = defineparents(repo, rev, target, state, targetancestors) + + # Merge phase + if len(repo.parents()) != 2: + # Update to target and merge it with local + merge.update(repo, p1, False, True, False) + repo.dirstate.write() + stats = merge.update(repo, rev, True, False, False) + + if stats[3] > 0: + raise util.Abort(_('fix unresolved conflicts with hg resolve then ' + 'run hg rebase --continue')) + else: # we have an interrupted rebase + repo.ui.debug(_('resuming interrupted rebase\n')) + + + newrev = concludenode(repo, rev, p1, p2, state, collapse) + + # Update the state + if newrev is not None: + state[rev] = repo[newrev].rev() + else: + if not collapse: + repo.ui.note('no changes, revision %d skipped\n' % rev) + repo.ui.debug('next revision set to %s\n' % p1) + skipped[rev] = True + state[rev] = p1 + +def defineparents(repo, rev, target, state, targetancestors): + 'Return the new parent relationship of the revision that will be rebased' + parents = repo[rev].parents() + p1 = p2 = nullrev + + P1n = parents[0].rev() + if P1n in targetancestors: + p1 = target + elif P1n in state: + p1 = state[P1n] + else: # P1n external + p1 = target + p2 = P1n + + if len(parents) == 2 and parents[1].rev() not in targetancestors: + P2n = parents[1].rev() + # interesting second parent + if P2n in state: + if p1 == target: # P1n in targetancestors or external + p1 = state[P2n] + else: + p2 = state[P2n] + else: # P2n external + if p2 != nullrev: # P1n external too => rev is a merged revision + raise util.Abort(_('cannot use revision %d as base, result ' + 'would have 3 parents') % rev) + p2 = P2n + return p1, p2 + +def updatemq(repo, state, skipped, **opts): + 'Update rebased mq patches - finalize and then import them' + mqrebase = {} + for p in repo.mq.applied: + if repo[p.rev].rev() in state: + repo.ui.debug('revision %d is an mq patch (%s), finalize it.\n' % + (repo[p.rev].rev(), p.name)) + mqrebase[repo[p.rev].rev()] = p.name + + if mqrebase: + repo.mq.finish(repo, mqrebase.keys()) + + # We must start import from the newest revision + mq = mqrebase.keys() + mq.sort() + mq.reverse() + for rev in mq: + if rev not in skipped: + repo.ui.debug('import mq patch %d (%s)\n' % (state[rev], + mqrebase[rev])) + repo.mq.qimport(repo, (), patchname=mqrebase[rev], + git=opts.get('git', False),rev=[str(state[rev])]) + repo.mq.save_dirty() + +def storestatus(repo, originalwd, target, state, collapse, external): + 'Store the current status to allow recovery' + f = repo.opener("rebasestate", "w") + f.write(repo[originalwd].hex() + '\n') + f.write(repo[target].hex() + '\n') + f.write(repo[external].hex() + '\n') + f.write('%d\n' % int(collapse)) + for d, v in state.items(): + oldrev = repo[d].hex() + newrev = repo[v].hex() + f.write("%s:%s\n" % (oldrev, newrev)) + f.close() + repo.ui.debug(_('rebase status stored\n')) + +def clearstatus(repo): + 'Remove the status files' + if os.path.exists(repo.join("rebasestate")): + util.unlink(repo.join("rebasestate")) + +def restorestatus(repo): + 'Restore a previously stored status' + try: + target = None + collapse = False + external = nullrev + state = {} + f = repo.opener("rebasestate") + for i, l in enumerate(f.read().splitlines()): + if i == 0: + originalwd = repo[l].rev() + elif i == 1: + target = repo[l].rev() + elif i == 2: + external = repo[l].rev() + elif i == 3: + collapse = bool(int(l)) + else: + oldrev, newrev = l.split(':') + state[repo[oldrev].rev()] = repo[newrev].rev() + repo.ui.debug(_('rebase status resumed\n')) + return originalwd, target, state, collapse, external + except IOError, err: + if err.errno != errno.ENOENT: + raise + raise util.Abort(_('no rebase in progress')) + +def abort(repo, originalwd, target, state): + 'Restore the repository to its original state' + if util.set(repo.changelog.descendants(target)) - util.set(state.values()): + repo.ui.warn(_("warning: new changesets detected on target branch, " + "not stripping\n")) + else: + # Strip from the first rebased revision + merge.update(repo, repo[originalwd].rev(), False, True, False) + rebased = filter(lambda x: x > -1, state.values()) + if rebased: + strippoint = min(rebased) + repair.strip(repo.ui, repo, repo[strippoint].node(), "strip") + clearstatus(repo) + repo.ui.status(_('rebase aborted\n')) + +def buildstate(repo, dest, src, base, collapse): + 'Define which revisions are going to be rebased and where' + state = {} + targetancestors = util.set() + + if not dest: + # Destination defaults to the latest revision in the current branch + branch = repo[None].branch() + dest = repo[branch].rev() + else: + if 'qtip' in repo.tags() and (repo[dest].hex() in + [s.rev for s in repo.mq.applied]): + raise util.Abort(_('cannot rebase onto an applied mq patch')) + dest = repo[dest].rev() + + if src: + commonbase = repo[src].ancestor(repo[dest]) + if commonbase == repo[src]: + raise util.Abort(_('cannot rebase an ancestor')) + if commonbase == repo[dest]: + raise util.Abort(_('cannot rebase a descendant')) + source = repo[src].rev() + else: + if base: + cwd = repo[base].rev() + else: + cwd = repo['.'].rev() + + if cwd == dest: + repo.ui.debug(_('already working on current\n')) + return None + + targetancestors = util.set(repo.changelog.ancestors(dest)) + if cwd in targetancestors: + repo.ui.debug(_('already working on the current branch\n')) + return None + + cwdancestors = util.set(repo.changelog.ancestors(cwd)) + cwdancestors.add(cwd) + rebasingbranch = cwdancestors - targetancestors + source = min(rebasingbranch) + + repo.ui.debug(_('rebase onto %d starting from %d\n') % (dest, source)) + state = dict.fromkeys(repo.changelog.descendants(source), nullrev) + external = nullrev + if collapse: + if not targetancestors: + targetancestors = util.set(repo.changelog.ancestors(dest)) + for rev in state: + # Check externals and fail if there are more than one + for p in repo[rev].parents(): + if (p.rev() not in state and p.rev() != source + and p.rev() not in targetancestors): + if external != nullrev: + raise util.Abort(_('unable to collapse, there is more ' + 'than one external parent')) + external = p.rev() + + state[source] = nullrev + return repo['.'].rev(), repo[dest].rev(), state, external + +def pulldelegate(pullfunction, repo, *args, **opts): + 'Call rebase after pull if the latter has been invoked with --rebase' + if opts.get('rebase'): + if opts.get('update'): + raise util.Abort(_('--update and --rebase are not compatible')) + + cmdutil.bail_if_changed(repo) + revsprepull = len(repo) + pullfunction(repo.ui, repo, *args, **opts) + revspostpull = len(repo) + if revspostpull > revsprepull: + rebase(repo.ui, repo, **opts) + else: + pullfunction(repo.ui, repo, *args, **opts) + +def uisetup(ui): + 'Replace pull with a decorator to provide --rebase option' + # cribbed from color.py + aliases, entry = cmdutil.findcmd(ui, 'pull', commands.table) + for candidatekey, candidateentry in commands.table.iteritems(): + if candidateentry is entry: + cmdkey, cmdentry = candidatekey, entry + break + + decorator = lambda ui, repo, *args, **opts: \ + pulldelegate(cmdentry[0], repo, *args, **opts) + # make sure 'hg help cmd' still works + decorator.__doc__ = cmdentry[0].__doc__ + decoratorentry = (decorator,) + cmdentry[1:] + rebaseopt = ('', 'rebase', None, + _("rebase working directory to branch head")) + decoratorentry[1].append(rebaseopt) + commands.table[cmdkey] = decoratorentry + +cmdtable = { +"rebase": + (rebase, + [ + ('', 'keep', False, _('keep original revisions')), + ('s', 'source', '', _('rebase from a given revision')), + ('b', 'base', '', _('rebase from the base of a given revision')), + ('d', 'dest', '', _('rebase onto a given revision')), + ('', 'collapse', False, _('collapse the rebased revisions')), + ('c', 'continue', False, _('continue an interrupted rebase')), + ('a', 'abort', False, _('abort an interrupted rebase')),] + + templateopts, + _('hg rebase [-s rev | -b rev] [-d rev] [--collapse] | [-c] | [-a] | ' + '[--keep]')), +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-rebase-abort Mon Aug 18 21:16:31 2008 +0200 @@ -0,0 +1,44 @@ +#!/bin/sh + +echo "[extensions]" >> $HGRCPATH +echo "graphlog=" >> $HGRCPATH +echo "rebase=" >> $HGRCPATH + +function cleanoutput { + sed -e 's/\(Rebase status stored to\).*/\1/' \ + -e 's/\(Rebase status restored from\).*/\1/' \ + -e 's/\(saving bundle to \).*/\1/' +} + +hg init a +cd a +echo 'c1' >common +hg add common +hg commit -d '0 0' -u test -m "C1" + +echo 'c2' >>common +hg commit -d '1 0' -u test -m "C2" + +echo 'c3' >>common +hg commit -d '2 0' -u test -m "C3" + +hg update -C 1 +echo 'l1' >>extra +hg add extra +hg commit -d '3 0' -u test -m "L1" + +sed -e 's/c2/l2/' common > common.new +mv common.new common +hg commit -d '4 0' -u test -m "L2" + +hg glog --template '{rev}: {desc}\n' + +echo +echo '% Conflicting rebase' +hg rebase -s 3 -d 2 2>&1 | cleanoutput + +echo +echo '% Abort' +hg rebase --abort 2>&1 | cleanoutput + +hg glog --template '{rev}: {desc}\n'
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-rebase-abort.out Mon Aug 18 21:16:31 2008 +0200 @@ -0,0 +1,31 @@ +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +created new head +@ 4: L2 +| +o 3: L1 +| +| o 2: C3 +|/ +o 1: C2 +| +o 0: C1 + + +% Conflicting rebase +merging common +warning: conflicts during merge. +merging common failed! +abort: fix unresolved conflicts with hg resolve then run hg rebase --continue + +% Abort +rebase aborted +@ 4: L2 +| +o 3: L1 +| +| o 2: C3 +|/ +o 1: C2 +| +o 0: C1 +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-rebase-collapse Mon Aug 18 21:16:31 2008 +0200 @@ -0,0 +1,90 @@ +#!/bin/sh + +echo "[extensions]" >> $HGRCPATH +echo "graphlog=" >> $HGRCPATH +echo "rebase=" >> $HGRCPATH + +BASE=`pwd` + +function addcommit { + echo $1 > $1 + hg add $1 + hg commit -d "${2} 0" -u test -m $1 +} +function commit { + hg commit -d "${2} 0" -u test -m $1 +} + +function createrepo { + cd $BASE + rm -rf a + hg init a + cd a + addcommit "A" 0 + addcommit "B" 1 + addcommit "C" 2 + addcommit "D" 3 + + hg update -C 0 + addcommit "E" 4 + + hg update -C 0 + addcommit "F" 5 + + hg merge -r 4 + commit "G" 6 + + hg update -C 5 + addcommit "H" 7 +} + +createrepo > /dev/null 2>&1 +hg glog --template '{rev}: {desc}\n' +echo '% Rebasing' +hg up -C 3 +hg rebase --collapse 2>&1 | sed 's/\(saving bundle to \).*/\1/' +hg glog --template '{rev}: {desc}\n' + +createrepo > /dev/null 2>&1 +echo '% Rebasing' +hg rebase --base 6 --collapse 2>&1 | sed 's/\(saving bundle to \).*/\1/' +hg glog --template '{rev}: {desc}\n' + +function createrepocomplex { + cd $BASE + rm -rf a + hg init a + cd a + addcommit "A" 0 + addcommit "B" 1 + + hg up 0 + addcommit "C" 2 + hg merge + commit "D" 3 + + hg up 1 + addcommit "E" 4 + + addcommit "F" 5 + + hg merge + commit "G" 6 + + hg up 0 + addcommit "H" 7 +} + +createrepocomplex > /dev/null 2>&1 +hg glog --template '{rev}: {desc}\n' + +echo +echo '% Rebase and collapse - more than one external (fail)' +hg rebase -s 2 --collapse + +echo +echo '% Rebase and collapse' +hg rebase -s 4 --collapse 2>&1 | sed 's/\(saving bundle to \).*/\1/' +hg glog --template '{rev}: {desc}\n' + +exit 0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-rebase-collapse.out Mon Aug 18 21:16:31 2008 +0200 @@ -0,0 +1,104 @@ +@ 7: H +| +| o 6: G +|/| +o | 5: F +| | +| o 4: E +|/ +| o 3: D +| | +| o 2: C +| | +| o 1: B +|/ +o 0: A + +% Rebasing +3 files updated, 0 files merged, 2 files removed, 0 files unresolved +saving bundle to +adding branch +adding changesets +adding manifests +adding file changes +added 5 changesets with 6 changes to 6 files (+1 heads) +rebase completed +@ 5: Collapsed revision +| * B +| * C +| * D +o 4: H +| +| o 3: G +|/| +o | 2: F +| | +| o 1: E +|/ +o 0: A + +% Rebasing +saving bundle to +adding branch +adding changesets +adding manifests +adding file changes +added 3 changesets with 3 changes to 3 files (+1 heads) +rebase completed +@ 6: Collapsed revision +| * E +| * G +o 5: H +| +o 4: F +| +| o 3: D +| | +| o 2: C +| | +| o 1: B +|/ +o 0: A + +@ 7: H +| +| o 6: G +| |\ +| | o 5: F +| | | +| | o 4: E +| | | +| o | 3: D +| |\| +| o | 2: C +|/ / +| o 1: B +|/ +o 0: A + + +% Rebase and collapse - more than one external (fail) +abort: unable to collapse, there is more than one external parent + +% Rebase and collapse +saving bundle to +adding branch +adding changesets +adding manifests +adding file changes +added 2 changesets with 3 changes to 3 files +rebase completed +@ 5: Collapsed revision +|\ * E +| | * F +| | * G +| o 4: H +| | +o | 3: D +|\ \ +| o | 2: C +| |/ +o / 1: B +|/ +o 0: A +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-rebase-conflicts Mon Aug 18 21:16:31 2008 +0200 @@ -0,0 +1,55 @@ +#!/bin/sh + +echo "[extensions]" >> $HGRCPATH +echo "graphlog=" >> $HGRCPATH +echo "rebase=" >> $HGRCPATH + +function cleanoutput { + sed -e 's/\(Rebase status stored to\).*/\1/' \ + -e 's/\(Rebase status restored from\).*/\1/' \ + -e 's/\(saving bundle to \).*/\1/' +} + +hg init a +cd a +echo 'c1' >common +hg add common +hg commit -d '0 0' -u test -m "C1" + +echo 'c2' >>common +hg commit -d '1 0' -u test -m "C2" + +echo 'c3' >>common +hg commit -d '2 0' -u test -m "C3" + +hg update -C 1 +echo 'l1' >>extra +hg add extra +hg commit -d '3 0' -u test -m "L1" + +sed -e 's/c2/l2/' common > common.new +mv common.new common +hg commit -d '4 0' -u test -m "L2" + +hg glog --template '{rev}: {desc}\n' + +echo +echo '% Try to call --continue' +hg rebase --continue + +echo +echo '% Conflicting rebase' +hg rebase -s 3 -d 2 + +echo +echo '% Try to continue without solving the conflict' +hg rebase --continue + +echo +echo '% Conclude rebase' +echo 'solved merge' >common +hg resolve -m common +hg rebase --continue 2>&1 | cleanoutput + + +hg glog --template '{rev}: {desc}\n'
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-rebase-conflicts.out Mon Aug 18 21:16:31 2008 +0200 @@ -0,0 +1,43 @@ +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +created new head +@ 4: L2 +| +o 3: L1 +| +| o 2: C3 +|/ +o 1: C2 +| +o 0: C1 + + +% Try to call --continue +abort: no rebase in progress + +% Conflicting rebase +merging common +warning: conflicts during merge. +merging common failed! +abort: fix unresolved conflicts with hg resolve then run hg rebase --continue + +% Try to continue without solving the conflict +abort: unresolved merge conflicts (see hg resolve) + +% Conclude rebase +saving bundle to +adding branch +adding changesets +adding manifests +adding file changes +added 2 changesets with 2 changes to 2 files +rebase completed +@ 4: L2 +| +o 3: L1 +| +o 2: C3 +| +o 1: C2 +| +o 0: C1 +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-rebase-interruptions Mon Aug 18 21:16:31 2008 +0200 @@ -0,0 +1,81 @@ +#!/bin/sh + +echo "[extensions]" >> $HGRCPATH +echo "graphlog=" >> $HGRCPATH +echo "rebase=" >> $HGRCPATH + +BASE=`pwd` + +function addcommit { + echo $1 > $1 + hg add $1 + hg commit -d "${2} 0" -u test -m $1 +} +function commit { + hg commit -d "${2} 0" -u test -m $1 +} + +function createrepo { + cd $BASE + rm -rf a + hg init a + cd a + addcommit "A" 0 + addcommit "B" 1 + echo "C" >> A + commit "C" 2 + + hg update -C 0 + echo "D" >> A + commit "D" 3 + addcommit "E" 4 +} + +echo "% Changes during an interruption - continue" +createrepo > /dev/null 2>&1 +hg glog --template '{rev}: {desc}\n' + +echo +echo "% - Rebasing B onto E" +hg rebase -s 1 -d 4 2>&1 | sed 's/\(saving bundle to \).*/\1/' + +echo +echo "% - Force a commit on C during the interruption" +hg update -C 2 +addcommit "Extra" 5 +hg glog --template '{rev}: {desc}\n' + +echo +echo "% - Resume the rebasing" +hg rebase --continue + +echo +echo "% - Solve the conflict and go on" +echo 'conflict solved' > A +rm A.orig +hg resolve -m A +hg rebase --continue +hg glog --template '{rev}: {desc}\n' + +echo +echo +echo "% Changes during an interruption - abort" +createrepo > /dev/null 2>&1 +hg glog --template '{rev}: {desc}\n' + +echo +echo "% Rebasing B onto E" +hg rebase -s 1 -d 4 2>&1 | sed 's/\(saving bundle to \).*/\1/' + +echo +echo "% Force a commit on B' during the interruption" +hg update -C 5 +addcommit "Extra" 6 +hg glog --template '{rev}: {desc}\n' + +echo +echo "% Abort the rebasing" +hg rebase --abort +hg glog --template '{rev}: {desc}\n' + +exit 0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-rebase-interruptions.out Mon Aug 18 21:16:31 2008 +0200 @@ -0,0 +1,113 @@ +% Changes during an interruption - continue +@ 4: E +| +o 3: D +| +| o 2: C +| | +| o 1: B +|/ +o 0: A + + +% - Rebasing B onto E +merging A +warning: conflicts during merge. +merging A failed! +abort: fix unresolved conflicts with hg resolve then run hg rebase --continue + +% - Force a commit on C during the interruption +1 files updated, 0 files merged, 1 files removed, 0 files unresolved +@ 6: Extra +| +| o 5: B +| | +| o 4: E +| | +| o 3: D +| | +o | 2: C +| | +o | 1: B +|/ +o 0: A + + +% - Resume the rebasing +merging A +warning: conflicts during merge. +merging A failed! +abort: fix unresolved conflicts with hg resolve then run hg rebase --continue + +% - Solve the conflict and go on +warning: new changesets detected on source branch, not stripping +rebase completed +@ 7: C +| +| o 6: Extra +| | +o | 5: B +| | +o | 4: E +| | +o | 3: D +| | +| o 2: C +| | +| o 1: B +|/ +o 0: A + + + +% Changes during an interruption - abort +@ 4: E +| +o 3: D +| +| o 2: C +| | +| o 1: B +|/ +o 0: A + + +% Rebasing B onto E +merging A +warning: conflicts during merge. +merging A failed! +abort: fix unresolved conflicts with hg resolve then run hg rebase --continue + +% Force a commit on B' during the interruption +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +@ 6: Extra +| +o 5: B +| +o 4: E +| +o 3: D +| +| o 2: C +| | +| o 1: B +|/ +o 0: A + + +% Abort the rebasing +warning: new changesets detected on target branch, not stripping +@ 6: Extra +| +o 5: B +| +o 4: E +| +o 3: D +| +| o 2: C +| | +| o 1: B +|/ +o 0: A +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-rebase-issue-noparam-single-rev Mon Aug 18 21:16:31 2008 +0200 @@ -0,0 +1,49 @@ +#!/bin/sh + +echo "[extensions]" >> $HGRCPATH +echo "graphlog=" >> $HGRCPATH +echo "rebase=" >> $HGRCPATH + +function addcommit { + echo $1 > $1 + hg add $1 + hg commit -d "${2} 0" -u test -m $1 +} + +hg init a +cd a +addcommit "c1" 0 +addcommit "c2" 1 + +addcommit "l1" 2 + +hg update -C 1 +addcommit "r1" 3 +addcommit "r2" 4 +hg glog --template '{rev}:{desc}\n' + +echo +echo '% Rebase with no arguments - single revision in source branch' +hg update -C 2 +hg rebase 2>&1 | sed 's/\(saving bundle to \).*/\1/' +hg glog --template '{rev}:{desc}\n' + +cd .. +rm -rf a +hg init a +cd a +addcommit "c1" 0 +addcommit "c2" 1 + +addcommit "l1" 2 +addcommit "l2" 3 + +hg update -C 1 +addcommit "r1" 4 +hg glog --template '{rev}:{desc}\n' + +echo +echo '% Rebase with no arguments - single revision in target branch' +hg update -C 3 +hg rebase 2>&1 | sed 's/\(saving bundle to \).*/\1/' +hg glog --template '{rev}:{desc}\n'
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-rebase-issue-noparam-single-rev.out Mon Aug 18 21:16:31 2008 +0200 @@ -0,0 +1,64 @@ +0 files updated, 0 files merged, 1 files removed, 0 files unresolved +created new head +@ 4:r2 +| +o 3:r1 +| +| o 2:l1 +|/ +o 1:c2 +| +o 0:c1 + + +% Rebase with no arguments - single revision in source branch +1 files updated, 0 files merged, 2 files removed, 0 files unresolved +saving bundle to +adding branch +adding changesets +adding manifests +adding file changes +added 3 changesets with 3 changes to 3 files +rebase completed +@ 4:l1 +| +o 3:r2 +| +o 2:r1 +| +o 1:c2 +| +o 0:c1 + +0 files updated, 0 files merged, 2 files removed, 0 files unresolved +created new head +@ 4:r1 +| +| o 3:l2 +| | +| o 2:l1 +|/ +o 1:c2 +| +o 0:c1 + + +% Rebase with no arguments - single revision in target branch +2 files updated, 0 files merged, 1 files removed, 0 files unresolved +saving bundle to +adding branch +adding changesets +adding manifests +adding file changes +added 3 changesets with 3 changes to 3 files +rebase completed +@ 4:l2 +| +o 3:l1 +| +o 2:r1 +| +o 1:c2 +| +o 0:c1 +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-rebase-mq Mon Aug 18 21:16:31 2008 +0200 @@ -0,0 +1,69 @@ +#!/bin/sh + +echo "[extensions]" >> $HGRCPATH +echo "graphlog=" >> $HGRCPATH +echo "rebase=" >> $HGRCPATH +echo "mq=" >> $HGRCPATH + +hg init a +cd a +hg qinit -c # This must work even with a managed mq queue + +echo 'c1' > f +hg add f +hg commit -d '0 0' -u test -m "C1" + +echo 'r1' > f +hg commit -d '2 0' -u test -m "R1" + +hg up 0 +hg qnew f.patch +echo 'mq1' > f +hg qref -m 'P0' + +hg qnew f2.patch +echo 'mq2' > f +hg qref -m 'P1' +hg glog --template '{rev} {desc} tags: {tags}\n' + +echo +echo '% Rebase - try to rebase on an applied mq patch' +hg rebase -s 1 -d 3 + +echo +echo '% Rebase - generate a conflict' +hg rebase -s 2 -d 1 + +echo +echo '% Fix the 1st conflict' +echo 'mq1r1' > f +hg resolve -m f +hg rebase -c 2>&1 | sed -e 's/\(saving bundle to \).*/\1/' + +echo +echo '% Fix the 2nd conflict' +echo 'mq1r1mq2' > f +hg resolve -m f +hg rebase -c 2>&1 | sed -e 's/\(saving bundle to \).*/\1/' + +hg glog --template '{rev} {desc} tags: {tags}\n' + +echo +echo '% Update to qbase' +hg up qbase +echo '% f correctly reflects the merge result' +cat f +echo '% And the patch is correct' +cat .hg/patches/f.patch | sed -e "s/^\(# \(Date\|Node ID\|Parent\)\).*/\1/" \ + -e "s/^\(diff -r \)\([a-f0-9]* \)\(-r \)\([a-f0-9]* \)/\1x \3y /" \ + -e "s/\(\(---\|+++\) [a-zA-Z0-9_/.-]*\).*/\1/" + +echo +echo '% Update to qtip' +hg up qtip +echo '% f correctly reflects the merge result' +cat f +echo '% And the patch is correct' +cat .hg/patches/f2.patch | sed -e "s/^\(# \(Date\|Node ID\|Parent\)\).*/\1/" \ + -e "s/^\(diff -r \)\([a-f0-9]* \)\(-r \)\([a-f0-9]* \)/\1x \3y /" \ + -e "s/\(\(---\|+++\) [a-zA-Z0-9_/.-]*\).*/\1/"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-rebase-mq-skip Mon Aug 18 21:16:31 2008 +0200 @@ -0,0 +1,44 @@ +#!/bin/sh +# This emulates the effects of an hg pull --rebase in which the remote repo +# already has one local mq patch + +echo "[extensions]" >> $HGRCPATH +echo "graphlog=" >> $HGRCPATH +echo "rebase=" >> $HGRCPATH +echo "mq=" >> $HGRCPATH + +hg init a +cd a +hg qinit -c # This must work even with a managed mq queue + +echo 'c1' > c1 +hg add c1 +hg commit -d '0 0' -u test -m "C1" + +echo 'r1' > r1 +hg add r1 +hg commit -d '1 0' -u test -m "R1" + +hg up 0 +hg qnew p0.patch +echo 'p0' > p0 +hg add p0 +hg qref -m 'P0' + +hg qnew p1.patch +echo 'p1' > p1 +hg add p1 +hg qref -m 'P1' +hg export qtip > p1.patch + +echo +echo '% "Mainstream" import p1.patch' +hg up -C 1 +hg import p1.patch +rm p1.patch + +echo +echo '% Rebase' +hg up -C qtip +hg rebase 2>&1 | sed -e 's/\(saving bundle to \).*/\1/' +hg glog --template '{rev} {desc} tags: {tags}\n'
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-rebase-mq-skip.out Mon Aug 18 21:16:31 2008 +0200 @@ -0,0 +1,24 @@ +0 files updated, 0 files merged, 1 files removed, 0 files unresolved + +% "Mainstream" import p1.patch +1 files updated, 0 files merged, 2 files removed, 0 files unresolved +applying p1.patch + +% Rebase +1 files updated, 0 files merged, 1 files removed, 0 files unresolved +nothing changed +saving bundle to +adding branch +adding changesets +adding manifests +adding file changes +added 2 changesets with 2 changes to 2 files +rebase completed +@ 3 P0 tags: p0.patch qtip tip qbase +| +o 2 P1 tags: qparent +| +o 1 R1 tags: +| +o 0 C1 tags: +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-rebase-mq.out Mon Aug 18 21:16:31 2008 +0200 @@ -0,0 +1,79 @@ +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +@ 3 P1 tags: qtip tip f2.patch +| +o 2 P0 tags: f.patch qbase +| +| o 1 R1 tags: +|/ +o 0 C1 tags: qparent + + +% Rebase - try to rebase on an applied mq patch +abort: cannot rebase onto an applied mq patch + +% Rebase - generate a conflict +merging f +warning: conflicts during merge. +merging f failed! +abort: fix unresolved conflicts with hg resolve then run hg rebase --continue + +% Fix the 1st conflict +merging f +warning: conflicts during merge. +merging f failed! +abort: fix unresolved conflicts with hg resolve then run hg rebase --continue + +% Fix the 2nd conflict +saving bundle to +adding branch +adding changesets +adding manifests +adding file changes +added 2 changesets with 2 changes to 1 files +rebase completed +@ 3 P1 tags: qtip tip f2.patch +| +o 2 P0 tags: f.patch qbase +| +o 1 R1 tags: qparent +| +o 0 C1 tags: + + +% Update to qbase +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +% f correctly reflects the merge result +mq1r1 +% And the patch is correct +# HG changeset patch +# User test +# Date +# Node ID +# Parent +P0 + +diff -r x -r y f +--- a/f ++++ b/f +@@ -1,1 +1,1 @@ +-r1 ++mq1r1 + +% Update to qtip +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +% f correctly reflects the merge result +mq1r1mq2 +% And the patch is correct +# HG changeset patch +# User test +# Date +# Node ID +# Parent +P1 + +diff -r x -r y f +--- a/f ++++ b/f +@@ -1,1 +1,1 @@ +-mq1r1 ++mq1r1mq2
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-rebase-parameters Mon Aug 18 21:16:31 2008 +0200 @@ -0,0 +1,105 @@ +#!/bin/sh + +echo "[extensions]" >> $HGRCPATH +echo "rebase=" >> $HGRCPATH + +function addcommit { + echo $1 > $1 + hg add $1 + hg commit -d "${2} 0" -u test -m $1 +} + +function commit { + hg commit -d "${2} 0" -u test -m $1 +} + +function createrepo { + hg init a + cd a + addcommit "c1" 0 + addcommit "c2" 1 + addcommit "c3" 2 + + hg update -C 1 + addcommit "l1" 3 + addcommit "l2" 4 + addcommit "l3" 5 + + hg update -C 2 + addcommit "r1" 6 + addcommit "r2" 7 +} + +createrepo > /dev/null 2&>1 +echo "% These fail" +echo +echo "% Use continue and abort" +hg rebase --continue --abort + +echo +echo "% Use continue and collapse" +hg rebase --continue --collapse + +echo +echo "% Use continue/abort and dest/source" +hg rebase --continue --dest 4 + +echo +echo "% Use source and base" +hg rebase --base 5 --source 4 + +echo +echo "% Rebase with no arguments - from current" +hg rebase + +echo +echo "% Rebase with no arguments - from the current branch" +hg update 6 +hg rebase + +echo "% ----------" +echo "% These work" +echo +echo "% Rebase with no arguments (from 3 onto 7)" +hg update -C 5 +hg rebase 2>&1 | sed 's/\(saving bundle to \).*/\1/' + +createrepo > /dev/null 2&>1 +echo +echo "% Rebase with base == '.' => same as no arguments (from 3 onto 7)" +hg update -C 5 +hg rebase --base . 2>&1 | sed 's/\(saving bundle to \).*/\1/' + +createrepo > /dev/null 2&>1 +echo +echo "% Rebase with dest == `hg branch` => same as no arguments (from 3 onto 7)" +hg update -C 5 +hg rebase --dest `hg branch` 2>&1 | sed 's/\(saving bundle to \).*/\1/' + +createrepo > /dev/null 2&>1 +echo +echo "% Specify only source (from 4 onto 7)" +hg rebase --source 4 2>&1 | sed 's/\(saving bundle to \).*/\1/' + +createrepo > /dev/null 2&>1 +echo +echo "% Specify only dest (from 3 onto 6)" +hg update -C 5 +hg rebase --dest 6 2>&1 | sed 's/\(saving bundle to \).*/\1/' + +createrepo > /dev/null 2&>1 +echo +echo "% Specify only base (from 3 onto 7)" +hg rebase --base 5 2>&1 | sed 's/\(saving bundle to \).*/\1/' + +createrepo > /dev/null 2&>1 +echo +echo "% Specify source and dest (from 4 onto 6)" +hg rebase --source 4 --dest 6 2>&1 | sed 's/\(saving bundle to \).*/\1/' + +createrepo > /dev/null 2&>1 +echo +echo "% Specify base and dest (from 3 onto 6)" +hg rebase --base 4 --dest 6 2>&1 | sed 's/\(saving bundle to \).*/\1/' + +exit 0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-rebase-parameters.out Mon Aug 18 21:16:31 2008 +0200 @@ -0,0 +1,194 @@ +% These fail + +% Use continue and abort +hg rebase: cannot use both abort and continue +hg rebase [-s rev | -b rev] [-d rev] [--collapse] | [-c] | [-a] | [--keep] + +move changeset (and descendants) to a different branch + + Rebase uses repeated merging to graft changesets from one part of history + onto another. This can be useful for linearizing local changes relative to + a master development tree. + + If a rebase is interrupted to manually resolve a merge, it can be continued + with --continue or aborted with --abort. + +options: + + --keep keep original revisions + -s --source rebase from a given revision + -b --base rebase from the base of a given revision + -d --dest rebase onto a given revision + --collapse collapse the rebased revisions + -c --continue continue an interrupted rebase + -a --abort abort an interrupted rebase + --style display using template map file + --template display with template + +use "hg -v help rebase" to show global options + +% Use continue and collapse +hg rebase: cannot use collapse with continue or abort +hg rebase [-s rev | -b rev] [-d rev] [--collapse] | [-c] | [-a] | [--keep] + +move changeset (and descendants) to a different branch + + Rebase uses repeated merging to graft changesets from one part of history + onto another. This can be useful for linearizing local changes relative to + a master development tree. + + If a rebase is interrupted to manually resolve a merge, it can be continued + with --continue or aborted with --abort. + +options: + + --keep keep original revisions + -s --source rebase from a given revision + -b --base rebase from the base of a given revision + -d --dest rebase onto a given revision + --collapse collapse the rebased revisions + -c --continue continue an interrupted rebase + -a --abort abort an interrupted rebase + --style display using template map file + --template display with template + +use "hg -v help rebase" to show global options + +% Use continue/abort and dest/source +hg rebase: abort and continue do not allow specifying revisions +hg rebase [-s rev | -b rev] [-d rev] [--collapse] | [-c] | [-a] | [--keep] + +move changeset (and descendants) to a different branch + + Rebase uses repeated merging to graft changesets from one part of history + onto another. This can be useful for linearizing local changes relative to + a master development tree. + + If a rebase is interrupted to manually resolve a merge, it can be continued + with --continue or aborted with --abort. + +options: + + --keep keep original revisions + -s --source rebase from a given revision + -b --base rebase from the base of a given revision + -d --dest rebase onto a given revision + --collapse collapse the rebased revisions + -c --continue continue an interrupted rebase + -a --abort abort an interrupted rebase + --style display using template map file + --template display with template + +use "hg -v help rebase" to show global options + +% Use source and base +hg rebase: cannot specify both a revision and a base +hg rebase [-s rev | -b rev] [-d rev] [--collapse] | [-c] | [-a] | [--keep] + +move changeset (and descendants) to a different branch + + Rebase uses repeated merging to graft changesets from one part of history + onto another. This can be useful for linearizing local changes relative to + a master development tree. + + If a rebase is interrupted to manually resolve a merge, it can be continued + with --continue or aborted with --abort. + +options: + + --keep keep original revisions + -s --source rebase from a given revision + -b --base rebase from the base of a given revision + -d --dest rebase onto a given revision + --collapse collapse the rebased revisions + -c --continue continue an interrupted rebase + -a --abort abort an interrupted rebase + --style display using template map file + --template display with template + +use "hg -v help rebase" to show global options + +% Rebase with no arguments - from current +nothing to rebase + +% Rebase with no arguments - from the current branch +0 files updated, 0 files merged, 1 files removed, 0 files unresolved +nothing to rebase +% ---------- +% These work + +% Rebase with no arguments (from 3 onto 7) +3 files updated, 0 files merged, 2 files removed, 0 files unresolved +saving bundle to +adding branch +adding changesets +adding manifests +adding file changes +added 5 changesets with 5 changes to 5 files +rebase completed + +% Rebase with base == '.' => same as no arguments (from 3 onto 7) +3 files updated, 0 files merged, 3 files removed, 0 files unresolved +saving bundle to +adding branch +adding changesets +adding manifests +adding file changes +added 5 changesets with 5 changes to 5 files +rebase completed + +% Rebase with dest == default => same as no arguments (from 3 onto 7) +3 files updated, 0 files merged, 3 files removed, 0 files unresolved +saving bundle to +adding branch +adding changesets +adding manifests +adding file changes +added 5 changesets with 5 changes to 5 files +rebase completed + +% Specify only source (from 4 onto 7) +saving bundle to +adding branch +adding changesets +adding manifests +adding file changes +added 4 changesets with 4 changes to 4 files (-1 heads) +rebase completed + +% Specify only dest (from 3 onto 6) +3 files updated, 0 files merged, 3 files removed, 0 files unresolved +saving bundle to +adding branch +adding changesets +adding manifests +adding file changes +added 5 changesets with 5 changes to 5 files (+1 heads) +rebase completed + +% Specify only base (from 3 onto 7) +saving bundle to +adding branch +adding changesets +adding manifests +adding file changes +added 5 changesets with 5 changes to 5 files +rebase completed + +% Specify source and dest (from 4 onto 6) +saving bundle to +adding branch +adding changesets +adding manifests +adding file changes +added 4 changesets with 4 changes to 4 files +rebase completed + +% Specify base and dest (from 3 onto 6) +saving bundle to +adding branch +adding changesets +adding manifests +adding file changes +added 5 changesets with 5 changes to 5 files (+1 heads) +rebase completed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-rebase-pull Mon Aug 18 21:16:31 2008 +0200 @@ -0,0 +1,49 @@ +#!/bin/sh + +echo "[extensions]" >> $HGRCPATH +echo "graphlog=" >> $HGRCPATH +echo "rebase=" >> $HGRCPATH + +BASE=`pwd` + +function addcommit { + echo $1 > $1 + hg add $1 + hg commit -d "${2} 0" -u test -m $1 +} +function commit { + hg commit -d "${2} 0" -u test -m $1 +} + +cd $BASE +rm -rf a +hg init a +cd a +addcommit "C1" 0 +addcommit "C2" 1 + +cd .. +hg clone a b +cd b +addcommit "L1" 2 + +cd ../a +addcommit "R1" 3 + +cd ../b +echo +echo "% Now b has one revision to be pulled from a" +hg pull --rebase 2>&1 | sed -e 's/\(saving bundle to \).*/\1/' \ + -e 's/\(pulling from \).*/\1/' + +hg glog --template '{rev}:{desc}\n' + +echo +echo "% Re-run pull --rebase" +hg pull --rebase 2>&1 | sed 's/\(pulling from \).*/\1/' + +echo +echo "% Invoke pull --rebase with --update" +hg pull --rebase --update + +exit 0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-rebase-pull.out Mon Aug 18 21:16:31 2008 +0200 @@ -0,0 +1,34 @@ +updating working directory +2 files updated, 0 files merged, 0 files removed, 0 files unresolved + +% Now b has one revision to be pulled from a +pulling from +searching for changes +adding changesets +adding manifests +adding file changes +added 1 changesets with 1 changes to 1 files (+1 heads) +(run 'hg heads' to see heads, 'hg merge' to merge) +saving bundle to +adding branch +adding changesets +adding manifests +adding file changes +added 2 changesets with 2 changes to 2 files +rebase completed +@ 3:L1 +| +o 2:R1 +| +o 1:C2 +| +o 0:C1 + + +% Re-run pull --rebase +pulling from +searching for changes +no changes found + +% Invoke pull --rebase with --update +abort: --update and --rebase are not compatible
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-rebase-scenario-global Mon Aug 18 21:16:31 2008 +0200 @@ -0,0 +1,81 @@ +#!/bin/sh + +echo "[extensions]" >> $HGRCPATH +echo "graphlog=" >> $HGRCPATH +echo "rebase=" >> $HGRCPATH + +BASE=`pwd` + +function addcommit { + echo $1 > $1 + hg add $1 + hg commit -d "${2} 0" -u test -m $1 +} +function commit { + hg commit -d "${2} 0" -u test -m $1 +} + +function createrepo { + cd $BASE + rm -rf a + hg init a + cd a + addcommit "A" 0 + addcommit "B" 1 + + hg update -C 0 + addcommit "C" 2 + + hg update -C 0 + addcommit "D" 3 + + hg merge -r 2 + commit "E" 4 + + hg update -C 3 + addcommit "F" 5 +} + +createrepo > /dev/null 2>&1 +hg glog --template '{rev}: {desc}\n' + +echo '% Rebasing' +echo '% B onto F - simple rebase' +hg rebase -s 1 -d 5 2>&1 | sed 's/\(saving bundle to \).*/\1/' +hg glog --template '{rev}: {desc}\n' + +createrepo > /dev/null 2>&1 +echo '% B onto D - intermediate point' +hg rebase -s 1 -d 3 2>&1 | sed 's/\(saving bundle to \).*/\1/' +hg glog --template '{rev}: {desc}\n' + +createrepo > /dev/null 2>&1 +echo '% C onto F - skip of E' +hg rebase -s 2 -d 5 2>&1 | sed 's/\(saving bundle to \).*/\1/' +hg glog --template '{rev}: {desc}\n' + +createrepo > /dev/null 2>&1 +echo '% D onto C - rebase of a branching point (skip E)' +hg rebase -s 3 -d 2 2>&1 | sed 's/\(saving bundle to \).*/\1/' +hg glog --template '{rev}: {desc}\n' + +createrepo > /dev/null 2>&1 +echo '% E onto F - merged revision having a parent in ancestors of target' +hg rebase -s 4 -d 5 2>&1 | sed 's/\(saving bundle to \).*/\1/' +hg glog --template '{rev}: {desc}\n' + +createrepo > /dev/null 2>&1 +echo '% D onto B - E maintains C as parent' +hg rebase -s 3 -d 1 2>&1 | sed 's/\(saving bundle to \).*/\1/' +hg glog --template '{rev}: {desc}\n' + +echo '% These will fail' +createrepo > /dev/null 2>&1 +echo '% E onto D - rebase onto an ancestor' +hg rebase -s 4 -d 3 +echo '% D onto E - rebase onto a descendant' +hg rebase -s 3 -d 4 +echo '% E onto B - merge revision with both parents not in ancestors of target' +hg rebase -s 4 -d 1 + +exit 0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-rebase-scenario-global.out Mon Aug 18 21:16:31 2008 +0200 @@ -0,0 +1,138 @@ +@ 5: F +| +| o 4: E +|/| +o | 3: D +| | +| o 2: C +|/ +| o 1: B +|/ +o 0: A + +% Rebasing +% B onto F - simple rebase +saving bundle to +adding branch +adding changesets +adding manifests +adding file changes +added 5 changesets with 4 changes to 4 files (+1 heads) +rebase completed +@ 5: B +| +o 4: F +| +| o 3: E +|/| +o | 2: D +| | +| o 1: C +|/ +o 0: A + +% B onto D - intermediate point +saving bundle to +adding branch +adding changesets +adding manifests +adding file changes +added 5 changesets with 4 changes to 4 files (+2 heads) +rebase completed +@ 5: B +| +| o 4: F +|/ +| o 3: E +|/| +o | 2: D +| | +| o 1: C +|/ +o 0: A + +% C onto F - skip of E +nothing changed +saving bundle to +adding branch +adding changesets +adding manifests +adding file changes +added 3 changesets with 3 changes to 3 files (+1 heads) +rebase completed +@ 4: C +| +o 3: F +| +o 2: D +| +| o 1: B +|/ +o 0: A + +% D onto C - rebase of a branching point (skip E) +nothing changed +saving bundle to +adding branch +adding changesets +adding manifests +adding file changes +added 2 changesets with 2 changes to 2 files +rebase completed +@ 4: F +| +o 3: D +| +o 2: C +| +| o 1: B +|/ +o 0: A + +% E onto F - merged revision having a parent in ancestors of target +saving bundle to +adding branch +adding changesets +adding manifests +adding file changes +added 2 changesets with 1 changes to 1 files (-1 heads) +rebase completed +@ 5: E +|\ +| o 4: F +| | +| o 3: D +| | +o | 2: C +|/ +| o 1: B +|/ +o 0: A + +% D onto B - E maintains C as parent +saving bundle to +adding branch +adding changesets +adding manifests +adding file changes +added 3 changesets with 2 changes to 2 files +rebase completed +@ 5: F +| +| o 4: E +|/| +o | 3: D +| | +| o 2: C +| | +o | 1: B +|/ +o 0: A + +% These will fail +% E onto D - rebase onto an ancestor +abort: cannot rebase a descendant +% D onto E - rebase onto a descendant +abort: cannot rebase an ancestor +% E onto B - merge revision with both parents not in ancestors of target +abort: cannot use revision 4 as base, result would have 3 parents