Show More
@@ -327,11 +327,7 b' class rebaseruntime(object):' | |||||
327 | " unrebased descendants"), |
|
327 | " unrebased descendants"), | |
328 | hint=_('use --keep to keep original changesets')) |
|
328 | hint=_('use --keep to keep original changesets')) | |
329 |
|
329 | |||
330 |
|
|
330 | result = buildstate(self.repo, destmap, self.collapsef) | |
331 | self._handleskippingobsolete(obsrevs, destmap) |
|
|||
332 |
|
||||
333 | result = buildstate(self.repo, destmap, self.collapsef, |
|
|||
334 | self.obsoletenotrebased) |
|
|||
335 |
|
331 | |||
336 | if not result: |
|
332 | if not result: | |
337 | # Empty state built, nothing to rebase |
|
333 | # Empty state built, nothing to rebase | |
@@ -375,6 +371,10 b' class rebaseruntime(object):' | |||||
375 | raise error.Abort(_('cannot collapse multiple named ' |
|
371 | raise error.Abort(_('cannot collapse multiple named ' | |
376 | 'branches')) |
|
372 | 'branches')) | |
377 |
|
373 | |||
|
374 | # Calculate self.obsoletenotrebased | |||
|
375 | obsrevs = _filterobsoleterevs(self.repo, self.state) | |||
|
376 | self._handleskippingobsolete(obsrevs, self.destmap) | |||
|
377 | ||||
378 | # Keep track of the active bookmarks in order to reset them later |
|
378 | # Keep track of the active bookmarks in order to reset them later | |
379 | self.activebookmark = self.activebookmark or repo._activebookmark |
|
379 | self.activebookmark = self.activebookmark or repo._activebookmark | |
380 | if self.activebookmark: |
|
380 | if self.activebookmark: | |
@@ -401,13 +401,34 b' class rebaseruntime(object):' | |||||
401 | desc = _ctxdesc(ctx) |
|
401 | desc = _ctxdesc(ctx) | |
402 | if self.state[rev] == rev: |
|
402 | if self.state[rev] == rev: | |
403 | ui.status(_('already rebased %s\n') % desc) |
|
403 | ui.status(_('already rebased %s\n') % desc) | |
|
404 | elif rev in self.obsoletenotrebased: | |||
|
405 | succ = self.obsoletenotrebased[rev] | |||
|
406 | if succ is None: | |||
|
407 | msg = _('note: not rebasing %s, it has no ' | |||
|
408 | 'successor\n') % desc | |||
|
409 | else: | |||
|
410 | succctx = repo[succ] | |||
|
411 | succdesc = '%d:%s "%s"' % ( | |||
|
412 | succctx.rev(), succctx, | |||
|
413 | succctx.description().split('\n', 1)[0]) | |||
|
414 | msg = (_('note: not rebasing %s, already in ' | |||
|
415 | 'destination as %s\n') % (desc, succdesc)) | |||
|
416 | repo.ui.status(msg) | |||
|
417 | # Make clearrebased aware state[rev] is not a true successor | |||
|
418 | self.skipped.add(rev) | |||
|
419 | # Record rev as moved to its desired destination in self.state. | |||
|
420 | # This helps bookmark and working parent movement. | |||
|
421 | dest = max(adjustdest(repo, rev, self.destmap, self.state, | |||
|
422 | self.skipped)) | |||
|
423 | self.state[rev] = dest | |||
404 | elif self.state[rev] == revtodo: |
|
424 | elif self.state[rev] == revtodo: | |
405 | pos += 1 |
|
425 | pos += 1 | |
406 | ui.status(_('rebasing %s\n') % desc) |
|
426 | ui.status(_('rebasing %s\n') % desc) | |
407 | ui.progress(_("rebasing"), pos, ("%d:%s" % (rev, ctx)), |
|
427 | ui.progress(_("rebasing"), pos, ("%d:%s" % (rev, ctx)), | |
408 | _('changesets'), total) |
|
428 | _('changesets'), total) | |
409 | p1, p2, base = defineparents(repo, rev, self.destmap, |
|
429 | p1, p2, base = defineparents(repo, rev, self.destmap, | |
410 |
self.state |
|
430 | self.state, self.skipped, | |
|
431 | self.obsoletenotrebased) | |||
411 | self.storestatus(tr=tr) |
|
432 | self.storestatus(tr=tr) | |
412 | storecollapsemsg(repo, self.collapsemsg) |
|
433 | storecollapsemsg(repo, self.collapsemsg) | |
413 | if len(repo[None].parents()) == 2: |
|
434 | if len(repo[None].parents()) == 2: | |
@@ -462,7 +483,8 b' class rebaseruntime(object):' | |||||
462 | repo, ui, opts = self.repo, self.ui, self.opts |
|
483 | repo, ui, opts = self.repo, self.ui, self.opts | |
463 | if self.collapsef and not self.keepopen: |
|
484 | if self.collapsef and not self.keepopen: | |
464 | p1, p2, _base = defineparents(repo, min(self.state), self.destmap, |
|
485 | p1, p2, _base = defineparents(repo, min(self.state), self.destmap, | |
465 |
self.state |
|
486 | self.state, self.skipped, | |
|
487 | self.obsoletenotrebased) | |||
466 | editopt = opts.get('edit') |
|
488 | editopt = opts.get('edit') | |
467 | editform = 'rebase.collapse' |
|
489 | editform = 'rebase.collapse' | |
468 | if self.collapsemsg: |
|
490 | if self.collapsemsg: | |
@@ -935,7 +957,7 b' def rebasenode(repo, rev, p1, base, stat' | |||||
935 | copies.duplicatecopies(repo, rev, p1rev, skiprev=dest) |
|
957 | copies.duplicatecopies(repo, rev, p1rev, skiprev=dest) | |
936 | return stats |
|
958 | return stats | |
937 |
|
959 | |||
938 | def adjustdest(repo, rev, destmap, state): |
|
960 | def adjustdest(repo, rev, destmap, state, skipped): | |
939 | """adjust rebase destination given the current rebase state |
|
961 | """adjust rebase destination given the current rebase state | |
940 |
|
962 | |||
941 | rev is what is being rebased. Return a list of two revs, which are the |
|
963 | rev is what is being rebased. Return a list of two revs, which are the | |
@@ -989,7 +1011,8 b' def adjustdest(repo, rev, destmap, state' | |||||
989 | """ |
|
1011 | """ | |
990 | # pick already rebased revs with same dest from state as interesting source |
|
1012 | # pick already rebased revs with same dest from state as interesting source | |
991 | dest = destmap[rev] |
|
1013 | dest = destmap[rev] | |
992 |
source = [s for s, d in state.items() |
|
1014 | source = [s for s, d in state.items() | |
|
1015 | if d > 0 and destmap[s] == dest and s not in skipped] | |||
993 |
|
1016 | |||
994 | result = [] |
|
1017 | result = [] | |
995 | for prev in repo.changelog.parentrevs(rev): |
|
1018 | for prev in repo.changelog.parentrevs(rev): | |
@@ -1037,7 +1060,7 b' def successorrevs(repo, rev):' | |||||
1037 | if s in nodemap: |
|
1060 | if s in nodemap: | |
1038 | yield nodemap[s] |
|
1061 | yield nodemap[s] | |
1039 |
|
1062 | |||
1040 | def defineparents(repo, rev, destmap, state): |
|
1063 | def defineparents(repo, rev, destmap, state, skipped, obsskipped): | |
1041 | """Return new parents and optionally a merge base for rev being rebased |
|
1064 | """Return new parents and optionally a merge base for rev being rebased | |
1042 |
|
1065 | |||
1043 | The destination specified by "dest" cannot always be used directly because |
|
1066 | The destination specified by "dest" cannot always be used directly because | |
@@ -1064,7 +1087,7 b' def defineparents(repo, rev, destmap, st' | |||||
1064 | dest = destmap[rev] |
|
1087 | dest = destmap[rev] | |
1065 | oldps = repo.changelog.parentrevs(rev) # old parents |
|
1088 | oldps = repo.changelog.parentrevs(rev) # old parents | |
1066 | newps = [nullrev, nullrev] # new parents |
|
1089 | newps = [nullrev, nullrev] # new parents | |
1067 |
dests = adjustdest(repo, rev, destmap, state) |
|
1090 | dests = adjustdest(repo, rev, destmap, state, skipped) | |
1068 | bases = list(oldps) # merge base candidates, initially just old parents |
|
1091 | bases = list(oldps) # merge base candidates, initially just old parents | |
1069 |
|
1092 | |||
1070 | if all(r == nullrev for r in oldps[1:]): |
|
1093 | if all(r == nullrev for r in oldps[1:]): | |
@@ -1191,7 +1214,8 b' def defineparents(repo, rev, destmap, st' | |||||
1191 | # If those revisions are covered by rebaseset, the result is good. |
|
1214 | # If those revisions are covered by rebaseset, the result is good. | |
1192 | # A merge in rebaseset would be considered to cover its ancestors. |
|
1215 | # A merge in rebaseset would be considered to cover its ancestors. | |
1193 | if siderevs: |
|
1216 | if siderevs: | |
1194 |
rebaseset = [r for r, d in state.items() |
|
1217 | rebaseset = [r for r, d in state.items() | |
|
1218 | if d > 0 and r not in obsskipped] | |||
1195 | merges = [r for r in rebaseset |
|
1219 | merges = [r for r in rebaseset | |
1196 | if cl.parentrevs(r)[1] != nullrev] |
|
1220 | if cl.parentrevs(r)[1] != nullrev] | |
1197 | unwanted[i] = list(repo.revs('%ld - (::%ld) - %ld', |
|
1221 | unwanted[i] = list(repo.revs('%ld - (::%ld) - %ld', | |
@@ -1408,7 +1432,7 b' def sortsource(destmap):' | |||||
1408 | srcset -= set(result) |
|
1432 | srcset -= set(result) | |
1409 | yield result |
|
1433 | yield result | |
1410 |
|
1434 | |||
1411 |
def buildstate(repo, destmap, collapse |
|
1435 | def buildstate(repo, destmap, collapse): | |
1412 | '''Define which revisions are going to be rebased and where |
|
1436 | '''Define which revisions are going to be rebased and where | |
1413 |
|
1437 | |||
1414 | repo: repo |
|
1438 | repo: repo | |
@@ -1469,23 +1493,6 b' def buildstate(repo, destmap, collapse, ' | |||||
1469 | # if all parents of this revision are done, then so is this revision |
|
1493 | # if all parents of this revision are done, then so is this revision | |
1470 | if parents and all((state.get(p) == p for p in parents)): |
|
1494 | if parents and all((state.get(p) == p for p in parents)): | |
1471 | state[rev] = rev |
|
1495 | state[rev] = rev | |
1472 | unfi = repo.unfiltered() |
|
|||
1473 | for r in obsoletenotrebased: |
|
|||
1474 | desc = _ctxdesc(unfi[r]) |
|
|||
1475 | succ = obsoletenotrebased[r] |
|
|||
1476 | if succ is None: |
|
|||
1477 | msg = _('note: not rebasing %s, it has no successor\n') % desc |
|
|||
1478 | del state[r] |
|
|||
1479 | del destmap[r] |
|
|||
1480 | else: |
|
|||
1481 | destctx = unfi[succ] |
|
|||
1482 | destdesc = '%d:%s "%s"' % (destctx.rev(), destctx, |
|
|||
1483 | destctx.description().split('\n', 1)[0]) |
|
|||
1484 | msg = (_('note: not rebasing %s, already in destination as %s\n') |
|
|||
1485 | % (desc, destdesc)) |
|
|||
1486 | del state[r] |
|
|||
1487 | del destmap[r] |
|
|||
1488 | repo.ui.status(msg) |
|
|||
1489 | return originalwd, destmap, state |
|
1496 | return originalwd, destmap, state | |
1490 |
|
1497 | |||
1491 | def clearrebased(ui, repo, destmap, state, skipped, collapsedas=None): |
|
1498 | def clearrebased(ui, repo, destmap, state, skipped, collapsedas=None): |
@@ -205,8 +205,8 b' More complex case where part of the reba' | |||||
205 | o 0:cd010b8cd998 A |
|
205 | o 0:cd010b8cd998 A | |
206 |
|
206 | |||
207 | $ hg rebase --source 'desc(B)' --dest 'tip' --config experimental.rebaseskipobsolete=True |
|
207 | $ hg rebase --source 'desc(B)' --dest 'tip' --config experimental.rebaseskipobsolete=True | |
|
208 | rebasing 8:8877864f1edb "B" | |||
208 | note: not rebasing 9:08483444fef9 "D", already in destination as 11:4596109a6a43 "D" |
|
209 | note: not rebasing 9:08483444fef9 "D", already in destination as 11:4596109a6a43 "D" | |
209 | rebasing 8:8877864f1edb "B" |
|
|||
210 | rebasing 10:5ae4c968c6ac "C" |
|
210 | rebasing 10:5ae4c968c6ac "C" | |
211 | $ hg debugobsolete |
|
211 | $ hg debugobsolete | |
212 | 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 {cd010b8cd998f3981a5a8115f94f8da4ab506089} (*) {'user': 'test'} (glob) |
|
212 | 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 {cd010b8cd998f3981a5a8115f94f8da4ab506089} (*) {'user': 'test'} (glob) | |
@@ -736,8 +736,8 b' Even when the chain include missing node' | |||||
736 | $ hg debugobsolete `hg log -r 7 -T '{node}\n'` --config experimental.stabilization=all |
|
736 | $ hg debugobsolete `hg log -r 7 -T '{node}\n'` --config experimental.stabilization=all | |
737 | obsoleted 1 changesets |
|
737 | obsoleted 1 changesets | |
738 | $ hg rebase -d 6 -r "4::" |
|
738 | $ hg rebase -d 6 -r "4::" | |
|
739 | rebasing 4:ff2c4d47b71d "C" | |||
739 | note: not rebasing 7:360bbaa7d3ce "O", it has no successor |
|
740 | note: not rebasing 7:360bbaa7d3ce "O", it has no successor | |
740 | rebasing 4:ff2c4d47b71d "C" |
|
|||
741 | rebasing 8:8d47583e023f "P" (tip) |
|
741 | rebasing 8:8d47583e023f "P" (tip) | |
742 |
|
742 | |||
743 | If all the changeset to be rebased are obsolete and present in the destination, we |
|
743 | If all the changeset to be rebased are obsolete and present in the destination, we | |
@@ -769,10 +769,8 b' should display a friendly error message' | |||||
769 | If a rebase is going to create divergence, it should abort |
|
769 | If a rebase is going to create divergence, it should abort | |
770 |
|
770 | |||
771 | $ hg log -G |
|
771 | $ hg log -G | |
772 | @ 11:f44da1f4954c nonrelevant |
|
772 | @ 10:121d9e3bc4c6 P | |
773 | | |
|
773 | | | |
774 | | o 10:121d9e3bc4c6 P |
|
|||
775 | |/ |
|
|||
776 | o 9:4be60e099a77 C |
|
774 | o 9:4be60e099a77 C | |
777 | | |
|
775 | | | |
778 | o 6:9c48361117de D |
|
776 | o 6:9c48361117de D | |
@@ -904,7 +902,6 b' Create the changes that we will rebase' | |||||
904 | | |
|
902 | | | |
905 | ~ |
|
903 | ~ | |
906 | $ hg rebase -r ".^^ + .^ + ." -d 19 |
|
904 | $ hg rebase -r ".^^ + .^ + ." -d 19 | |
907 | note: not rebasing 21:8b31da3c4919 "dummy change", already in destination as 19:601db7a18f51 "dummy change successor" |
|
|||
908 | rebasing 20:b82fb57ea638 "willconflict second version" |
|
905 | rebasing 20:b82fb57ea638 "willconflict second version" | |
909 | merging willconflict |
|
906 | merging willconflict | |
910 | warning: conflicts while merging willconflict! (edit, then use 'hg resolve --mark') |
|
907 | warning: conflicts while merging willconflict! (edit, then use 'hg resolve --mark') | |
@@ -916,6 +913,7 b' Create the changes that we will rebase' | |||||
916 | continue: hg rebase --continue |
|
913 | continue: hg rebase --continue | |
917 | $ hg rebase --continue |
|
914 | $ hg rebase --continue | |
918 | rebasing 20:b82fb57ea638 "willconflict second version" |
|
915 | rebasing 20:b82fb57ea638 "willconflict second version" | |
|
916 | note: not rebasing 21:8b31da3c4919 "dummy change", already in destination as 19:601db7a18f51 "dummy change successor" | |||
919 | rebasing 22:7bdc8a87673d "dummy change" (tip) |
|
917 | rebasing 22:7bdc8a87673d "dummy change" (tip) | |
920 | $ cd .. |
|
918 | $ cd .. | |
921 |
|
919 | |||
@@ -1062,8 +1060,8 b' Rebase merge where successor of one pare' | |||||
1062 | > EOF |
|
1060 | > EOF | |
1063 |
|
1061 | |||
1064 | $ hg rebase -d C -b F |
|
1062 | $ hg rebase -d C -b F | |
|
1063 | rebasing 2:b18e25de2cf5 "D" (D) | |||
1065 | note: not rebasing 3:7fb047a69f22 "E" (E), already in destination as 1:112478962961 "B" |
|
1064 | note: not rebasing 3:7fb047a69f22 "E" (E), already in destination as 1:112478962961 "B" | |
1066 | rebasing 2:b18e25de2cf5 "D" (D) |
|
|||
1067 | rebasing 5:66f1a38021c9 "F" (F tip) |
|
1065 | rebasing 5:66f1a38021c9 "F" (F tip) | |
1068 | note: rebase of 5:66f1a38021c9 created no changes to commit |
|
1066 | note: rebase of 5:66f1a38021c9 created no changes to commit | |
1069 | $ hg log -G |
|
1067 | $ hg log -G | |
@@ -1179,8 +1177,8 b' parent moves as requested.' | |||||
1179 | > A B C # D/D = D |
|
1177 | > A B C # D/D = D | |
1180 | > EOS |
|
1178 | > EOS | |
1181 | $ hg rebase -r B+A+D -d Z |
|
1179 | $ hg rebase -r B+A+D -d Z | |
|
1180 | rebasing 0:426bada5c675 "A" (A) | |||
1182 | note: not rebasing 1:fc2b737bb2e5 "B" (B), already in destination as 2:96cc3511f894 "C" |
|
1181 | note: not rebasing 1:fc2b737bb2e5 "B" (B), already in destination as 2:96cc3511f894 "C" | |
1183 | rebasing 0:426bada5c675 "A" (A) |
|
|||
1184 | rebasing 3:b8ed089c80ad "D" (D) |
|
1182 | rebasing 3:b8ed089c80ad "D" (D) | |
1185 |
|
1183 | |||
1186 | $ rm .hg/localtags |
|
1184 | $ rm .hg/localtags | |
@@ -1226,17 +1224,46 b' equivalents in destination' | |||||
1226 | 2:1e9a3c00cbe9 b (no-eol) |
|
1224 | 2:1e9a3c00cbe9 b (no-eol) | |
1227 | $ hg rebase -r 2 -d 3 --config experimental.stabilization.track-operation=1 |
|
1225 | $ hg rebase -r 2 -d 3 --config experimental.stabilization.track-operation=1 | |
1228 | note: not rebasing 2:1e9a3c00cbe9 "b" (mybook), already in destination as 3:be1832deae9a "b" |
|
1226 | note: not rebasing 2:1e9a3c00cbe9 "b" (mybook), already in destination as 3:be1832deae9a "b" | |
1229 |
Check that working directory was |
|
1227 | Check that working directory and bookmark was updated to rev 3 although rev 2 | |
1230 | during the rebase operation |
|
1228 | was skipped | |
1231 | $ hg log -r . |
|
1229 | $ hg log -r . | |
1232 |
|
|
1230 | 3:be1832deae9a b (no-eol) | |
1233 |
|
||||
1234 | Check that bookmark was not moved to rev 3 if rev 2 was skipped during the |
|
|||
1235 | rebase operation. This makes sense because if rev 2 has a successor, the |
|
|||
1236 | operation generating that successor (ex. rebase) should be responsible for |
|
|||
1237 | moving bookmarks. If the bookmark is on a precursor, like rev 2, that means the |
|
|||
1238 | user manually moved it back. In that case we should not move it again. |
|
|||
1239 | $ hg bookmarks |
|
1231 | $ hg bookmarks | |
1240 |
mybook |
|
1232 | mybook 3:be1832deae9a | |
1241 | $ hg debugobsolete --rev tip |
|
1233 | $ hg debugobsolete --rev tip | |
1242 | 1e9a3c00cbe90d236ac05ef61efcc5e40b7412bc be1832deae9ac531caa7438b8dcf6055a122cd8e 0 (*) {'user': 'test'} (glob) |
|
1234 | 1e9a3c00cbe90d236ac05ef61efcc5e40b7412bc be1832deae9ac531caa7438b8dcf6055a122cd8e 0 (*) {'user': 'test'} (glob) | |
|
1235 | ||||
|
1236 | Obsoleted working parent and bookmark could be moved if an ancestor of working | |||
|
1237 | parent gets moved: | |||
|
1238 | ||||
|
1239 | $ hg init $TESTTMP/ancestor-wd-move | |||
|
1240 | $ cd $TESTTMP/ancestor-wd-move | |||
|
1241 | $ hg debugdrawdag <<'EOS' | |||
|
1242 | > E D1 # rebase: D1 -> D2 | |||
|
1243 | > | | | |||
|
1244 | > | C | |||
|
1245 | > D2 | | |||
|
1246 | > | B | |||
|
1247 | > |/ | |||
|
1248 | > A | |||
|
1249 | > EOS | |||
|
1250 | $ hg update D1 -q | |||
|
1251 | $ hg bookmark book -i | |||
|
1252 | $ hg rebase -r B+D1 -d E | |||
|
1253 | rebasing 1:112478962961 "B" (B) | |||
|
1254 | note: not rebasing 5:15ecf15e0114 "D1" (D1 tip book), already in destination as 2:0807738e0be9 "D2" | |||
|
1255 | $ hg log -G -T '{desc} {bookmarks}' | |||
|
1256 | @ B book | |||
|
1257 | | | |||
|
1258 | | x D1 | |||
|
1259 | | | | |||
|
1260 | o | E | |||
|
1261 | | | | |||
|
1262 | | o C | |||
|
1263 | | | | |||
|
1264 | o | D2 | |||
|
1265 | | | | |||
|
1266 | | x B | |||
|
1267 | |/ | |||
|
1268 | o A | |||
|
1269 |
General Comments 0
You need to be logged in to leave comments.
Login now