##// END OF EJS Templates
rebase: move base calculation from rebasenode() to defineparents()...
Mads Kiilerich -
r23484:cf3495df default
parent child Browse files
Show More
@@ -370,7 +370,7 def rebase(ui, repo, **opts):
370 if state[rev] == -1:
370 if state[rev] == -1:
371 ui.progress(_("rebasing"), pos, ("%d:%s" % (rev, repo[rev])),
371 ui.progress(_("rebasing"), pos, ("%d:%s" % (rev, repo[rev])),
372 _('changesets'), total)
372 _('changesets'), total)
373 p1, p2 = defineparents(repo, rev, target, state,
373 p1, p2, base = defineparents(repo, rev, target, state,
374 targetancestors)
374 targetancestors)
375 storestatus(repo, originalwd, target, state, collapsef, keepf,
375 storestatus(repo, originalwd, target, state, collapsef, keepf,
376 keepbranchesf, external, activebookmark)
376 keepbranchesf, external, activebookmark)
@@ -380,8 +380,8 def rebase(ui, repo, **opts):
380 try:
380 try:
381 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
381 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
382 'rebase')
382 'rebase')
383 stats = rebasenode(repo, rev, p1, state, collapsef,
383 stats = rebasenode(repo, rev, p1, base, state,
384 target)
384 collapsef, target)
385 if stats and stats[3] > 0:
385 if stats and stats[3] > 0:
386 raise error.InterventionRequired(
386 raise error.InterventionRequired(
387 _('unresolved conflicts (see hg '
387 _('unresolved conflicts (see hg '
@@ -414,7 +414,7 def rebase(ui, repo, **opts):
414 ui.note(_('rebase merging completed\n'))
414 ui.note(_('rebase merging completed\n'))
415
415
416 if collapsef and not keepopen:
416 if collapsef and not keepopen:
417 p1, p2 = defineparents(repo, min(state), target,
417 p1, p2, _base = defineparents(repo, min(state), target,
418 state, targetancestors)
418 state, targetancestors)
419 editopt = opts.get('edit')
419 editopt = opts.get('edit')
420 editform = 'rebase.collapse'
420 editform = 'rebase.collapse'
@@ -509,7 +509,8 def externalparent(repo, state, targetan
509 ', '.join(str(p) for p in sorted(parents))))
509 ', '.join(str(p) for p in sorted(parents))))
510
510
511 def concludenode(repo, rev, p1, p2, commitmsg=None, editor=None, extrafn=None):
511 def concludenode(repo, rev, p1, p2, commitmsg=None, editor=None, extrafn=None):
512 '''Commit the changes and store useful information in extra.
512 '''Commit the wd changes with parents p1 and p2. Reuse commit info from rev
513 but also store useful information in extra.
513 Return node of committed revision.'''
514 Return node of committed revision.'''
514 try:
515 try:
515 repo.dirstate.beginparentchange()
516 repo.dirstate.beginparentchange()
@@ -539,8 +540,8 def concludenode(repo, rev, p1, p2, comm
539 repo.dirstate.invalidate()
540 repo.dirstate.invalidate()
540 raise
541 raise
541
542
542 def rebasenode(repo, rev, p1, state, collapse, target):
543 def rebasenode(repo, rev, p1, base, state, collapse, target):
543 'Rebase a single revision'
544 'Rebase a single revision rev on top of p1 using base as merge ancestor'
544 # Merge phase
545 # Merge phase
545 # Update to target and merge it with local
546 # Update to target and merge it with local
546 if repo['.'].rev() != p1:
547 if repo['.'].rev() != p1:
@@ -550,48 +551,6 def rebasenode(repo, rev, p1, state, col
550 repo.ui.debug(" already in target\n")
551 repo.ui.debug(" already in target\n")
551 repo.dirstate.write()
552 repo.dirstate.write()
552 repo.ui.debug(" merge against %d:%s\n" % (rev, repo[rev]))
553 repo.ui.debug(" merge against %d:%s\n" % (rev, repo[rev]))
553 if rev == min(state):
554 # Case (1) initial changeset of a non-detaching rebase.
555 # Let the merge mechanism find the base itself.
556 base = None
557 elif not repo[rev].p2():
558 # Case (2) detaching the node with a single parent, use this parent
559 base = repo[rev].p1().rev()
560 else:
561 # In case of merge, we need to pick the right parent as merge base.
562 #
563 # Imagine we have:
564 # - M: currently rebase revision in this step
565 # - A: one parent of M
566 # - B: second parent of M
567 # - D: destination of this merge step (p1 var)
568 #
569 # If we are rebasing on D, D is the successors of A or B. The right
570 # merge base is the one D succeed to. We pretend it is B for the rest
571 # of this comment
572 #
573 # If we pick B as the base, the merge involves:
574 # - changes from B to M (actual changeset payload)
575 # - changes from B to D (induced by rebase) as D is a rebased
576 # version of B)
577 # Which exactly represent the rebase operation.
578 #
579 # If we pick the A as the base, the merge involves
580 # - changes from A to M (actual changeset payload)
581 # - changes from A to D (with include changes between unrelated A and B
582 # plus changes induced by rebase)
583 # Which does not represent anything sensible and creates a lot of
584 # conflicts.
585 for p in repo[rev].parents():
586 if state.get(p.rev()) == p1:
587 base = p.rev()
588 break
589 else: # fallback when base not found
590 base = None
591
592 # Raise because this function is called wrong (see issue 4106)
593 raise AssertionError('no base found to rebase on '
594 '(rebasenode called wrong)')
595 if base is not None:
554 if base is not None:
596 repo.ui.debug(" detach base %d:%s\n" % (base, repo[base]))
555 repo.ui.debug(" detach base %d:%s\n" % (base, repo[base]))
597 # When collapsing in-place, the parent is the common ancestor, we
556 # When collapsing in-place, the parent is the common ancestor, we
@@ -660,7 +619,50 def defineparents(repo, rev, target, sta
660 p2 = p2n
619 p2 = p2n
661 repo.ui.debug(" future parents are %d and %d\n" %
620 repo.ui.debug(" future parents are %d and %d\n" %
662 (repo[p1].rev(), repo[p2].rev()))
621 (repo[p1].rev(), repo[p2].rev()))
663 return p1, p2
622
623 if rev == min(state):
624 # Case (1) initial changeset of a non-detaching rebase.
625 # Let the merge mechanism find the base itself.
626 base = None
627 elif not repo[rev].p2():
628 # Case (2) detaching the node with a single parent, use this parent
629 base = repo[rev].p1().rev()
630 else:
631 # In case of merge, we need to pick the right parent as merge base.
632 #
633 # Imagine we have:
634 # - M: currently rebase revision in this step
635 # - A: one parent of M
636 # - B: second parent of M
637 # - D: destination of this merge step (p1 var)
638 #
639 # If we are rebasing on D, D is the successors of A or B. The right
640 # merge base is the one D succeed to. We pretend it is B for the rest
641 # of this comment
642 #
643 # If we pick B as the base, the merge involves:
644 # - changes from B to M (actual changeset payload)
645 # - changes from B to D (induced by rebase) as D is a rebased
646 # version of B)
647 # Which exactly represent the rebase operation.
648 #
649 # If we pick the A as the base, the merge involves
650 # - changes from A to M (actual changeset payload)
651 # - changes from A to D (with include changes between unrelated A and B
652 # plus changes induced by rebase)
653 # Which does not represent anything sensible and creates a lot of
654 # conflicts.
655 for p in repo[rev].parents():
656 if state.get(p.rev()) == p1:
657 base = p.rev()
658 break
659 else: # fallback when base not found
660 base = None
661
662 # Raise because this function is called wrong (see issue 4106)
663 raise AssertionError('no base found to rebase on '
664 '(defineparents called wrong)')
665 return p1, p2, base
664
666
665 def isagitpatch(repo, patchname):
667 def isagitpatch(repo, patchname):
666 'Return true if the given patch is in git format'
668 'Return true if the given patch is in git format'
General Comments 0
You need to be logged in to leave comments. Login now