331 raise util.Abort( |
332 raise util.Abort( |
332 _("can't remove original changesets with" |
333 _("can't remove original changesets with" |
333 " unrebased descendants"), |
334 " unrebased descendants"), |
334 hint=_('use --keep to keep original changesets')) |
335 hint=_('use --keep to keep original changesets')) |
335 |
336 |
336 result = buildstate(repo, dest, rebaseset, collapsef) |
337 obsoletenotrebased = {} |
|
338 if ui.configbool('experimental', 'rebaseskipobsolete'): |
|
339 rebasesetrevs = set(rebaseset) |
|
340 obsoletenotrebased = _computeobsoletenotrebased(repo, |
|
341 rebasesetrevs, |
|
342 dest) |
|
343 |
|
344 # - plain prune (no successor) changesets are rebased |
|
345 # - split changesets are not rebased if at least one of the |
|
346 # changeset resulting from the split is an ancestor of dest |
|
347 rebaseset = rebasesetrevs - set(obsoletenotrebased) |
|
348 result = buildstate(repo, dest, rebaseset, collapsef, |
|
349 obsoletenotrebased) |
|
350 |
337 if not result: |
351 if not result: |
338 # Empty state built, nothing to rebase |
352 # Empty state built, nothing to rebase |
339 ui.status(_('nothing to rebase\n')) |
353 ui.status(_('nothing to rebase\n')) |
340 return 1 |
354 return 1 |
341 |
355 |
437 ui.debug('next revision set to %s\n' % p1) |
451 ui.debug('next revision set to %s\n' % p1) |
438 elif state[rev] == nullmerge: |
452 elif state[rev] == nullmerge: |
439 ui.debug('ignoring null merge rebase of %s\n' % rev) |
453 ui.debug('ignoring null merge rebase of %s\n' % rev) |
440 elif state[rev] == revignored: |
454 elif state[rev] == revignored: |
441 ui.status(_('not rebasing ignored %s\n') % desc) |
455 ui.status(_('not rebasing ignored %s\n') % desc) |
|
456 elif state[rev] == revprecursor: |
|
457 targetctx = repo[obsoletenotrebased[rev]] |
|
458 desctarget = '%d:%s "%s"' % (targetctx.rev(), targetctx, |
|
459 targetctx.description().split('\n', 1)[0]) |
|
460 msg = _('note: not rebasing %s, already in destination as %s\n') |
|
461 ui.status(msg % (desc, desctarget)) |
442 else: |
462 else: |
443 ui.status(_('already rebased %s as %s\n') % |
463 ui.status(_('already rebased %s as %s\n') % |
444 (desc, repo[state[rev]])) |
464 (desc, repo[state[rev]])) |
445 |
465 |
446 ui.progress(_('rebasing'), None) |
466 ui.progress(_('rebasing'), None) |
618 if p1n in targetancestors: |
638 if p1n in targetancestors: |
619 p1 = target |
639 p1 = target |
620 elif p1n in state: |
640 elif p1n in state: |
621 if state[p1n] == nullmerge: |
641 if state[p1n] == nullmerge: |
622 p1 = target |
642 p1 = target |
623 elif state[p1n] == revignored: |
643 elif state[p1n] in (revignored, revprecursor): |
624 p1 = nearestrebased(repo, p1n, state) |
644 p1 = nearestrebased(repo, p1n, state) |
625 if p1 is None: |
645 if p1 is None: |
626 p1 = target |
646 p1 = target |
627 else: |
647 else: |
628 p1 = state[p1n] |
648 p1 = state[p1n] |
634 p2n = parents[1].rev() |
654 p2n = parents[1].rev() |
635 # interesting second parent |
655 # interesting second parent |
636 if p2n in state: |
656 if p2n in state: |
637 if p1 == target: # p1n in targetancestors or external |
657 if p1 == target: # p1n in targetancestors or external |
638 p1 = state[p2n] |
658 p1 = state[p2n] |
639 elif state[p2n] == revignored: |
659 elif state[p2n] in (revignored, revprecursor): |
640 p2 = nearestrebased(repo, p2n, state) |
660 p2 = nearestrebased(repo, p2n, state) |
641 if p2 is None: |
661 if p2 is None: |
642 # no ancestors rebased yet, detach |
662 # no ancestors rebased yet, detach |
643 p2 = target |
663 p2 = target |
644 else: |
664 else: |
822 # line 6 is a recent addition, so for backwards compatibility |
842 # line 6 is a recent addition, so for backwards compatibility |
823 # check that the line doesn't look like the oldrev:newrev lines |
843 # check that the line doesn't look like the oldrev:newrev lines |
824 activebookmark = l |
844 activebookmark = l |
825 else: |
845 else: |
826 oldrev, newrev = l.split(':') |
846 oldrev, newrev = l.split(':') |
827 if newrev in (str(nullmerge), str(revignored)): |
847 if newrev in (str(nullmerge), str(revignored), |
|
848 str(revprecursor)): |
828 state[repo[oldrev].rev()] = int(newrev) |
849 state[repo[oldrev].rev()] = int(newrev) |
829 elif newrev == nullid: |
850 elif newrev == nullid: |
830 state[repo[oldrev].rev()] = revtodo |
851 state[repo[oldrev].rev()] = revtodo |
831 # Legacy compat special case |
852 # Legacy compat special case |
832 else: |
853 else: |
910 |
931 |
911 clearstatus(repo) |
932 clearstatus(repo) |
912 repo.ui.warn(_('rebase aborted\n')) |
933 repo.ui.warn(_('rebase aborted\n')) |
913 return 0 |
934 return 0 |
914 |
935 |
915 def buildstate(repo, dest, rebaseset, collapse): |
936 def buildstate(repo, dest, rebaseset, collapse, obsoletenotrebased): |
916 '''Define which revisions are going to be rebased and where |
937 '''Define which revisions are going to be rebased and where |
917 |
938 |
918 repo: repo |
939 repo: repo |
919 dest: context |
940 dest: context |
920 rebaseset: set of rev |
941 rebaseset: set of rev |
997 # the revision should be ignored but that `defineparents` should search |
1018 # the revision should be ignored but that `defineparents` should search |
998 # a rebase destination that make sense regarding rebased topology. |
1019 # a rebase destination that make sense regarding rebased topology. |
999 rebasedomain = set(repo.revs('%ld::%ld', rebaseset, rebaseset)) |
1020 rebasedomain = set(repo.revs('%ld::%ld', rebaseset, rebaseset)) |
1000 for ignored in set(rebasedomain) - set(rebaseset): |
1021 for ignored in set(rebasedomain) - set(rebaseset): |
1001 state[ignored] = revignored |
1022 state[ignored] = revignored |
|
1023 for r in obsoletenotrebased: |
|
1024 state[r] = revprecursor |
1002 return repo['.'].rev(), dest.rev(), state |
1025 return repo['.'].rev(), dest.rev(), state |
1003 |
1026 |
1004 def clearrebased(ui, repo, state, skipped, collapsedas=None): |
1027 def clearrebased(ui, repo, state, skipped, collapsedas=None): |
1005 """dispose of rebased revision at the end of the rebase |
1028 """dispose of rebased revision at the end of the rebase |
1006 |
1029 |
1105 """ensure rebased revs stay visible (see issue4505)""" |
1128 """ensure rebased revs stay visible (see issue4505)""" |
1106 blockers = orig(repo) |
1129 blockers = orig(repo) |
1107 blockers.update(getattr(repo, '_rebaseset', ())) |
1130 blockers.update(getattr(repo, '_rebaseset', ())) |
1108 return blockers |
1131 return blockers |
1109 |
1132 |
|
1133 def _computeobsoletenotrebased(repo, rebasesetrevs, dest): |
|
1134 """return a mapping obsolete => successor for all obsolete nodes to be |
|
1135 rebased that have a successors in the destination""" |
|
1136 obsoletenotrebased = {} |
|
1137 |
|
1138 # Build a mapping succesor => obsolete nodes for the obsolete |
|
1139 # nodes to be rebased |
|
1140 allsuccessors = {} |
|
1141 for r in rebasesetrevs: |
|
1142 n = repo[r] |
|
1143 if n.obsolete(): |
|
1144 node = repo.changelog.node(r) |
|
1145 for s in obsolete.allsuccessors(repo.obsstore, [node]): |
|
1146 allsuccessors[repo.changelog.rev(s)] = repo.changelog.rev(node) |
|
1147 |
|
1148 if allsuccessors: |
|
1149 # Look for successors of obsolete nodes to be rebased among |
|
1150 # the ancestors of dest |
|
1151 ancs = repo.changelog.ancestors([repo[dest].rev()], |
|
1152 stoprev=min(allsuccessors), |
|
1153 inclusive=True) |
|
1154 for s in allsuccessors: |
|
1155 if s in ancs: |
|
1156 obsoletenotrebased[allsuccessors[s]] = s |
|
1157 return obsoletenotrebased |
|
1158 |
1110 def summaryhook(ui, repo): |
1159 def summaryhook(ui, repo): |
1111 if not os.path.exists(repo.join('rebasestate')): |
1160 if not os.path.exists(repo.join('rebasestate')): |
1112 return |
1161 return |
1113 try: |
1162 try: |
1114 state = restorestatus(repo)[2] |
1163 state = restorestatus(repo)[2] |