Skip to content
Snippets Groups Projects
Commit 50f434510da6 authored by Pierre-Yves David's avatar Pierre-Yves David
Browse files

rebase: do not add second parent to rebased changeset (drop detach option) (BC)

Rebase now behaves as if --detach was always passed. Non-merges are
rebased as non-merges, regardless of their parent being an ancestor of
the destination. Merges will usually be rebased as merges unless both of
their parents are ancestors of the destination, or one of their parents
is pruned when rebased.

This only alters the behavior of rebase when using the --source/--rev
options. --detach option is deprecated.

All test changes were carefully validated.
parent a1d86396d8c1
No related branches found
No related tags found
No related merge requests found
...@@ -48,8 +48,7 @@ ...@@ -48,8 +48,7 @@
_('read collapse commit message from file'), _('FILE')), _('read collapse commit message from file'), _('FILE')),
('', 'keep', False, _('keep original changesets')), ('', 'keep', False, _('keep original changesets')),
('', 'keepbranches', False, _('keep original branch names')), ('', 'keepbranches', False, _('keep original branch names')),
('D', 'detach', False, _('force detaching of source from its original ' ('D', 'detach', False, _('(DEPRECATED)')),
'branch')),
('t', 'tool', '', _('specify merge tool')), ('t', 'tool', '', _('specify merge tool')),
('c', 'continue', False, _('continue an interrupted rebase')), ('c', 'continue', False, _('continue an interrupted rebase')),
('a', 'abort', False, _('abort an interrupted rebase'))] + ('a', 'abort', False, _('abort an interrupted rebase'))] +
...@@ -131,7 +130,6 @@ ...@@ -131,7 +130,6 @@
extrafn = opts.get('extrafn') # internal, used by e.g. hgsubversion extrafn = opts.get('extrafn') # internal, used by e.g. hgsubversion
keepf = opts.get('keep', False) keepf = opts.get('keep', False)
keepbranchesf = opts.get('keepbranches', False) keepbranchesf = opts.get('keepbranches', False)
detachf = opts.get('detach', False)
# keepopen is not meant for use on the command line, but by # keepopen is not meant for use on the command line, but by
# other extensions # other extensions
keepopen = opts.get('keepopen', False) keepopen = opts.get('keepopen', False)
...@@ -146,8 +144,6 @@ ...@@ -146,8 +144,6 @@
if collapsef: if collapsef:
raise util.Abort( raise util.Abort(
_('cannot use collapse with continue or abort')) _('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:
raise util.Abort( raise util.Abort(
_('abort and continue do not allow specifying revisions')) _('abort and continue do not allow specifying revisions'))
...@@ -168,12 +164,6 @@ ...@@ -168,12 +164,6 @@
if revf and srcf: if revf and srcf:
raise util.Abort(_('cannot specify both a ' raise util.Abort(_('cannot specify both a '
'revision and a source')) 'revision and a source'))
if detachf:
if not (srcf or revf):
raise util.Abort(
_('detach requires a revision to be specified'))
if basef:
raise util.Abort(_('cannot specify a base with detach'))
cmdutil.bailifchanged(repo) cmdutil.bailifchanged(repo)
...@@ -215,7 +205,7 @@ ...@@ -215,7 +205,7 @@
% repo[root], % repo[root],
hint=_('see hg help phases for details')) hint=_('see hg help phases for details'))
else: else:
result = buildstate(repo, dest, rebaseset, detachf, collapsef) result = buildstate(repo, dest, rebaseset, collapsef)
if not result: if not result:
# Empty state built, nothing to rebase # Empty state built, nothing to rebase
...@@ -592,9 +582,9 @@ ...@@ -592,9 +582,9 @@
repo.ui.warn(_('rebase aborted\n')) repo.ui.warn(_('rebase aborted\n'))
return 0 return 0
def buildstate(repo, dest, rebaseset, detach, collapse): def buildstate(repo, dest, rebaseset, collapse):
'''Define which revisions are going to be rebased and where '''Define which revisions are going to be rebased and where
repo: repo repo: repo
dest: context dest: context
rebaseset: set of rev rebaseset: set of rev
...@@ -596,9 +586,9 @@ ...@@ -596,9 +586,9 @@
'''Define which revisions are going to be rebased and where '''Define which revisions are going to be rebased and where
repo: repo repo: repo
dest: context dest: context
rebaseset: set of rev rebaseset: set of rev
detach: boolean''' '''
# This check isn't strictly necessary, since mq detects commits over an # This check isn't strictly necessary, since mq detects commits over an
# applied patch. But it prevents messing up the working directory when # applied patch. But it prevents messing up the working directory when
...@@ -607,7 +597,6 @@ ...@@ -607,7 +597,6 @@
[s.node for s in repo.mq.applied]): [s.node for s in repo.mq.applied]):
raise util.Abort(_('cannot rebase onto an applied mq patch')) raise util.Abort(_('cannot rebase onto an applied mq patch'))
detachset = set()
roots = list(repo.set('roots(%ld)', rebaseset)) roots = list(repo.set('roots(%ld)', rebaseset))
if not roots: if not roots:
raise util.Abort(_('no matching revisions')) raise util.Abort(_('no matching revisions'))
...@@ -623,10 +612,6 @@ ...@@ -623,10 +612,6 @@
if not collapse and samebranch and root in dest.children(): if not collapse and samebranch and root in dest.children():
repo.ui.debug('source is a child of destination\n') repo.ui.debug('source is a child of destination\n')
return None return None
# rebase on ancestor, force detach
detach = True
if detach:
detachset = repo.revs('::%d - ::%d - %d', root, commonbase, root)
repo.ui.debug('rebase onto %d starting from %d\n' % (dest, root)) repo.ui.debug('rebase onto %d starting from %d\n' % (dest, root))
state = dict.fromkeys(rebaseset, nullrev) state = dict.fromkeys(rebaseset, nullrev)
...@@ -630,7 +615,47 @@ ...@@ -630,7 +615,47 @@
repo.ui.debug('rebase onto %d starting from %d\n' % (dest, root)) repo.ui.debug('rebase onto %d starting from %d\n' % (dest, root))
state = dict.fromkeys(rebaseset, nullrev) state = dict.fromkeys(rebaseset, nullrev)
state.update(dict.fromkeys(detachset, nullmerge)) # Rebase tries to turn <dest> into a parent of <root> while
# preserving the number of parents of rebased changesets:
#
# - A changeset with a single parent will always be rebased as a
# changeset with a single parent.
#
# - A merge will be rebased as merge unless its parents are both
# ancestors of <dest> or are themselves in the rebased set and
# pruned while rebased.
#
# If one parent of <root> is an ancestor of <dest>, the rebased
# version of this parent will be <dest>. This is always true with
# --base option.
#
# Otherwise, we need to *replace* the original parents with
# <dest>. This "detaches" the rebased set from its former location
# and rebases it onto <dest>. Changes introduced by ancestors of
# <root> not common with <dest> (the detachset, marked as
# nullmerge) are "removed" from the rebased changesets.
#
# - If <root> has a single parent, set it to <dest>.
#
# - If <root> is a merge, we cannot decide which parent to
# replace, the rebase operation is not clearly defined.
#
# The table below sums up this behavior:
#
# +--------------------+----------------------+-------------------------+
# | | one parent | merge |
# +--------------------+----------------------+-------------------------+
# | parent in ::<dest> | new parent is <dest> | parents in ::<dest> are |
# | | | remapped to <dest> |
# +--------------------+----------------------+-------------------------+
# | unrelated source | new parent is <dest> | ambiguous, abort |
# +--------------------+----------------------+-------------------------+
#
# The actual abort is handled by `defineparents`
if len(root.parents()) <= 1:
# (strict) ancestors of <root> not ancestors of <dest>
detachset = repo.revs('::%d - ::%d - %d', root, commonbase, root)
state.update(dict.fromkeys(detachset, nullmerge))
return repo['.'].rev(), dest.rev(), state return repo['.'].rev(), dest.rev(), state
def pullrebase(orig, ui, repo, *args, **opts): def pullrebase(orig, ui, repo, *args, **opts):
......
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
saved backup bundle to $TESTTMP/.hg/strip-backup/*-backup.hg (glob) saved backup bundle to $TESTTMP/.hg/strip-backup/*-backup.hg (glob)
$ hg log $ hg log
changeset: 3:9163974d1cb5 changeset: 3:42e5ed2cdcf4
bookmark: two bookmark: two
tag: tip tag: tip
parent: 1:925d80f479bb parent: 1:925d80f479bb
...@@ -43,7 +43,6 @@ ...@@ -43,7 +43,6 @@
bookmark: two bookmark: two
tag: tip tag: tip
parent: 1:925d80f479bb parent: 1:925d80f479bb
parent: 2:db815d6d32e6
user: test user: test
date: Thu Jan 01 00:00:00 1970 +0000 date: Thu Jan 01 00:00:00 1970 +0000
summary: 3 summary: 3
......
...@@ -54,7 +54,7 @@ ...@@ -54,7 +54,7 @@
$ cd a1 $ cd a1
$ hg up -q Z $ hg up -q Z
$ hg rebase --detach -s Y -d 3 $ hg rebase -s Y -d 3
saved backup bundle to $TESTTMP/a1/.hg/strip-backup/*-backup.hg (glob) saved backup bundle to $TESTTMP/a1/.hg/strip-backup/*-backup.hg (glob)
$ hg tglog $ hg tglog
......
...@@ -104,7 +104,7 @@ ...@@ -104,7 +104,7 @@
2: 'B' branch1 2: 'B' branch1
0: 'A' 0: 'A'
$ hg rebase --detach -s 5 -d 8 $ hg rebase -s 5 -d 8
saved backup bundle to $TESTTMP/a1/.hg/strip-backup/*-backup.hg (glob) saved backup bundle to $TESTTMP/a1/.hg/strip-backup/*-backup.hg (glob)
$ hg branches $ hg branches
...@@ -165,7 +165,7 @@ ...@@ -165,7 +165,7 @@
|/ |/
o 0: 'A' o 0: 'A'
$ hg rebase --detach -s 8 -d 6 $ hg rebase -s 8 -d 6
saved backup bundle to $TESTTMP/a2/.hg/strip-backup/*-backup.hg (glob) saved backup bundle to $TESTTMP/a2/.hg/strip-backup/*-backup.hg (glob)
$ hg branches $ hg branches
...@@ -229,7 +229,7 @@ ...@@ -229,7 +229,7 @@
|/ |/
o 0: 'A' o 0: 'A'
$ hg rebase --detach -s 7 -d 6 $ hg rebase -s 7 -d 6
saved backup bundle to $TESTTMP/a3/.hg/strip-backup/*-backup.hg (glob) saved backup bundle to $TESTTMP/a3/.hg/strip-backup/*-backup.hg (glob)
$ hg branches $ hg branches
......
...@@ -230,7 +230,7 @@ ...@@ -230,7 +230,7 @@
Rebase and collapse - E onto H: Rebase and collapse - E onto H:
$ hg rebase -s 4 --collapse $ hg rebase -s 4 --collapse # root (4) is not a merge
saved backup bundle to $TESTTMP/b1/.hg/strip-backup/*-backup.hg (glob) saved backup bundle to $TESTTMP/b1/.hg/strip-backup/*-backup.hg (glob)
$ hg tglog $ hg tglog
...@@ -250,7 +250,6 @@ ...@@ -250,7 +250,6 @@
$ hg manifest $ hg manifest
A A
B
C C
D D
E E
...@@ -340,7 +339,7 @@ ...@@ -340,7 +339,7 @@
$ hg clone -q -u . c c1 $ hg clone -q -u . c c1
$ cd c1 $ cd c1
$ hg rebase -s 4 --collapse $ hg rebase -s 4 --collapse # root (4) is not a merge
merging E merging E
saved backup bundle to $TESTTMP/c1/.hg/strip-backup/*-backup.hg (glob) saved backup bundle to $TESTTMP/c1/.hg/strip-backup/*-backup.hg (glob)
...@@ -362,7 +361,6 @@ ...@@ -362,7 +361,6 @@
$ hg manifest $ hg manifest
A A
B
C C
D D
E E
......
...@@ -48,7 +48,7 @@ ...@@ -48,7 +48,7 @@
o 0: 'A' o 0: 'A'
$ hg phase --force --secret 3 $ hg phase --force --secret 3
$ hg rebase --detach -s 3 -d 7 $ hg rebase -s 3 -d 7
saved backup bundle to $TESTTMP/a1/.hg/strip-backup/*-backup.hg (glob) saved backup bundle to $TESTTMP/a1/.hg/strip-backup/*-backup.hg (glob)
$ hg log -G --template "{rev}:{phase} '{desc}' {branches}\n" $ hg log -G --template "{rev}:{phase} '{desc}' {branches}\n"
...@@ -99,7 +99,7 @@ ...@@ -99,7 +99,7 @@
|/ |/
o 0: 'A' o 0: 'A'
$ hg rebase --detach -s 2 -d 7 $ hg rebase -s 2 -d 7
saved backup bundle to $TESTTMP/a2/.hg/strip-backup/*-backup.hg (glob) saved backup bundle to $TESTTMP/a2/.hg/strip-backup/*-backup.hg (glob)
$ hg tglog $ hg tglog
...@@ -151,7 +151,7 @@ ...@@ -151,7 +151,7 @@
|/ |/
o 0: 'A' o 0: 'A'
$ hg rebase --detach -s 1 -d 7 $ hg rebase -s 1 -d 7
saved backup bundle to $TESTTMP/a3/.hg/strip-backup/*-backup.hg (glob) saved backup bundle to $TESTTMP/a3/.hg/strip-backup/*-backup.hg (glob)
$ hg tglog $ hg tglog
...@@ -205,7 +205,7 @@ ...@@ -205,7 +205,7 @@
|/ |/
o 0: 'A' o 0: 'A'
$ hg rebase --detach --collapse -s 2 -d 7 $ hg rebase --collapse -s 2 -d 7
saved backup bundle to $TESTTMP/a4/.hg/strip-backup/*-backup.hg (glob) saved backup bundle to $TESTTMP/a4/.hg/strip-backup/*-backup.hg (glob)
$ hg log -G --template "{rev}:{phase} '{desc}' {branches}\n" $ hg log -G --template "{rev}:{phase} '{desc}' {branches}\n"
...@@ -264,7 +264,7 @@ ...@@ -264,7 +264,7 @@
|/ |/
o 0: 'A' o 0: 'A'
$ hg rebase --detach -s 1 -d tip $ hg rebase -s 1 -d tip
saved backup bundle to $TESTTMP/a5/.hg/strip-backup/*-backup.hg (glob) saved backup bundle to $TESTTMP/a5/.hg/strip-backup/*-backup.hg (glob)
$ hg tglog $ hg tglog
...@@ -325,7 +325,7 @@ ...@@ -325,7 +325,7 @@
$ echo "J" >> F $ echo "J" >> F
$ hg ci -m "J" $ hg ci -m "J"
$ hg rebase -s 8 -d 7 --collapse --detach --config ui.merge=internal:other $ hg rebase -s 8 -d 7 --collapse --config ui.merge=internal:other
remote changed E which local deleted remote changed E which local deleted
use (c)hanged version or leave (d)eleted? c use (c)hanged version or leave (d)eleted? c
saved backup bundle to $TESTTMP/a6/.hg/strip-backup/*-backup.hg (glob) saved backup bundle to $TESTTMP/a6/.hg/strip-backup/*-backup.hg (glob)
...@@ -370,7 +370,7 @@ ...@@ -370,7 +370,7 @@
$ hg ci -A -m 'H2' $ hg ci -A -m 'H2'
adding H adding H
$ hg phase --force --secret 8 $ hg phase --force --secret 8
$ hg rebase -s 8 -d 7 --detach --config ui.merge=internal:fail $ hg rebase -s 8 -d 7 --config ui.merge=internal:fail
merging H merging H
warning: conflicts during merge. warning: conflicts during merge.
merging H incomplete! (edit conflicts, then use 'hg resolve --mark') merging H incomplete! (edit conflicts, then use 'hg resolve --mark')
......
...@@ -199,9 +199,13 @@ ...@@ -199,9 +199,13 @@
$ hg tglog $ hg tglog
@ 8: 'D' @ 8: 'D'
| |
o 7: 'C' o 7: 'C'
|\ |
| o 6: 'I' o 6: 'I'
| | |
| o 5: 'H' o 5: 'H'
|
| o 4: 'G'
|/|
o | 3: 'F'
| | | |
...@@ -207,11 +211,7 @@ ...@@ -207,11 +211,7 @@
| | | |
| | o 4: 'G' | o 2: 'E'
| |/| |/
| o | 3: 'F' | o 1: 'B'
| | |
| | o 2: 'E'
| |/
o | 1: 'B'
|/ |/
o 0: 'A' o 0: 'A'
...@@ -283,7 +283,7 @@ ...@@ -283,7 +283,7 @@
$ hg clone -q -u . a a7 $ hg clone -q -u . a a7
$ cd a7 $ cd a7
$ hg rebase --detach --source 2 --dest 7 $ hg rebase --source 2 --dest 7
saved backup bundle to $TESTTMP/a7/.hg/strip-backup/*-backup.hg (glob) saved backup bundle to $TESTTMP/a7/.hg/strip-backup/*-backup.hg (glob)
$ hg tglog $ hg tglog
...@@ -349,9 +349,13 @@ ...@@ -349,9 +349,13 @@
$ hg tglog $ hg tglog
@ 8: 'D' @ 8: 'D'
| |
o 7: 'C' o 7: 'C'
|\ |
| o 6: 'I' o 6: 'I'
| | |
| o 5: 'H' o 5: 'H'
|
| o 4: 'G'
|/|
o | 3: 'F'
| | | |
...@@ -357,11 +361,7 @@ ...@@ -357,11 +361,7 @@
| | | |
| | o 4: 'G' | o 2: 'E'
| |/| |/
| o | 3: 'F' | o 1: 'B'
| | |
| | o 2: 'E'
| |/
o | 1: 'B'
|/ |/
o 0: 'A' o 0: 'A'
......
...@@ -52,7 +52,11 @@ ...@@ -52,7 +52,11 @@
saved backup bundle to $TESTTMP/a1/.hg/strip-backup/*-backup.hg (glob) saved backup bundle to $TESTTMP/a1/.hg/strip-backup/*-backup.hg (glob)
$ hg tglog $ hg tglog
@ 7: 'D' @ 7: 'D'
|\ |
| o 6: 'H' o 6: 'H'
|
| o 5: 'G'
|/|
o | 4: 'F'
| | | |
...@@ -58,9 +62,5 @@ ...@@ -58,9 +62,5 @@
| | | |
| | o 5: 'G' | o 3: 'E'
| |/| |/
| o | 4: 'F' | o 2: 'C'
| | |
| | o 3: 'E'
| |/
o | 2: 'C'
| | | |
...@@ -66,5 +66,5 @@ ...@@ -66,5 +66,5 @@
| | | |
o | 1: 'B' | o 1: 'B'
|/ |/
o 0: 'A' o 0: 'A'
...@@ -80,15 +80,11 @@ ...@@ -80,15 +80,11 @@
saved backup bundle to $TESTTMP/a2/.hg/strip-backup/*-backup.hg (glob) saved backup bundle to $TESTTMP/a2/.hg/strip-backup/*-backup.hg (glob)
$ hg tglog $ hg tglog
@ 7: 'D' @ 7: 'D'
|\ |
| | o 6: 'H' | o 6: 'H'
| |/ |/
| | o 5: 'G' | o 5: 'G'
| |/| |/|
| o | 4: 'F' o | 4: 'F'
| | |
| | o 3: 'E'
| |/
o | 2: 'C'
| | | |
...@@ -94,5 +90,9 @@ ...@@ -94,5 +90,9 @@
| | | |
o | 1: 'B' | o 3: 'E'
|/
| o 2: 'C'
| |
| o 1: 'B'
|/ |/
o 0: 'A' o 0: 'A'
...@@ -303,9 +303,9 @@ ...@@ -303,9 +303,9 @@
$ hg log --template "{phase}\n" -r 9 $ hg log --template "{phase}\n" -r 9
secret secret
Source phase lower than destination phase: new changeset get the phase of destination: Source phase lower than destination phase: new changeset get the phase of destination:
$ hg rebase -s7 -d9 $ hg rebase -s8 -d9
saved backup bundle to $TESTTMP/a7/.hg/strip-backup/c9659aac0000-backup.hg (glob) saved backup bundle to $TESTTMP/a7/.hg/strip-backup/6d4f22462821-backup.hg
$ hg log --template "{phase}\n" -r 9 $ hg log --template "{phase}\n" -r 'rev(9)'
secret secret
$ cd .. $ cd ..
...@@ -404,9 +404,13 @@ ...@@ -404,9 +404,13 @@
| |
o 10: 'G' o 10: 'G'
| |
o 9: 'D' o 9: 'D'
|\ |
| | o 8: 'I' | o 8: 'I'
| | | | |
| | o 7: 'H' | o 7: 'H'
| |
| o 6: 'G'
| |
| | o 5: 'F'
| | | | | |
...@@ -412,9 +416,3 @@ ...@@ -412,9 +416,3 @@
| | | | | |
| | o 6: 'G' | | o 4: 'E'
| | |
| | | o 5: 'F'
| | | |
| | | o 4: 'E'
| | |/
| | o 3: 'D'
| |/ | |/
...@@ -420,4 +418,6 @@ ...@@ -420,4 +418,6 @@
| |/ | |/
| o 3: 'D'
| |
| o 2: 'C' | o 2: 'C'
| | | |
o | 1: 'B' o | 1: 'B'
...@@ -441,9 +441,13 @@ ...@@ -441,9 +441,13 @@
| |
o 10: 'G' o 10: 'G'
| |
o 9: 'D' o 9: 'D'
|\ |
| | o 8: 'I' | o 8: 'I'
| | | | |
| | o 7: 'H' | o 7: 'H'
| |
| o 6: 'G'
| |
| | o 5: 'F'
| | | | | |
...@@ -449,9 +453,3 @@ ...@@ -449,9 +453,3 @@
| | | | | |
| | o 6: 'G' | | o 4: 'E'
| | |
| | | o 5: 'F'
| | | |
| | | o 4: 'E'
| | |/
| | o 3: 'D'
| |/ | |/
...@@ -457,4 +455,6 @@ ...@@ -457,4 +455,6 @@
| |/ | |/
| o 3: 'D'
| |
| o 2: 'C' | o 2: 'C'
| | | |
o | 1: 'B' o | 1: 'B'
...@@ -482,9 +482,13 @@ ...@@ -482,9 +482,13 @@
| | | |
| o 10: 'E' | o 10: 'E'
|/ |/
o 9: 'D' o 9: 'D'
|\ |
| | o 8: 'I' | o 8: 'I'
| | | | |
| | o 7: 'H' | o 7: 'H'
| |
| o 6: 'G'
| |
| | o 5: 'F'
| | | | | |
...@@ -490,9 +494,3 @@ ...@@ -490,9 +494,3 @@
| | | | | |
| | o 6: 'G' | | o 4: 'E'
| | |
| | | o 5: 'F'
| | | |
| | | o 4: 'E'
| | |/
| | o 3: 'D'
| |/ | |/
...@@ -498,4 +496,6 @@ ...@@ -498,4 +496,6 @@
| |/ | |/
| o 3: 'D'
| |
| o 2: 'C' | o 2: 'C'
| | | |
o | 1: 'B' o | 1: 'B'
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment