[PATCH 1 of 2] rebase: add upto option for cherry picking
Stefano Tortarolo
stefano.tortarolo at gmail.com
Sun Mar 29 15:28:13 CDT 2009
# HG changeset patch
# User Stefano Tortarolo <stefano.tortarolo at gmail.com>
# Date 1238332125 -7200
# Node ID 1b0dfe2121f22ca65e78541a0132f00940a9401c
# Parent 915d6b44eed31eed187f0770e185a27158a215cb
rebase: add upto option for cherry picking
Rebase now allows rebasing only some revisions.
It's very important to note that cherry picking intermediate
revisions will rebase also their parents up to the --base
revision.
That's why --source y is transformed to --base y.
Inspired by Tomasz Barszczak
diff --git a/hgext/rebase.py b/hgext/rebase.py
--- a/hgext/rebase.py
+++ b/hgext/rebase.py
@@ -59,6 +59,7 @@
# Validate input and define rebasing points
destf = opts.get('dest', None)
srcf = opts.get('source', None)
+ uptof = opts.get('upto', None)
basef = opts.get('base', None)
contf = opts.get('continue')
abortf = opts.get('abort')
@@ -74,22 +75,30 @@
if collapsef:
raise error.ParseError(
'rebase', _('cannot use collapse with continue or abort'))
-
+ if uptof:
+ raise error.ParseError(
+ 'rebase', _('cannot use upto with continue or abort'))
if (srcf or basef or destf):
raise error.ParseError('rebase',
_('abort and continue do not allow specifying revisions'))
- (originalwd, target, state, collapsef, keepf,
- keepbranchesf, external) = restorestatus(repo)
+ (originalwd, target, state, collapsef, keepf, keepbranchesf,
+ external) = restorestatus(repo)
if abortf:
abort(repo, originalwd, target, state)
return
else:
+ if uptof:
+ keepf = True
+ if srcf and not basef:
+ ui.warn(_('warning: assuming base instead of source\n'))
+ basef = srcf
+ srcf = None
if srcf and basef:
raise error.ParseError('rebase', _('cannot specify both a '
'revision and a base'))
cmdutil.bail_if_changed(repo)
- result = buildstate(repo, destf, srcf, basef, collapsef)
+ result = buildstate(repo, destf, srcf, uptof, basef, collapsef)
if result:
originalwd, target, state, external = result
else: # Empty state built, nothing to rebase
@@ -210,7 +219,6 @@
else: # we have an interrupted rebase
repo.ui.debug(_('resuming interrupted rebase\n'))
-
newrev = concludenode(repo, rev, p1, p2, state, collapse,
extrafn=extrafn)
@@ -345,7 +353,7 @@
clearstatus(repo)
repo.ui.status(_('rebase aborted\n'))
-def buildstate(repo, dest, src, base, collapse):
+def buildstate(repo, dest, src, upto, base, collapse):
'Define which revisions are going to be rebased and where'
targetancestors = util.set()
@@ -387,7 +395,14 @@
source = min(rebasingbranch)
repo.ui.debug(_('rebase onto %d starting from %d\n') % (dest, source))
- state = dict.fromkeys(repo.changelog.descendants(source), nullrev)
+ descendants = repo.changelog.descendants(source)
+ if upto:
+ upto = repo[upto].rev()
+ descendants = filter(lambda x: x <= upto, descendants)
+ if upto != source and upto not in descendants:
+ raise util.Abort(_('upto revision is not a descendant of source '
+ 'revision'))
+ state = dict.fromkeys(descendants, nullrev)
external = nullrev
if collapse:
if not targetancestors:
@@ -444,9 +459,10 @@
('', 'collapse', False, _('collapse the rebased revisions')),
('', 'keep', False, _('keep original revisions')),
('', 'keepbranches', False, _('keep original branches')),
+ ('', 'upto', '', _('rebase up to a given revision')),
('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]')),
+ '[--keepbranches] [--upto] | [-c] | [-a]')),
}
diff --git a/tests/test-rebase-check-restore b/tests/test-rebase-check-restore
--- a/tests/test-rebase-check-restore
+++ b/tests/test-rebase-check-restore
@@ -30,11 +30,12 @@
echo "D" >> A
commit "D" 3
addcommit "E" 4
+ addcommit "F" 5
hg update -C 0
hg branch 'notdefault'
- echo "F" >> A
- commit "F" 5
+ echo "G" >> A
+ commit "G" 6
}
echo
@@ -52,10 +53,10 @@
hg glog --template '{rev}:{desc}:{branches}\n'
echo
-echo "% - Rebase F onto E - check keepbranches"
+echo "% - Rebase G onto F - check keepbranches"
createrepo > /dev/null 2>&1
hg glog --template '{rev}:{desc}:{branches}\n'
-hg rebase -s 5 -d 4 --keepbranches 2>&1 | sed 's/\(saving bundle to \).*/\1/'
+hg rebase -s 6 -d 5 --keepbranches 2>&1 | sed 's/\(saving bundle to \).*/\1/'
echo
echo "% - Solve the conflict and go on"
@@ -65,4 +66,18 @@
hg rebase --continue 2>&1 | sed 's/\(saving bundle to \).*/\1/'
hg glog --template '{rev}:{desc}:{branches}\n'
+echo
+echo "% - Cherrypick base E onto C - conflict"
+createrepo > /dev/null 2>&1
+hg glog --template '{rev}:{desc}:{branches}\n'
+hg rebase --upto 4 -b 4 -d 2 2>&1 | sed 's/\(saving bundle to \).*/\1/'
+
+echo
+echo "% - Solve the conflict and go on - must stop at E"
+echo 'conflict solved' > A
+rm A.orig
+hg resolve -m A
+hg rebase --continue 2>&1 | sed 's/\(saving bundle to \).*/\1/'
+hg glog --template '{rev}:{desc}:{branches}\n'
+
exit 0
diff --git a/tests/test-rebase-check-restore.out b/tests/test-rebase-check-restore.out
--- a/tests/test-rebase-check-restore.out
+++ b/tests/test-rebase-check-restore.out
@@ -1,7 +1,9 @@
% - Rebasing B onto E - check keep
-@ 5:F:notdefault
+@ 6:G:notdefault
|
+| o 5:F:
+| |
| o 4:E:
| |
| o 3:D:
@@ -19,11 +21,13 @@
% - Solve the conflict and go on
rebase completed
-@ 7:C:
+@ 8:C:
|
-o 6:B:
+o 7:B:
|
-| o 5:F:notdefault
+| o 6:G:notdefault
+| |
++---o 5:F:
| |
o | 4:E:
| |
@@ -36,9 +40,11 @@
o 0:A:
-% - Rebase F onto E - check keepbranches
-@ 5:F:notdefault
+% - Rebase G onto F - check keepbranches
+@ 6:G:notdefault
|
+| o 5:F:
+| |
| o 4:E:
| |
| o 3:D:
@@ -62,7 +68,9 @@
adding file changes
added 1 changesets with 1 changes to 1 files
rebase completed
-@ 5:F:notdefault
+@ 6:G:notdefault
+|
+o 5:F:
|
o 4:E:
|
@@ -74,3 +82,44 @@
|/
o 0:A:
+
+% - Cherrypick base E onto C - conflict
+@ 6:G:notdefault
+|
+| o 5:F:
+| |
+| o 4:E:
+| |
+| o 3:D:
+|/
+| o 2:C:
+| |
+| o 1:B:
+|/
+o 0:A:
+
+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 - must stop at E
+rebase completed
+@ 8:E:
+|
+o 7:D:
+|
+| o 6:G:notdefault
+| |
+| | o 5:F:
+| | |
+| | o 4:E:
+| | |
+| | o 3:D:
+| |/
+o | 2:C:
+| |
+o | 1:B:
+|/
+o 0:A:
+
diff --git a/tests/test-rebase-cherrypicking b/tests/test-rebase-cherrypicking
new file mode 100755
--- /dev/null
+++ b/tests/test-rebase-cherrypicking
@@ -0,0 +1,62 @@
+#!/bin/sh
+
+echo "[extensions]" >> $HGRCPATH
+echo "graphlog=" >> $HGRCPATH
+echo "rebase=" >> $HGRCPATH
+
+BASE=`pwd`
+
+addcommit () {
+ echo $1 > $1
+ hg add $1
+ hg commit -d "${2} 0" -u test -m $1
+}
+
+commit () {
+ hg commit -d "${2} 0" -u test -m $1
+}
+
+createrepo () {
+ cd $BASE
+ rm -rf a
+ hg init a
+ cd a
+ addcommit "A" 0
+ addcommit "B" 1
+ addcommit "C" 2
+
+ hg update -C 0
+ addcommit "D" 3
+ addcommit "E" 4
+ addcommit "F" 5
+ addcommit "G" 6
+}
+
+echo '% Cherry picking D onto C'
+createrepo > /dev/null 2>&1
+hg glog --template '{rev}: {desc}\n'
+hg rebase --upto 3 --base 3 -d 2 2>&1 | sed 's/\(saving bundle to \).*/\1/'
+hg glog --template '{rev}: {desc}\n'
+echo "Expected A, B, C, D"
+hg manifest
+
+echo
+echo '% Cherry picking D, E onto C'
+echo '% (using --source, converted to --base)'
+createrepo > /dev/null 2>&1
+hg glog --template '{rev}: {desc}\n'
+hg rebase --upto 4 -s 3 -d 2 2>&1 | sed 's/\(saving bundle to \).*/\1/'
+hg glog --template '{rev}: {desc}\n'
+echo "Expected A, B, C, D, E"
+hg manifest
+
+echo
+echo '% Cherry picking F onto C'
+createrepo > /dev/null 2>&1
+hg glog --template '{rev}: {desc}\n'
+hg rebase --upto 5 -s 5 -d 2 2>&1 | sed 's/\(saving bundle to \).*/\1/'
+hg glog --template '{rev}: {desc}\n'
+echo "Expected A, B, C, D, E, F"
+hg manifest
+
+exit 0
diff --git a/tests/test-rebase-cherrypicking.out b/tests/test-rebase-cherrypicking.out
new file mode 100644
--- /dev/null
+++ b/tests/test-rebase-cherrypicking.out
@@ -0,0 +1,125 @@
+% Cherry picking D onto C
+@ 6: G
+|
+o 5: F
+|
+o 4: E
+|
+o 3: D
+|
+| o 2: C
+| |
+| o 1: B
+|/
+o 0: A
+
+rebase completed
+@ 7: D
+|
+| o 6: G
+| |
+| o 5: F
+| |
+| o 4: E
+| |
+| o 3: D
+| |
+o | 2: C
+| |
+o | 1: B
+|/
+o 0: A
+
+Expected A, B, C, D
+A
+B
+C
+D
+
+% Cherry picking D, E onto C
+% (using --source, converted to --base)
+@ 6: G
+|
+o 5: F
+|
+o 4: E
+|
+o 3: D
+|
+| o 2: C
+| |
+| o 1: B
+|/
+o 0: A
+
+warning: assuming base instead of source
+rebase completed
+@ 8: E
+|
+o 7: D
+|
+| o 6: G
+| |
+| o 5: F
+| |
+| o 4: E
+| |
+| o 3: D
+| |
+o | 2: C
+| |
+o | 1: B
+|/
+o 0: A
+
+Expected A, B, C, D, E
+A
+B
+C
+D
+E
+
+% Cherry picking F onto C
+@ 6: G
+|
+o 5: F
+|
+o 4: E
+|
+o 3: D
+|
+| o 2: C
+| |
+| o 1: B
+|/
+o 0: A
+
+warning: assuming base instead of source
+rebase completed
+@ 9: F
+|
+o 8: E
+|
+o 7: D
+|
+| o 6: G
+| |
+| o 5: F
+| |
+| o 4: E
+| |
+| o 3: D
+| |
+o | 2: C
+| |
+o | 1: B
+|/
+o 0: A
+
+Expected A, B, C, D, E, F
+A
+B
+C
+D
+E
+F
diff --git a/tests/test-rebase-parameters.out b/tests/test-rebase-parameters.out
--- a/tests/test-rebase-parameters.out
+++ b/tests/test-rebase-parameters.out
@@ -2,7 +2,7 @@
% Use continue and abort
hg rebase: cannot use both abort and continue
-hg rebase [-s rev | -b rev] [-d rev] [--collapse] [--keep] [--keepbranches] | [-c] | [-a]
+hg rebase [-s rev | -b rev] [-d rev] [--collapse] [--keep] [--keepbranches] [--upto] | [-c] | [-a]
move changeset (and descendants) to a different branch
@@ -21,6 +21,7 @@
--collapse collapse the rebased revisions
--keep keep original revisions
--keepbranches keep original branches
+ --upto rebase up to a given revision
-c --continue continue an interrupted rebase
-a --abort abort an interrupted rebase
--style display using template map file
@@ -30,7 +31,7 @@
% Use continue and collapse
hg rebase: cannot use collapse with continue or abort
-hg rebase [-s rev | -b rev] [-d rev] [--collapse] [--keep] [--keepbranches] | [-c] | [-a]
+hg rebase [-s rev | -b rev] [-d rev] [--collapse] [--keep] [--keepbranches] [--upto] | [-c] | [-a]
move changeset (and descendants) to a different branch
@@ -49,6 +50,7 @@
--collapse collapse the rebased revisions
--keep keep original revisions
--keepbranches keep original branches
+ --upto rebase up to a given revision
-c --continue continue an interrupted rebase
-a --abort abort an interrupted rebase
--style display using template map file
@@ -58,7 +60,7 @@
% 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] [--keep] [--keepbranches] | [-c] | [-a]
+hg rebase [-s rev | -b rev] [-d rev] [--collapse] [--keep] [--keepbranches] [--upto] | [-c] | [-a]
move changeset (and descendants) to a different branch
@@ -77,6 +79,7 @@
--collapse collapse the rebased revisions
--keep keep original revisions
--keepbranches keep original branches
+ --upto rebase up to a given revision
-c --continue continue an interrupted rebase
-a --abort abort an interrupted rebase
--style display using template map file
@@ -86,7 +89,7 @@
% Use source and base
hg rebase: cannot specify both a revision and a base
-hg rebase [-s rev | -b rev] [-d rev] [--collapse] [--keep] [--keepbranches] | [-c] | [-a]
+hg rebase [-s rev | -b rev] [-d rev] [--collapse] [--keep] [--keepbranches] [--upto] | [-c] | [-a]
move changeset (and descendants) to a different branch
@@ -105,6 +108,7 @@
--collapse collapse the rebased revisions
--keep keep original revisions
--keepbranches keep original branches
+ --upto rebase up to a given revision
-c --continue continue an interrupted rebase
-a --abort abort an interrupted rebase
--style display using template map file
More information about the Mercurial-devel
mailing list