368 for rev in sortedstate: |
368 for rev in sortedstate: |
369 pos += 1 |
369 pos += 1 |
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) |
377 if len(repo.parents()) == 2: |
377 if len(repo.parents()) == 2: |
378 repo.ui.debug('resuming interrupted rebase\n') |
378 repo.ui.debug('resuming interrupted rebase\n') |
379 else: |
379 else: |
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 ' |
388 'resolve, then hg rebase --continue)')) |
388 'resolve, then hg rebase --continue)')) |
389 finally: |
389 finally: |
412 |
412 |
413 ui.progress(_('rebasing'), None) |
413 ui.progress(_('rebasing'), None) |
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' |
421 if collapsemsg: |
421 if collapsemsg: |
422 commitmsg = collapsemsg |
422 commitmsg = collapsemsg |
423 else: |
423 else: |
507 'than one external parent: %s') % |
507 'than one external parent: %s') % |
508 (max(targetancestors), |
508 (max(targetancestors), |
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() |
516 repo.setparents(repo[p1].node(), repo[p2].node()) |
517 repo.setparents(repo[p1].node(), repo[p2].node()) |
517 repo.dirstate.endparentchange() |
518 repo.dirstate.endparentchange() |
537 except util.Abort: |
538 except util.Abort: |
538 # Invalidate the previous setparents |
539 # Invalidate the previous setparents |
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: |
547 repo.ui.debug(" update to %d:%s\n" % (p1, repo[p1])) |
548 repo.ui.debug(" update to %d:%s\n" % (p1, repo[p1])) |
548 merge.update(repo, p1, False, True, False) |
549 merge.update(repo, p1, False, True, False) |
549 else: |
550 else: |
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 |
598 # have to allow merging with it. |
557 # have to allow merging with it. |
599 stats = merge.update(repo, rev, True, True, False, base, collapse, |
558 stats = merge.update(repo, rev, True, True, False, base, collapse, |
658 raise util.Abort(_('cannot use revision %d as base, result ' |
617 raise util.Abort(_('cannot use revision %d as base, result ' |
659 'would have 3 parents') % rev) |
618 'would have 3 parents') % rev) |
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' |
667 mqpatch = os.path.join(repo.mq.path, patchname) |
669 mqpatch = os.path.join(repo.mq.path, patchname) |
668 for line in patch.linereader(file(mqpatch, 'rb')): |
670 for line in patch.linereader(file(mqpatch, 'rb')): |