##// END OF EJS Templates
rebase: change internal format to support destination map...
Jun Wu -
r34006:af609bb3 default
parent child Browse files
Show More
@@ -0,0 +1,76 b''
1 Test rebase --continue with rebasestate written by legacy client
2
3 $ cat >> $HGRCPATH <<EOF
4 > [extensions]
5 > rebase=
6 > drawdag=$TESTDIR/drawdag.py
7 > EOF
8
9 $ hg init
10 $ hg debugdrawdag <<'EOF'
11 > D H
12 > | |
13 > C G
14 > | |
15 > B F
16 > | |
17 > Z A E
18 > \|/
19 > R
20 > EOF
21
22 rebasestate generated by a legacy client running "hg rebase -r B+D+E+G+H -d Z"
23
24 $ touch .hg/last-message.txt
25 $ cat > .hg/rebasestate <<EOF
26 > 0000000000000000000000000000000000000000
27 > f424eb6a8c01c4a0c0fba9f863f79b3eb5b4b69f
28 > 0000000000000000000000000000000000000000
29 > 0
30 > 0
31 > 0
32 >
33 > 21a6c45028857f500f56ae84fbf40689c429305b:-2
34 > de008c61a447fcfd93f808ef527d933a84048ce7:0000000000000000000000000000000000000000
35 > c1e6b162678d07d0b204e5c8267d51b4e03b633c:0000000000000000000000000000000000000000
36 > aeba276fcb7df8e10153a07ee728d5540693f5aa:-3
37 > bd5548558fcf354d37613005737a143871bf3723:-3
38 > d2fa1c02b2401b0e32867f26cce50818a4bd796a:0000000000000000000000000000000000000000
39 > 6f7a236de6852570cd54649ab62b1012bb78abc8:0000000000000000000000000000000000000000
40 > 6582e6951a9c48c236f746f186378e36f59f4928:0000000000000000000000000000000000000000
41 > EOF
42
43 $ hg rebase --continue
44 rebasing 4:c1e6b162678d "B" (B)
45 rebasing 8:6f7a236de685 "D" (D)
46 rebasing 2:de008c61a447 "E" (E)
47 rebasing 7:d2fa1c02b240 "G" (G)
48 rebasing 9:6582e6951a9c "H" (H tip)
49 warning: orphaned descendants detected, not stripping c1e6b162678d, de008c61a447
50 saved backup bundle to $TESTTMP/.hg/strip-backup/6f7a236de685-9880a3dc-rebase.hg (glob)
51
52 $ hg log -G -T '{rev}:{node|short} {desc}\n'
53 o 11:721b8da0a708 H
54 |
55 o 10:9d65695ec3c2 G
56 |
57 o 9:21c8397a5d68 E
58 |
59 | o 8:fc52970345e8 D
60 | |
61 | o 7:eac96551b107 B
62 |/
63 | o 6:bd5548558fcf C
64 | |
65 | | o 5:aeba276fcb7d F
66 | | |
67 | o | 4:c1e6b162678d B
68 | | |
69 o | | 3:f424eb6a8c01 Z
70 | | |
71 +---o 2:de008c61a447 E
72 | |
73 | o 1:21a6c4502885 A
74 |/
75 o 0:b41ce7760717 R
76
@@ -21,7 +21,6 b' import os'
21
21
22 from mercurial.i18n import _
22 from mercurial.i18n import _
23 from mercurial.node import (
23 from mercurial.node import (
24 hex,
25 nullid,
24 nullid,
26 nullrev,
25 nullrev,
27 short,
26 short,
@@ -60,6 +59,7 b' templateopts = cmdutil.templateopts'
60
59
61 # Indicates that a revision needs to be rebased
60 # Indicates that a revision needs to be rebased
62 revtodo = -1
61 revtodo = -1
62 revtodostr = '-1'
63
63
64 # legacy revstates no longer needed in current code
64 # legacy revstates no longer needed in current code
65 # -2: nullmerge, -3: revignored, -4: revprecursor, -5: revpruned
65 # -2: nullmerge, -3: revignored, -4: revprecursor, -5: revpruned
@@ -146,7 +146,7 b' class rebaseruntime(object):'
146 # dict will be what contains most of the rebase progress state.
146 # dict will be what contains most of the rebase progress state.
147 self.state = {}
147 self.state = {}
148 self.activebookmark = None
148 self.activebookmark = None
149 self.dest = None
149 self.destmap = {}
150 self.skipped = set()
150 self.skipped = set()
151
151
152 self.collapsef = opts.get('collapse', False)
152 self.collapsef = opts.get('collapse', False)
@@ -177,34 +177,34 b' class rebaseruntime(object):'
177 def _writestatus(self, f):
177 def _writestatus(self, f):
178 repo = self.repo.unfiltered()
178 repo = self.repo.unfiltered()
179 f.write(repo[self.originalwd].hex() + '\n')
179 f.write(repo[self.originalwd].hex() + '\n')
180 f.write(repo[self.dest].hex() + '\n')
180 # was "dest". we now write dest per src root below.
181 f.write('\n')
181 f.write(repo[self.external].hex() + '\n')
182 f.write(repo[self.external].hex() + '\n')
182 f.write('%d\n' % int(self.collapsef))
183 f.write('%d\n' % int(self.collapsef))
183 f.write('%d\n' % int(self.keepf))
184 f.write('%d\n' % int(self.keepf))
184 f.write('%d\n' % int(self.keepbranchesf))
185 f.write('%d\n' % int(self.keepbranchesf))
185 f.write('%s\n' % (self.activebookmark or ''))
186 f.write('%s\n' % (self.activebookmark or ''))
187 destmap = self.destmap
186 for d, v in self.state.iteritems():
188 for d, v in self.state.iteritems():
187 oldrev = repo[d].hex()
189 oldrev = repo[d].hex()
188 if v >= 0:
190 if v >= 0:
189 newrev = repo[v].hex()
191 newrev = repo[v].hex()
190 elif v == revtodo:
191 # To maintain format compatibility, we have to use nullid.
192 # Please do remove this special case when upgrading the format.
193 newrev = hex(nullid)
194 else:
192 else:
195 newrev = v
193 newrev = v
196 f.write("%s:%s\n" % (oldrev, newrev))
194 destnode = repo[destmap[d]].hex()
195 f.write("%s:%s:%s\n" % (oldrev, newrev, destnode))
197 repo.ui.debug('rebase status stored\n')
196 repo.ui.debug('rebase status stored\n')
198
197
199 def restorestatus(self):
198 def restorestatus(self):
200 """Restore a previously stored status"""
199 """Restore a previously stored status"""
201 repo = self.repo
200 repo = self.repo
202 keepbranches = None
201 keepbranches = None
203 dest = None
202 legacydest = None
204 collapse = False
203 collapse = False
205 external = nullrev
204 external = nullrev
206 activebookmark = None
205 activebookmark = None
207 state = {}
206 state = {}
207 destmap = {}
208
208
209 try:
209 try:
210 f = repo.vfs("rebasestate")
210 f = repo.vfs("rebasestate")
@@ -212,7 +212,10 b' class rebaseruntime(object):'
212 if i == 0:
212 if i == 0:
213 originalwd = repo[l].rev()
213 originalwd = repo[l].rev()
214 elif i == 1:
214 elif i == 1:
215 dest = repo[l].rev()
215 # this line should be empty in newer version. but legacy
216 # clients may still use it
217 if l:
218 legacydest = repo[l].rev()
216 elif i == 2:
219 elif i == 2:
217 external = repo[l].rev()
220 external = repo[l].rev()
218 elif i == 3:
221 elif i == 3:
@@ -227,10 +230,17 b' class rebaseruntime(object):'
227 # oldrev:newrev lines
230 # oldrev:newrev lines
228 activebookmark = l
231 activebookmark = l
229 else:
232 else:
230 oldrev, newrev = l.split(':')
233 args = l.split(':')
234 oldrev = args[0]
235 newrev = args[1]
231 if newrev in legacystates:
236 if newrev in legacystates:
232 continue
237 continue
233 elif newrev == nullid:
238 if len(args) > 2:
239 destnode = args[2]
240 else:
241 destnode = legacydest
242 destmap[repo[oldrev].rev()] = repo[destnode].rev()
243 if newrev in (nullid, revtodostr):
234 state[repo[oldrev].rev()] = revtodo
244 state[repo[oldrev].rev()] = revtodo
235 # Legacy compat special case
245 # Legacy compat special case
236 else:
246 else:
@@ -247,7 +257,7 b' class rebaseruntime(object):'
247 skipped = set()
257 skipped = set()
248 # recompute the set of skipped revs
258 # recompute the set of skipped revs
249 if not collapse:
259 if not collapse:
250 seen = {dest}
260 seen = set(destmap.values())
251 for old, new in sorted(state.items()):
261 for old, new in sorted(state.items()):
252 if new != revtodo and new in seen:
262 if new != revtodo and new in seen:
253 skipped.add(old)
263 skipped.add(old)
@@ -258,7 +268,7 b' class rebaseruntime(object):'
258 _setrebasesetvisibility(repo, set(state.keys()) | {originalwd})
268 _setrebasesetvisibility(repo, set(state.keys()) | {originalwd})
259
269
260 self.originalwd = originalwd
270 self.originalwd = originalwd
261 self.dest = dest
271 self.destmap = destmap
262 self.state = state
272 self.state = state
263 self.skipped = skipped
273 self.skipped = skipped
264 self.collapsef = collapse
274 self.collapsef = collapse
@@ -267,12 +277,11 b' class rebaseruntime(object):'
267 self.external = external
277 self.external = external
268 self.activebookmark = activebookmark
278 self.activebookmark = activebookmark
269
279
270 def _handleskippingobsolete(self, rebaserevs, obsoleterevs, dest):
280 def _handleskippingobsolete(self, obsoleterevs, destmap):
271 """Compute structures necessary for skipping obsolete revisions
281 """Compute structures necessary for skipping obsolete revisions
272
282
273 rebaserevs: iterable of all revisions that are to be rebased
274 obsoleterevs: iterable of all obsolete revisions in rebaseset
283 obsoleterevs: iterable of all obsolete revisions in rebaseset
275 dest: a destination revision for the rebase operation
284 destmap: {srcrev: destrev} destination revisions
276 """
285 """
277 self.obsoletenotrebased = {}
286 self.obsoletenotrebased = {}
278 if not self.ui.configbool('experimental', 'rebaseskipobsolete',
287 if not self.ui.configbool('experimental', 'rebaseskipobsolete',
@@ -280,7 +289,7 b' class rebaseruntime(object):'
280 return
289 return
281 obsoleteset = set(obsoleterevs)
290 obsoleteset = set(obsoleterevs)
282 self.obsoletenotrebased = _computeobsoletenotrebased(self.repo,
291 self.obsoletenotrebased = _computeobsoletenotrebased(self.repo,
283 obsoleteset, dest)
292 obsoleteset, destmap)
284 skippedset = set(self.obsoletenotrebased)
293 skippedset = set(self.obsoletenotrebased)
285 _checkobsrebase(self.repo, self.ui, obsoleteset, skippedset)
294 _checkobsrebase(self.repo, self.ui, obsoleteset, skippedset)
286
295
@@ -300,13 +309,14 b' class rebaseruntime(object):'
300 hint = _('use "hg rebase --abort" to clear broken state')
309 hint = _('use "hg rebase --abort" to clear broken state')
301 raise error.Abort(msg, hint=hint)
310 raise error.Abort(msg, hint=hint)
302 if isabort:
311 if isabort:
303 return abort(self.repo, self.originalwd, self.dest,
312 return abort(self.repo, self.originalwd, self.destmap,
304 self.state, activebookmark=self.activebookmark)
313 self.state, activebookmark=self.activebookmark)
305
314
306 def _preparenewrebase(self, dest, rebaseset):
315 def _preparenewrebase(self, destmap):
307 if dest is None:
316 if not destmap:
308 return _nothingtorebase()
317 return _nothingtorebase()
309
318
319 rebaseset = destmap.keys()
310 allowunstable = obsolete.isenabled(self.repo, obsolete.allowunstableopt)
320 allowunstable = obsolete.isenabled(self.repo, obsolete.allowunstableopt)
311 if (not (self.keepf or allowunstable)
321 if (not (self.keepf or allowunstable)
312 and self.repo.revs('first(children(%ld) - %ld)',
322 and self.repo.revs('first(children(%ld) - %ld)',
@@ -316,10 +326,10 b' class rebaseruntime(object):'
316 " unrebased descendants"),
326 " unrebased descendants"),
317 hint=_('use --keep to keep original changesets'))
327 hint=_('use --keep to keep original changesets'))
318
328
319 obsrevs = _filterobsoleterevs(self.repo, set(rebaseset))
329 obsrevs = _filterobsoleterevs(self.repo, rebaseset)
320 self._handleskippingobsolete(rebaseset, obsrevs, dest.rev())
330 self._handleskippingobsolete(obsrevs, destmap)
321
331
322 result = buildstate(self.repo, dest, rebaseset, self.collapsef,
332 result = buildstate(self.repo, destmap, self.collapsef,
323 self.obsoletenotrebased)
333 self.obsoletenotrebased)
324
334
325 if not result:
335 if not result:
@@ -333,14 +343,21 b' class rebaseruntime(object):'
333 % root,
343 % root,
334 hint=_("see 'hg help phases' for details"))
344 hint=_("see 'hg help phases' for details"))
335
345
336 (self.originalwd, self.dest, self.state) = result
346 (self.originalwd, self.destmap, self.state) = result
337 if self.collapsef:
347 if self.collapsef:
338 destancestors = self.repo.changelog.ancestors([self.dest],
348 dests = set(self.destmap.values())
349 if len(dests) != 1:
350 raise error.Abort(
351 _('--collapse does not work with multiple destinations'))
352 destrev = next(iter(dests))
353 destancestors = self.repo.changelog.ancestors([destrev],
339 inclusive=True)
354 inclusive=True)
340 self.external = externalparent(self.repo, self.state, destancestors)
355 self.external = externalparent(self.repo, self.state, destancestors)
341
356
342 if dest.closesbranch() and not self.keepbranchesf:
357 for destrev in sorted(set(destmap.values())):
343 self.ui.status(_('reopening closed branch head %s\n') % dest)
358 dest = self.repo[destrev]
359 if dest.closesbranch() and not self.keepbranchesf:
360 self.ui.status(_('reopening closed branch head %s\n') % dest)
344
361
345 def _performrebase(self, tr):
362 def _performrebase(self, tr):
346 repo, ui, opts = self.repo, self.ui, self.opts
363 repo, ui, opts = self.repo, self.ui, self.opts
@@ -371,6 +388,7 b' class rebaseruntime(object):'
371 total = len(cands)
388 total = len(cands)
372 pos = 0
389 pos = 0
373 for rev in sortedrevs:
390 for rev in sortedrevs:
391 dest = self.destmap[rev]
374 ctx = repo[rev]
392 ctx = repo[rev]
375 desc = _ctxdesc(ctx)
393 desc = _ctxdesc(ctx)
376 if self.state[rev] == rev:
394 if self.state[rev] == rev:
@@ -380,7 +398,8 b' class rebaseruntime(object):'
380 ui.status(_('rebasing %s\n') % desc)
398 ui.status(_('rebasing %s\n') % desc)
381 ui.progress(_("rebasing"), pos, ("%d:%s" % (rev, ctx)),
399 ui.progress(_("rebasing"), pos, ("%d:%s" % (rev, ctx)),
382 _('changesets'), total)
400 _('changesets'), total)
383 p1, p2, base = defineparents(repo, rev, self.dest, self.state)
401 p1, p2, base = defineparents(repo, rev, self.destmap,
402 self.state)
384 self.storestatus(tr=tr)
403 self.storestatus(tr=tr)
385 storecollapsemsg(repo, self.collapsemsg)
404 storecollapsemsg(repo, self.collapsemsg)
386 if len(repo[None].parents()) == 2:
405 if len(repo[None].parents()) == 2:
@@ -390,7 +409,7 b' class rebaseruntime(object):'
390 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
409 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
391 'rebase')
410 'rebase')
392 stats = rebasenode(repo, rev, p1, base, self.state,
411 stats = rebasenode(repo, rev, p1, base, self.state,
393 self.collapsef, self.dest)
412 self.collapsef, dest)
394 if stats and stats[3] > 0:
413 if stats and stats[3] > 0:
395 raise error.InterventionRequired(
414 raise error.InterventionRequired(
396 _('unresolved conflicts (see hg '
415 _('unresolved conflicts (see hg '
@@ -436,8 +455,8 b' class rebaseruntime(object):'
436 def _finishrebase(self):
455 def _finishrebase(self):
437 repo, ui, opts = self.repo, self.ui, self.opts
456 repo, ui, opts = self.repo, self.ui, self.opts
438 if self.collapsef and not self.keepopen:
457 if self.collapsef and not self.keepopen:
439 p1, p2, _base = defineparents(repo, min(self.state),
458 p1, p2, _base = defineparents(repo, min(self.state), self.destmap,
440 self.dest, self.state)
459 self.state)
441 editopt = opts.get('edit')
460 editopt = opts.get('edit')
442 editform = 'rebase.collapse'
461 editform = 'rebase.collapse'
443 if self.collapsemsg:
462 if self.collapsemsg:
@@ -483,7 +502,7 b' class rebaseruntime(object):'
483 collapsedas = None
502 collapsedas = None
484 if self.collapsef:
503 if self.collapsef:
485 collapsedas = newnode
504 collapsedas = newnode
486 clearrebased(ui, repo, self.dest, self.state, self.skipped,
505 clearrebased(ui, repo, self.destmap, self.state, self.skipped,
487 collapsedas)
506 collapsedas)
488
507
489 clearstatus(repo)
508 clearstatus(repo)
@@ -675,9 +694,9 b' def rebase(ui, repo, **opts):'
675 if retcode is not None:
694 if retcode is not None:
676 return retcode
695 return retcode
677 else:
696 else:
678 dest, rebaseset = _definesets(ui, repo, destf, srcf, basef, revf,
697 destmap = _definedestmap(ui, repo, destf, srcf, basef, revf,
679 destspace=destspace)
698 destspace=destspace)
680 retcode = rbsrt._preparenewrebase(dest, rebaseset)
699 retcode = rbsrt._preparenewrebase(destmap)
681 if retcode is not None:
700 if retcode is not None:
682 return retcode
701 return retcode
683
702
@@ -695,10 +714,9 b' def rebase(ui, repo, **opts):'
695
714
696 rbsrt._finishrebase()
715 rbsrt._finishrebase()
697
716
698 def _definesets(ui, repo, destf=None, srcf=None, basef=None, revf=None,
717 def _definedestmap(ui, repo, destf=None, srcf=None, basef=None, revf=None,
699 destspace=None):
718 destspace=None):
700 """use revisions argument to define destination and rebase set
719 """use revisions argument to define destmap {srcrev: destrev}"""
701 """
702 if revf is None:
720 if revf is None:
703 revf = []
721 revf = []
704
722
@@ -725,12 +743,12 b' def _definesets(ui, repo, destf=None, sr'
725 rebaseset = scmutil.revrange(repo, revf)
743 rebaseset = scmutil.revrange(repo, revf)
726 if not rebaseset:
744 if not rebaseset:
727 ui.status(_('empty "rev" revision set - nothing to rebase\n'))
745 ui.status(_('empty "rev" revision set - nothing to rebase\n'))
728 return None, None
746 return None
729 elif srcf:
747 elif srcf:
730 src = scmutil.revrange(repo, [srcf])
748 src = scmutil.revrange(repo, [srcf])
731 if not src:
749 if not src:
732 ui.status(_('empty "source" revision set - nothing to rebase\n'))
750 ui.status(_('empty "source" revision set - nothing to rebase\n'))
733 return None, None
751 return None
734 rebaseset = repo.revs('(%ld)::', src)
752 rebaseset = repo.revs('(%ld)::', src)
735 assert rebaseset
753 assert rebaseset
736 else:
754 else:
@@ -738,7 +756,7 b' def _definesets(ui, repo, destf=None, sr'
738 if not base:
756 if not base:
739 ui.status(_('empty "base" revision set - '
757 ui.status(_('empty "base" revision set - '
740 "can't compute rebase set\n"))
758 "can't compute rebase set\n"))
741 return None, None
759 return None
742 if not destf:
760 if not destf:
743 dest = repo[_destrebase(repo, base, destspace=destspace)]
761 dest = repo[_destrebase(repo, base, destspace=destspace)]
744 destf = str(dest)
762 destf = str(dest)
@@ -782,13 +800,17 b' def _definesets(ui, repo, destf=None, sr'
782 else: # can it happen?
800 else: # can it happen?
783 ui.status(_('nothing to rebase from %s to %s\n') %
801 ui.status(_('nothing to rebase from %s to %s\n') %
784 ('+'.join(str(repo[r]) for r in base), dest))
802 ('+'.join(str(repo[r]) for r in base), dest))
785 return None, None
803 return None
786
804
787 if not destf:
805 if not destf:
788 dest = repo[_destrebase(repo, rebaseset, destspace=destspace)]
806 dest = repo[_destrebase(repo, rebaseset, destspace=destspace)]
789 destf = str(dest)
807 destf = str(dest)
790
808
791 return dest, rebaseset
809 # assign dest to each rev in rebaseset
810 destrev = dest.rev()
811 destmap = {r: destrev for r in rebaseset} # {srcrev: destrev}
812
813 return destmap
792
814
793 def externalparent(repo, state, destancestors):
815 def externalparent(repo, state, destancestors):
794 """Return the revision that should be used as the second parent
816 """Return the revision that should be used as the second parent
@@ -874,7 +896,7 b' def rebasenode(repo, rev, p1, base, stat'
874 copies.duplicatecopies(repo, rev, p1rev, skiprev=dest)
896 copies.duplicatecopies(repo, rev, p1rev, skiprev=dest)
875 return stats
897 return stats
876
898
877 def adjustdest(repo, rev, dest, state):
899 def adjustdest(repo, rev, destmap, state):
878 """adjust rebase destination given the current rebase state
900 """adjust rebase destination given the current rebase state
879
901
880 rev is what is being rebased. Return a list of two revs, which are the
902 rev is what is being rebased. Return a list of two revs, which are the
@@ -914,8 +936,9 b' def adjustdest(repo, rev, dest, state):'
914 |/ |/
936 |/ |/
915 A A
937 A A
916 """
938 """
917 # pick already rebased revs from state
939 # pick already rebased revs with same dest from state as interesting source
918 source = [s for s, d in state.items() if d > 0]
940 dest = destmap[rev]
941 source = [s for s, d in state.items() if d > 0 and destmap[s] == dest]
919
942
920 result = []
943 result = []
921 for prev in repo.changelog.parentrevs(rev):
944 for prev in repo.changelog.parentrevs(rev):
@@ -957,7 +980,7 b' def successorrevs(repo, rev):'
957 if s in nodemap:
980 if s in nodemap:
958 yield nodemap[s]
981 yield nodemap[s]
959
982
960 def defineparents(repo, rev, dest, state):
983 def defineparents(repo, rev, destmap, state):
961 """Return new parents and optionally a merge base for rev being rebased
984 """Return new parents and optionally a merge base for rev being rebased
962
985
963 The destination specified by "dest" cannot always be used directly because
986 The destination specified by "dest" cannot always be used directly because
@@ -981,9 +1004,10 b' def defineparents(repo, rev, dest, state'
981 return False
1004 return False
982 return cl.isancestor(cl.node(a), cl.node(b))
1005 return cl.isancestor(cl.node(a), cl.node(b))
983
1006
1007 dest = destmap[rev]
984 oldps = repo.changelog.parentrevs(rev) # old parents
1008 oldps = repo.changelog.parentrevs(rev) # old parents
985 newps = [nullrev, nullrev] # new parents
1009 newps = [nullrev, nullrev] # new parents
986 dests = adjustdest(repo, rev, dest, state) # adjusted destinations
1010 dests = adjustdest(repo, rev, destmap, state) # adjusted destinations
987 bases = list(oldps) # merge base candidates, initially just old parents
1011 bases = list(oldps) # merge base candidates, initially just old parents
988
1012
989 if all(r == nullrev for r in oldps[1:]):
1013 if all(r == nullrev for r in oldps[1:]):
@@ -1238,7 +1262,7 b' def needupdate(repo, state):'
1238
1262
1239 return False
1263 return False
1240
1264
1241 def abort(repo, originalwd, dest, state, activebookmark=None):
1265 def abort(repo, originalwd, destmap, state, activebookmark=None):
1242 '''Restore the repository to its original state. Additional args:
1266 '''Restore the repository to its original state. Additional args:
1243
1267
1244 activebookmark: the name of the bookmark that should be active after the
1268 activebookmark: the name of the bookmark that should be active after the
@@ -1248,7 +1272,7 b' def abort(repo, originalwd, dest, state,'
1248 # If the first commits in the rebased set get skipped during the rebase,
1272 # If the first commits in the rebased set get skipped during the rebase,
1249 # their values within the state mapping will be the dest rev id. The
1273 # their values within the state mapping will be the dest rev id. The
1250 # dstates list must must not contain the dest rev (issue4896)
1274 # dstates list must must not contain the dest rev (issue4896)
1251 dstates = [s for s in state.values() if s >= 0 and s != dest]
1275 dstates = [s for r, s in state.items() if s >= 0 and s != destmap[r]]
1252 immutable = [d for d in dstates if not repo[d].mutable()]
1276 immutable = [d for d in dstates if not repo[d].mutable()]
1253 cleanup = True
1277 cleanup = True
1254 if immutable:
1278 if immutable:
@@ -1267,13 +1291,14 b' def abort(repo, originalwd, dest, state,'
1267
1291
1268 if cleanup:
1292 if cleanup:
1269 shouldupdate = False
1293 shouldupdate = False
1270 rebased = filter(lambda x: x >= 0 and x != dest, state.values())
1294 rebased = [s for r, s in state.items()
1295 if s >= 0 and s != destmap[r]]
1271 if rebased:
1296 if rebased:
1272 strippoints = [
1297 strippoints = [
1273 c.node() for c in repo.set('roots(%ld)', rebased)]
1298 c.node() for c in repo.set('roots(%ld)', rebased)]
1274
1299
1275 updateifonnodes = set(rebased)
1300 updateifonnodes = set(rebased)
1276 updateifonnodes.add(dest)
1301 updateifonnodes.update(destmap.values())
1277 updateifonnodes.add(originalwd)
1302 updateifonnodes.add(originalwd)
1278 shouldupdate = repo['.'].rev() in updateifonnodes
1303 shouldupdate = repo['.'].rev() in updateifonnodes
1279
1304
@@ -1295,22 +1320,23 b' def abort(repo, originalwd, dest, state,'
1295 repo.ui.warn(_('rebase aborted\n'))
1320 repo.ui.warn(_('rebase aborted\n'))
1296 return 0
1321 return 0
1297
1322
1298 def buildstate(repo, dest, rebaseset, collapse, obsoletenotrebased):
1323 def buildstate(repo, destmap, collapse, obsoletenotrebased):
1299 '''Define which revisions are going to be rebased and where
1324 '''Define which revisions are going to be rebased and where
1300
1325
1301 repo: repo
1326 repo: repo
1302 dest: context
1327 destmap: {srcrev: destrev}
1303 rebaseset: set of rev
1304 '''
1328 '''
1329 rebaseset = destmap.keys()
1305 originalwd = repo['.'].rev()
1330 originalwd = repo['.'].rev()
1306 _setrebasesetvisibility(repo, set(rebaseset) | {originalwd})
1331 _setrebasesetvisibility(repo, set(rebaseset) | {originalwd})
1307
1332
1308 # This check isn't strictly necessary, since mq detects commits over an
1333 # This check isn't strictly necessary, since mq detects commits over an
1309 # applied patch. But it prevents messing up the working directory when
1334 # applied patch. But it prevents messing up the working directory when
1310 # a partially completed rebase is blocked by mq.
1335 # a partially completed rebase is blocked by mq.
1311 if 'qtip' in repo.tags() and (dest.node() in
1336 if 'qtip' in repo.tags():
1312 [s.node for s in repo.mq.applied]):
1337 mqapplied = set(repo[s.node].rev() for s in repo.mq.applied)
1313 raise error.Abort(_('cannot rebase onto an applied mq patch'))
1338 if set(destmap.values()) & mqapplied:
1339 raise error.Abort(_('cannot rebase onto an applied mq patch'))
1314
1340
1315 roots = list(repo.set('roots(%ld)', rebaseset))
1341 roots = list(repo.set('roots(%ld)', rebaseset))
1316 if not roots:
1342 if not roots:
@@ -1319,6 +1345,7 b' def buildstate(repo, dest, rebaseset, co'
1319 state = dict.fromkeys(rebaseset, revtodo)
1345 state = dict.fromkeys(rebaseset, revtodo)
1320 emptyrebase = True
1346 emptyrebase = True
1321 for root in roots:
1347 for root in roots:
1348 dest = repo[destmap[root.rev()]]
1322 commonbase = root.ancestor(dest)
1349 commonbase = root.ancestor(dest)
1323 if commonbase == root:
1350 if commonbase == root:
1324 raise error.Abort(_('source is ancestor of destination'))
1351 raise error.Abort(_('source is ancestor of destination'))
@@ -1352,6 +1379,7 b' def buildstate(repo, dest, rebaseset, co'
1352 if succ is None:
1379 if succ is None:
1353 msg = _('note: not rebasing %s, it has no successor\n') % desc
1380 msg = _('note: not rebasing %s, it has no successor\n') % desc
1354 del state[r]
1381 del state[r]
1382 del destmap[r]
1355 else:
1383 else:
1356 destctx = unfi[succ]
1384 destctx = unfi[succ]
1357 destdesc = '%d:%s "%s"' % (destctx.rev(), destctx,
1385 destdesc = '%d:%s "%s"' % (destctx.rev(), destctx,
@@ -1359,10 +1387,11 b' def buildstate(repo, dest, rebaseset, co'
1359 msg = (_('note: not rebasing %s, already in destination as %s\n')
1387 msg = (_('note: not rebasing %s, already in destination as %s\n')
1360 % (desc, destdesc))
1388 % (desc, destdesc))
1361 del state[r]
1389 del state[r]
1390 del destmap[r]
1362 repo.ui.status(msg)
1391 repo.ui.status(msg)
1363 return originalwd, dest.rev(), state
1392 return originalwd, destmap, state
1364
1393
1365 def clearrebased(ui, repo, dest, state, skipped, collapsedas=None):
1394 def clearrebased(ui, repo, destmap, state, skipped, collapsedas=None):
1366 """dispose of rebased revision at the end of the rebase
1395 """dispose of rebased revision at the end of the rebase
1367
1396
1368 If `collapsedas` is not None, the rebase was a collapse whose result if the
1397 If `collapsedas` is not None, the rebase was a collapse whose result if the
@@ -1371,7 +1400,7 b' def clearrebased(ui, repo, dest, state, '
1371 # Move bookmark of skipped nodes to destination. This cannot be handled
1400 # Move bookmark of skipped nodes to destination. This cannot be handled
1372 # by scmutil.cleanupnodes since it will treat rev as removed (no successor)
1401 # by scmutil.cleanupnodes since it will treat rev as removed (no successor)
1373 # and move bookmark backwards.
1402 # and move bookmark backwards.
1374 bmchanges = [(name, tonode(max(adjustdest(repo, rev, dest, state))))
1403 bmchanges = [(name, tonode(max(adjustdest(repo, rev, destmap, state))))
1375 for rev in skipped
1404 for rev in skipped
1376 for name in repo.nodebookmarks(tonode(rev))]
1405 for name in repo.nodebookmarks(tonode(rev))]
1377 if bmchanges:
1406 if bmchanges:
@@ -1477,7 +1506,7 b' def _filterobsoleterevs(repo, revs):'
1477 """returns a set of the obsolete revisions in revs"""
1506 """returns a set of the obsolete revisions in revs"""
1478 return set(r for r in revs if repo[r].obsolete())
1507 return set(r for r in revs if repo[r].obsolete())
1479
1508
1480 def _computeobsoletenotrebased(repo, rebaseobsrevs, dest):
1509 def _computeobsoletenotrebased(repo, rebaseobsrevs, destmap):
1481 """return a mapping obsolete => successor for all obsolete nodes to be
1510 """return a mapping obsolete => successor for all obsolete nodes to be
1482 rebased that have a successors in the destination
1511 rebased that have a successors in the destination
1483
1512
@@ -1486,9 +1515,9 b' def _computeobsoletenotrebased(repo, reb'
1486
1515
1487 cl = repo.unfiltered().changelog
1516 cl = repo.unfiltered().changelog
1488 nodemap = cl.nodemap
1517 nodemap = cl.nodemap
1489 destnode = cl.node(dest)
1490 for srcrev in rebaseobsrevs:
1518 for srcrev in rebaseobsrevs:
1491 srcnode = cl.node(srcrev)
1519 srcnode = cl.node(srcrev)
1520 destnode = cl.node(destmap[srcrev])
1492 # XXX: more advanced APIs are required to handle split correctly
1521 # XXX: more advanced APIs are required to handle split correctly
1493 successors = list(obsutil.allsuccessors(repo.obsstore, [srcnode]))
1522 successors = list(obsutil.allsuccessors(repo.obsstore, [srcnode]))
1494 if len(successors) == 1:
1523 if len(successors) == 1:
General Comments 0
You need to be logged in to leave comments. Login now