##// END OF EJS Templates
rebase: don't rebase obsolete commit whose successor is already rebased...
Laurent Charignon -
r26349:92409f8d default
parent child Browse files
Show More
@@ -26,6 +26,7 b' import os, errno'
26 revtodo = -1
26 revtodo = -1
27 nullmerge = -2
27 nullmerge = -2
28 revignored = -3
28 revignored = -3
29 revprecursor = -4
29
30
30 cmdtable = {}
31 cmdtable = {}
31 command = cmdutil.command(cmdtable)
32 command = cmdutil.command(cmdtable)
@@ -333,7 +334,20 b' def rebase(ui, repo, **opts):'
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'))
@@ -439,6 +453,12 b' def rebase(ui, repo, **opts):'
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]]))
@@ -620,7 +640,7 b' def defineparents(repo, rev, target, sta'
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
@@ -636,7 +656,7 b' def defineparents(repo, rev, target, sta'
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
@@ -824,7 +844,8 b' def restorestatus(repo):'
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
@@ -912,7 +933,7 b' def abort(repo, originalwd, target, stat'
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
@@ -999,6 +1020,8 b' def buildstate(repo, dest, rebaseset, co'
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):
@@ -1107,6 +1130,32 b' def _rebasedvisible(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
@@ -203,10 +203,9 b' More complex case were part of the rebas'
203 |/
203 |/
204 o 0:cd010b8cd998 A
204 o 0:cd010b8cd998 A
205
205
206 $ hg rebase --source 'desc(B)' --dest 'tip'
206 $ hg rebase --source 'desc(B)' --dest 'tip' --config experimental.rebaseskipobsolete=True
207 rebasing 8:8877864f1edb "B"
207 rebasing 8:8877864f1edb "B"
208 rebasing 9:08483444fef9 "D"
208 note: not rebasing 9:08483444fef9 "D", already in destination as 11:4596109a6a43 "D"
209 note: rebase of 9:08483444fef9 created no changes to commit
210 rebasing 10:5ae4c968c6ac "C"
209 rebasing 10:5ae4c968c6ac "C"
211 $ hg debugobsolete
210 $ hg debugobsolete
212 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 {cd010b8cd998f3981a5a8115f94f8da4ab506089} (*) {'user': 'test'} (glob)
211 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 {cd010b8cd998f3981a5a8115f94f8da4ab506089} (*) {'user': 'test'} (glob)
@@ -214,7 +213,6 b' More complex case were part of the rebas'
214 32af7686d403cf45b5d95f2d70cebea587ac806a 0 {5fddd98957c8a54a4d436dfe1da9d87f21a1b97b} (*) {'user': 'test'} (glob)
213 32af7686d403cf45b5d95f2d70cebea587ac806a 0 {5fddd98957c8a54a4d436dfe1da9d87f21a1b97b} (*) {'user': 'test'} (glob)
215 08483444fef91d6224f6655ee586a65d263ad34c 4596109a6a4328c398bde3a4a3b6737cfade3003 0 (*) {'user': 'test'} (glob)
214 08483444fef91d6224f6655ee586a65d263ad34c 4596109a6a4328c398bde3a4a3b6737cfade3003 0 (*) {'user': 'test'} (glob)
216 8877864f1edb05d0e07dc4ba77b67a80a7b86672 462a34d07e599b87ea08676a449373fe4e2e1347 0 (*) {'user': 'test'} (glob)
215 8877864f1edb05d0e07dc4ba77b67a80a7b86672 462a34d07e599b87ea08676a449373fe4e2e1347 0 (*) {'user': 'test'} (glob)
217 08483444fef91d6224f6655ee586a65d263ad34c 0 {8877864f1edb05d0e07dc4ba77b67a80a7b86672} (*) {'user': 'test'} (glob)
218 5ae4c968c6aca831df823664e706c9d4aa34473d 98f6af4ee9539e14da4465128f894c274900b6e5 0 (*) {'user': 'test'} (glob)
216 5ae4c968c6aca831df823664e706c9d4aa34473d 98f6af4ee9539e14da4465128f894c274900b6e5 0 (*) {'user': 'test'} (glob)
219 $ hg log --rev 'divergent()'
217 $ hg log --rev 'divergent()'
220 $ hg log -G
218 $ hg log -G
@@ -540,3 +538,55 b' Test hidden changesets in the rebase set'
540 |/
538 |/
541 o 0:cd010b8cd998 A
539 o 0:cd010b8cd998 A
542
540
541 $ hg up 14 -C
542 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
543 $ echo "K" > K
544 $ hg add K
545 $ hg commit --amend -m "K"
546 $ echo "L" > L
547 $ hg add L
548 $ hg commit -m "L"
549 $ hg up '.^'
550 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
551 $ echo "M" > M
552 $ hg add M
553 $ hg commit --amend -m "M"
554 $ hg log -G
555 @ 20:bfaedf8eb73b M
556 |
557 | o 18:97219452e4bd L
558 | |
559 | x 17:fc37a630c901 K
560 |/
561 | o 15:5ae8a643467b J
562 | |
563 | x 14:9ad579b4a5de I
564 |/
565 | o 12:acd174b7ab39 I
566 | |
567 | o 11:6c11a6218c97 H
568 | |
569 o | 10:b5313c85b22e D
570 |/
571 | o 8:53a6a128b2b7 M
572 | |\
573 | | x 7:02de42196ebe H
574 | | |
575 o---+ 6:eea13746799a G
576 | | |
577 | | o 5:24b6387c8c8c F
578 | | |
579 o---+ 4:9520eea781bc E
580 / /
581 x | 3:32af7686d403 D
582 | |
583 o | 2:5fddd98957c8 C
584 | |
585 o | 1:42ccdea3bb16 B
586 |/
587 o 0:cd010b8cd998 A
588
589 $ hg rebase -s 14 -d 18 --config experimental.rebaseskipobsolete=True
590 note: not rebasing 14:9ad579b4a5de "I", already in destination as 17:fc37a630c901 "K"
591 rebasing 15:5ae8a643467b "J"
592
General Comments 0
You need to be logged in to leave comments. Login now