comparison hgext/rebase.py @ 29063:8ede973597fd

rebase: handle successor targets (issue5198) When a parent has a successor (indicated by revprecursor in state), we need to use it.
author timeless <timeless@mozdev.org>
date Mon, 11 Apr 2016 21:33:07 +0000
parents 261c25372959
children e521cb13d354
comparison
equal deleted inserted replaced
29062:906a1c8a75fd 29063:8ede973597fd
388 if state[rev] == revtodo: 388 if state[rev] == revtodo:
389 ui.status(_('rebasing %s\n') % desc) 389 ui.status(_('rebasing %s\n') % desc)
390 ui.progress(_("rebasing"), pos, ("%d:%s" % (rev, ctx)), 390 ui.progress(_("rebasing"), pos, ("%d:%s" % (rev, ctx)),
391 _('changesets'), total) 391 _('changesets'), total)
392 p1, p2, base = defineparents(repo, rev, target, state, 392 p1, p2, base = defineparents(repo, rev, target, state,
393 targetancestors) 393 targetancestors,
394 obsoletenotrebased)
394 storestatus(repo, originalwd, target, state, collapsef, keepf, 395 storestatus(repo, originalwd, target, state, collapsef, keepf,
395 keepbranchesf, external, activebookmark) 396 keepbranchesf, external, activebookmark)
396 storecollapsemsg(repo, collapsemsg) 397 storecollapsemsg(repo, collapsemsg)
397 if len(repo[None].parents()) == 2: 398 if len(repo[None].parents()) == 2:
398 repo.ui.debug('resuming interrupted rebase\n') 399 repo.ui.debug('resuming interrupted rebase\n')
453 ui.progress(_('rebasing'), None) 454 ui.progress(_('rebasing'), None)
454 ui.note(_('rebase merging completed\n')) 455 ui.note(_('rebase merging completed\n'))
455 456
456 if collapsef and not keepopen: 457 if collapsef and not keepopen:
457 p1, p2, _base = defineparents(repo, min(state), target, 458 p1, p2, _base = defineparents(repo, min(state), target,
458 state, targetancestors) 459 state, targetancestors,
460 obsoletenotrebased)
459 editopt = opts.get('edit') 461 editopt = opts.get('edit')
460 editform = 'rebase.collapse' 462 editform = 'rebase.collapse'
461 if collapsemsg: 463 if collapsemsg:
462 commitmsg = collapsemsg 464 commitmsg = collapsemsg
463 else: 465 else:
742 'or were marked as obsolete') 744 'or were marked as obsolete')
743 hint = _('to force the rebase, set the config ' 745 hint = _('to force the rebase, set the config '
744 'experimental.rebaseskipobsolete to False') 746 'experimental.rebaseskipobsolete to False')
745 raise error.Abort(msg, hint=hint) 747 raise error.Abort(msg, hint=hint)
746 748
747 def defineparents(repo, rev, target, state, targetancestors): 749 def defineparents(repo, rev, target, state, targetancestors,
750 obsoletenotrebased):
748 'Return the new parent relationship of the revision that will be rebased' 751 'Return the new parent relationship of the revision that will be rebased'
749 parents = repo[rev].parents() 752 parents = repo[rev].parents()
750 p1 = p2 = nullrev 753 p1 = p2 = nullrev
754 rp1 = None
751 755
752 p1n = parents[0].rev() 756 p1n = parents[0].rev()
753 if p1n in targetancestors: 757 if p1n in targetancestors:
754 p1 = target 758 p1 = target
755 elif p1n in state: 759 elif p1n in state:
769 p2n = parents[1].rev() 773 p2n = parents[1].rev()
770 # interesting second parent 774 # interesting second parent
771 if p2n in state: 775 if p2n in state:
772 if p1 == target: # p1n in targetancestors or external 776 if p1 == target: # p1n in targetancestors or external
773 p1 = state[p2n] 777 p1 = state[p2n]
778 if p1 == revprecursor:
779 rp1 = obsoletenotrebased[p2n]
774 elif state[p2n] in revskipped: 780 elif state[p2n] in revskipped:
775 p2 = nearestrebased(repo, p2n, state) 781 p2 = nearestrebased(repo, p2n, state)
776 if p2 is None: 782 if p2 is None:
777 # no ancestors rebased yet, detach 783 # no ancestors rebased yet, detach
778 p2 = target 784 p2 = target
782 if p2 != nullrev: # p1n external too => rev is a merged revision 788 if p2 != nullrev: # p1n external too => rev is a merged revision
783 raise error.Abort(_('cannot use revision %d as base, result ' 789 raise error.Abort(_('cannot use revision %d as base, result '
784 'would have 3 parents') % rev) 790 'would have 3 parents') % rev)
785 p2 = p2n 791 p2 = p2n
786 repo.ui.debug(" future parents are %d and %d\n" % 792 repo.ui.debug(" future parents are %d and %d\n" %
787 (repo[p1].rev(), repo[p2].rev())) 793 (repo[rp1 or p1].rev(), repo[p2].rev()))
788 794
789 if not any(p.rev() in state for p in parents): 795 if not any(p.rev() in state for p in parents):
790 # Case (1) root changeset of a non-detaching rebase set. 796 # Case (1) root changeset of a non-detaching rebase set.
791 # Let the merge mechanism find the base itself. 797 # Let the merge mechanism find the base itself.
792 base = None 798 base = None
826 # or if the other is not parent 'outside' (especially not if the other 832 # or if the other is not parent 'outside' (especially not if the other
827 # parent has been rebased). The current implementation does not 833 # parent has been rebased). The current implementation does not
828 # make it feasible to consider different cases separately. In these 834 # make it feasible to consider different cases separately. In these
829 # other cases we currently just leave it to the user to correctly 835 # other cases we currently just leave it to the user to correctly
830 # resolve an impossible merge using a wrong ancestor. 836 # resolve an impossible merge using a wrong ancestor.
837 #
838 # xx, p1 could be -4, and both parents could probably be -4...
831 for p in repo[rev].parents(): 839 for p in repo[rev].parents():
832 if state.get(p.rev()) == p1: 840 if state.get(p.rev()) == p1:
833 base = p.rev() 841 base = p.rev()
834 break 842 break
835 else: # fallback when base not found 843 else: # fallback when base not found
836 base = None 844 base = None
837 845
838 # Raise because this function is called wrong (see issue 4106) 846 # Raise because this function is called wrong (see issue 4106)
839 raise AssertionError('no base found to rebase on ' 847 raise AssertionError('no base found to rebase on '
840 '(defineparents called wrong)') 848 '(defineparents called wrong)')
841 return p1, p2, base 849 return rp1 or p1, p2, base
842 850
843 def isagitpatch(repo, patchname): 851 def isagitpatch(repo, patchname):
844 'Return true if the given patch is in git format' 852 'Return true if the given patch is in git format'
845 mqpatch = os.path.join(repo.mq.path, patchname) 853 mqpatch = os.path.join(repo.mq.path, patchname)
846 for line in patch.linereader(file(mqpatch, 'rb')): 854 for line in patch.linereader(file(mqpatch, 'rb')):