comparison hgext/rebase.py @ 43076:2372284d9457

formatting: blacken the codebase This is using my patch to black (https://github.com/psf/black/pull/826) so we don't un-wrap collection literals. Done with: hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**"' | xargs black -S # skip-blame mass-reformatting only # no-check-commit reformats foo_bar functions Differential Revision: https://phab.mercurial-scm.org/D6971
author Augie Fackler <augie@google.com>
date Sun, 06 Oct 2019 09:45:02 -0400
parents 43c84b816445
children 687b865b95ad
comparison
equal deleted inserted replaced
43075:57875cf423c9 43076:2372284d9457
68 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should 68 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
69 # be specifying the version(s) of Mercurial they are tested with, or 69 # be specifying the version(s) of Mercurial they are tested with, or
70 # leave the attribute unspecified. 70 # leave the attribute unspecified.
71 testedwith = 'ships-with-hg-core' 71 testedwith = 'ships-with-hg-core'
72 72
73
73 def _nothingtorebase(): 74 def _nothingtorebase():
74 return 1 75 return 1
76
75 77
76 def _savegraft(ctx, extra): 78 def _savegraft(ctx, extra):
77 s = ctx.extra().get('source', None) 79 s = ctx.extra().get('source', None)
78 if s is not None: 80 if s is not None:
79 extra['source'] = s 81 extra['source'] = s
80 s = ctx.extra().get('intermediate-source', None) 82 s = ctx.extra().get('intermediate-source', None)
81 if s is not None: 83 if s is not None:
82 extra['intermediate-source'] = s 84 extra['intermediate-source'] = s
83 85
86
84 def _savebranch(ctx, extra): 87 def _savebranch(ctx, extra):
85 extra['branch'] = ctx.branch() 88 extra['branch'] = ctx.branch()
86 89
90
87 def _destrebase(repo, sourceset, destspace=None): 91 def _destrebase(repo, sourceset, destspace=None):
88 """small wrapper around destmerge to pass the right extra args 92 """small wrapper around destmerge to pass the right extra args
89 93
90 Please wrap destutil.destmerge instead.""" 94 Please wrap destutil.destmerge instead."""
91 return destutil.destmerge(repo, action='rebase', sourceset=sourceset, 95 return destutil.destmerge(
92 onheadcheck=False, destspace=destspace) 96 repo,
97 action='rebase',
98 sourceset=sourceset,
99 onheadcheck=False,
100 destspace=destspace,
101 )
102
93 103
94 revsetpredicate = registrar.revsetpredicate() 104 revsetpredicate = registrar.revsetpredicate()
105
95 106
96 @revsetpredicate('_destrebase') 107 @revsetpredicate('_destrebase')
97 def _revsetdestrebase(repo, subset, x): 108 def _revsetdestrebase(repo, subset, x):
98 # ``_rebasedefaultdest()`` 109 # ``_rebasedefaultdest()``
99 110
104 sourceset = None 115 sourceset = None
105 if x is not None: 116 if x is not None:
106 sourceset = revset.getset(repo, smartset.fullreposet(repo), x) 117 sourceset = revset.getset(repo, smartset.fullreposet(repo), x)
107 return subset & smartset.baseset([_destrebase(repo, sourceset)]) 118 return subset & smartset.baseset([_destrebase(repo, sourceset)])
108 119
120
109 @revsetpredicate('_destautoorphanrebase') 121 @revsetpredicate('_destautoorphanrebase')
110 def _revsetdestautoorphanrebase(repo, subset, x): 122 def _revsetdestautoorphanrebase(repo, subset, x):
111 # ``_destautoorphanrebase()`` 123 # ``_destautoorphanrebase()``
112 124
113 # automatic rebase destination for a single orphan revision. 125 # automatic rebase destination for a single orphan revision.
120 if not src or src in obsoleted: 132 if not src or src in obsoleted:
121 return smartset.baseset() 133 return smartset.baseset()
122 dests = destutil.orphanpossibledestination(repo, src) 134 dests = destutil.orphanpossibledestination(repo, src)
123 if len(dests) > 1: 135 if len(dests) > 1:
124 raise error.Abort( 136 raise error.Abort(
125 _("ambiguous automatic rebase: %r could end up on any of %r") % ( 137 _("ambiguous automatic rebase: %r could end up on any of %r")
126 src, dests)) 138 % (src, dests)
139 )
127 # We have zero or one destination, so we can just return here. 140 # We have zero or one destination, so we can just return here.
128 return smartset.baseset(dests) 141 return smartset.baseset(dests)
129 142
143
130 def _ctxdesc(ctx): 144 def _ctxdesc(ctx):
131 """short description for a context""" 145 """short description for a context"""
132 desc = '%d:%s "%s"' % (ctx.rev(), ctx, 146 desc = '%d:%s "%s"' % (ctx.rev(), ctx, ctx.description().split('\n', 1)[0])
133 ctx.description().split('\n', 1)[0])
134 repo = ctx.repo() 147 repo = ctx.repo()
135 names = [] 148 names = []
136 for nsname, ns in repo.names.iteritems(): 149 for nsname, ns in repo.names.iteritems():
137 if nsname == 'branches': 150 if nsname == 'branches':
138 continue 151 continue
139 names.extend(ns.names(repo, ctx.node())) 152 names.extend(ns.names(repo, ctx.node()))
140 if names: 153 if names:
141 desc += ' (%s)' % ' '.join(names) 154 desc += ' (%s)' % ' '.join(names)
142 return desc 155 return desc
143 156
157
144 class rebaseruntime(object): 158 class rebaseruntime(object):
145 """This class is a container for rebase runtime state""" 159 """This class is a container for rebase runtime state"""
160
146 def __init__(self, repo, ui, inmemory=False, opts=None): 161 def __init__(self, repo, ui, inmemory=False, opts=None):
147 if opts is None: 162 if opts is None:
148 opts = {} 163 opts = {}
149 164
150 # prepared: whether we have rebasestate prepared or not. Currently it 165 # prepared: whether we have rebasestate prepared or not. Currently it
172 187
173 self.collapsef = opts.get('collapse', False) 188 self.collapsef = opts.get('collapse', False)
174 self.collapsemsg = cmdutil.logmessage(ui, opts) 189 self.collapsemsg = cmdutil.logmessage(ui, opts)
175 self.date = opts.get('date', None) 190 self.date = opts.get('date', None)
176 191
177 e = opts.get('extrafn') # internal, used by e.g. hgsubversion 192 e = opts.get('extrafn') # internal, used by e.g. hgsubversion
178 self.extrafns = [_savegraft] 193 self.extrafns = [_savegraft]
179 if e: 194 if e:
180 self.extrafns = [e] 195 self.extrafns = [e]
181 196
182 self.backupf = ui.configbool('rewrite', 'backup-bundle') 197 self.backupf = ui.configbool('rewrite', 'backup-bundle')
195 return self._repo 210 return self._repo
196 211
197 def storestatus(self, tr=None): 212 def storestatus(self, tr=None):
198 """Store the current status to allow recovery""" 213 """Store the current status to allow recovery"""
199 if tr: 214 if tr:
200 tr.addfilegenerator('rebasestate', ('rebasestate',), 215 tr.addfilegenerator(
201 self._writestatus, location='plain') 216 'rebasestate',
217 ('rebasestate',),
218 self._writestatus,
219 location='plain',
220 )
202 else: 221 else:
203 with self.repo.vfs("rebasestate", "w") as f: 222 with self.repo.vfs("rebasestate", "w") as f:
204 self._writestatus(f) 223 self._writestatus(f)
205 224
206 def _writestatus(self, f): 225 def _writestatus(self, f):
245 264
246 def _read(self): 265 def _read(self):
247 self.prepared = True 266 self.prepared = True
248 repo = self.repo 267 repo = self.repo
249 assert repo.filtername is None 268 assert repo.filtername is None
250 data = {'keepbranches': None, 'collapse': None, 'activebookmark': None, 269 data = {
251 'external': nullrev, 'keep': None, 'originalwd': None} 270 'keepbranches': None,
271 'collapse': None,
272 'activebookmark': None,
273 'external': nullrev,
274 'keep': None,
275 'originalwd': None,
276 }
252 legacydest = None 277 legacydest = None
253 state = {} 278 state = {}
254 destmap = {} 279 destmap = {}
255 280
256 if True: 281 if True:
305 for old, new in sorted(state.items()): 330 for old, new in sorted(state.items()):
306 if new != revtodo and new in seen: 331 if new != revtodo and new in seen:
307 skipped.add(old) 332 skipped.add(old)
308 seen.add(new) 333 seen.add(new)
309 data['skipped'] = skipped 334 data['skipped'] = skipped
310 repo.ui.debug('computed skipped revs: %s\n' % 335 repo.ui.debug(
311 (' '.join('%d' % r for r in sorted(skipped)) or '')) 336 'computed skipped revs: %s\n'
337 % (' '.join('%d' % r for r in sorted(skipped)) or '')
338 )
312 339
313 return data 340 return data
314 341
315 def _handleskippingobsolete(self, obsoleterevs, destmap): 342 def _handleskippingobsolete(self, obsoleterevs, destmap):
316 """Compute structures necessary for skipping obsolete revisions 343 """Compute structures necessary for skipping obsolete revisions
320 """ 347 """
321 self.obsoletenotrebased = {} 348 self.obsoletenotrebased = {}
322 if not self.ui.configbool('experimental', 'rebaseskipobsolete'): 349 if not self.ui.configbool('experimental', 'rebaseskipobsolete'):
323 return 350 return
324 obsoleteset = set(obsoleterevs) 351 obsoleteset = set(obsoleterevs)
325 (self.obsoletenotrebased, 352 (
326 self.obsoletewithoutsuccessorindestination, 353 self.obsoletenotrebased,
327 obsoleteextinctsuccessors) = _computeobsoletenotrebased( 354 self.obsoletewithoutsuccessorindestination,
328 self.repo, obsoleteset, destmap) 355 obsoleteextinctsuccessors,
356 ) = _computeobsoletenotrebased(self.repo, obsoleteset, destmap)
329 skippedset = set(self.obsoletenotrebased) 357 skippedset = set(self.obsoletenotrebased)
330 skippedset.update(self.obsoletewithoutsuccessorindestination) 358 skippedset.update(self.obsoletewithoutsuccessorindestination)
331 skippedset.update(obsoleteextinctsuccessors) 359 skippedset.update(obsoleteextinctsuccessors)
332 _checkobsrebase(self.repo, self.ui, obsoleteset, skippedset) 360 _checkobsrebase(self.repo, self.ui, obsoleteset, skippedset)
333 361
337 self.collapsemsg = restorecollapsemsg(self.repo, isabort) 365 self.collapsemsg = restorecollapsemsg(self.repo, isabort)
338 except error.RepoLookupError: 366 except error.RepoLookupError:
339 if isabort: 367 if isabort:
340 clearstatus(self.repo) 368 clearstatus(self.repo)
341 clearcollapsemsg(self.repo) 369 clearcollapsemsg(self.repo)
342 self.repo.ui.warn(_('rebase aborted (no revision is removed,' 370 self.repo.ui.warn(
343 ' only broken state is cleared)\n')) 371 _(
372 'rebase aborted (no revision is removed,'
373 ' only broken state is cleared)\n'
374 )
375 )
344 return 0 376 return 0
345 else: 377 else:
346 msg = _('cannot continue inconsistent rebase') 378 msg = _('cannot continue inconsistent rebase')
347 hint = _('use "hg rebase --abort" to clear broken state') 379 hint = _('use "hg rebase --abort" to clear broken state')
348 raise error.Abort(msg, hint=hint) 380 raise error.Abort(msg, hint=hint)
355 if not destmap: 387 if not destmap:
356 return _nothingtorebase() 388 return _nothingtorebase()
357 389
358 rebaseset = destmap.keys() 390 rebaseset = destmap.keys()
359 allowunstable = obsolete.isenabled(self.repo, obsolete.allowunstableopt) 391 allowunstable = obsolete.isenabled(self.repo, obsolete.allowunstableopt)
360 if (not (self.keepf or allowunstable) 392 if not (self.keepf or allowunstable) and self.repo.revs(
361 and self.repo.revs('first(children(%ld) - %ld)', 393 'first(children(%ld) - %ld)', rebaseset, rebaseset
362 rebaseset, rebaseset)): 394 ):
363 raise error.Abort( 395 raise error.Abort(
364 _("can't remove original changesets with" 396 _(
365 " unrebased descendants"), 397 "can't remove original changesets with"
366 hint=_('use --keep to keep original changesets')) 398 " unrebased descendants"
399 ),
400 hint=_('use --keep to keep original changesets'),
401 )
367 402
368 result = buildstate(self.repo, destmap, self.collapsef) 403 result = buildstate(self.repo, destmap, self.collapsef)
369 404
370 if not result: 405 if not result:
371 # Empty state built, nothing to rebase 406 # Empty state built, nothing to rebase
372 self.ui.status(_('nothing to rebase\n')) 407 self.ui.status(_('nothing to rebase\n'))
373 return _nothingtorebase() 408 return _nothingtorebase()
374 409
375 for root in self.repo.set('roots(%ld)', rebaseset): 410 for root in self.repo.set('roots(%ld)', rebaseset):
376 if not self.keepf and not root.mutable(): 411 if not self.keepf and not root.mutable():
377 raise error.Abort(_("can't rebase public changeset %s") 412 raise error.Abort(
378 % root, 413 _("can't rebase public changeset %s") % root,
379 hint=_("see 'hg help phases' for details")) 414 hint=_("see 'hg help phases' for details"),
415 )
380 416
381 (self.originalwd, self.destmap, self.state) = result 417 (self.originalwd, self.destmap, self.state) = result
382 if self.collapsef: 418 if self.collapsef:
383 dests = set(self.destmap.values()) 419 dests = set(self.destmap.values())
384 if len(dests) != 1: 420 if len(dests) != 1:
385 raise error.Abort( 421 raise error.Abort(
386 _('--collapse does not work with multiple destinations')) 422 _('--collapse does not work with multiple destinations')
423 )
387 destrev = next(iter(dests)) 424 destrev = next(iter(dests))
388 destancestors = self.repo.changelog.ancestors([destrev], 425 destancestors = self.repo.changelog.ancestors(
389 inclusive=True) 426 [destrev], inclusive=True
427 )
390 self.external = externalparent(self.repo, self.state, destancestors) 428 self.external = externalparent(self.repo, self.state, destancestors)
391 429
392 for destrev in sorted(set(destmap.values())): 430 for destrev in sorted(set(destmap.values())):
393 dest = self.repo[destrev] 431 dest = self.repo[destrev]
394 if dest.closesbranch() and not self.keepbranchesf: 432 if dest.closesbranch() and not self.keepbranchesf:
397 self.prepared = True 435 self.prepared = True
398 436
399 def _assignworkingcopy(self): 437 def _assignworkingcopy(self):
400 if self.inmemory: 438 if self.inmemory:
401 from mercurial.context import overlayworkingctx 439 from mercurial.context import overlayworkingctx
440
402 self.wctx = overlayworkingctx(self.repo) 441 self.wctx = overlayworkingctx(self.repo)
403 self.repo.ui.debug("rebasing in-memory\n") 442 self.repo.ui.debug("rebasing in-memory\n")
404 else: 443 else:
405 self.wctx = self.repo[None] 444 self.wctx = self.repo[None]
406 self.repo.ui.debug("rebasing on disk\n") 445 self.repo.ui.debug("rebasing on disk\n")
407 self.repo.ui.log("rebase", 446 self.repo.ui.log(
408 "using in-memory rebase: %r\n", self.inmemory, 447 "rebase",
409 rebase_imm_used=self.inmemory) 448 "using in-memory rebase: %r\n",
449 self.inmemory,
450 rebase_imm_used=self.inmemory,
451 )
410 452
411 def _performrebase(self, tr): 453 def _performrebase(self, tr):
412 self._assignworkingcopy() 454 self._assignworkingcopy()
413 repo, ui = self.repo, self.ui 455 repo, ui = self.repo, self.ui
414 if self.keepbranchesf: 456 if self.keepbranchesf:
419 if self.collapsef: 461 if self.collapsef:
420 branches = set() 462 branches = set()
421 for rev in self.state: 463 for rev in self.state:
422 branches.add(repo[rev].branch()) 464 branches.add(repo[rev].branch())
423 if len(branches) > 1: 465 if len(branches) > 1:
424 raise error.Abort(_('cannot collapse multiple named ' 466 raise error.Abort(
425 'branches')) 467 _('cannot collapse multiple named ' 'branches')
468 )
426 469
427 # Calculate self.obsoletenotrebased 470 # Calculate self.obsoletenotrebased
428 obsrevs = _filterobsoleterevs(self.repo, self.state) 471 obsrevs = _filterobsoleterevs(self.repo, self.state)
429 self._handleskippingobsolete(obsrevs, self.destmap) 472 self._handleskippingobsolete(obsrevs, self.destmap)
430 473
440 # When using single transaction, store state when transaction 483 # When using single transaction, store state when transaction
441 # commits. 484 # commits.
442 self.storestatus(tr) 485 self.storestatus(tr)
443 486
444 cands = [k for k, v in self.state.iteritems() if v == revtodo] 487 cands = [k for k, v in self.state.iteritems() if v == revtodo]
445 p = repo.ui.makeprogress(_("rebasing"), unit=_('changesets'), 488 p = repo.ui.makeprogress(
446 total=len(cands)) 489 _("rebasing"), unit=_('changesets'), total=len(cands)
490 )
491
447 def progress(ctx): 492 def progress(ctx):
448 p.increment(item=("%d:%s" % (ctx.rev(), ctx))) 493 p.increment(item=("%d:%s" % (ctx.rev(), ctx)))
494
449 allowdivergence = self.ui.configbool( 495 allowdivergence = self.ui.configbool(
450 'experimental', 'evolution.allowdivergence') 496 'experimental', 'evolution.allowdivergence'
497 )
451 for subset in sortsource(self.destmap): 498 for subset in sortsource(self.destmap):
452 sortedrevs = self.repo.revs('sort(%ld, -topo)', subset) 499 sortedrevs = self.repo.revs('sort(%ld, -topo)', subset)
453 if not allowdivergence: 500 if not allowdivergence:
454 sortedrevs -= self.repo.revs( 501 sortedrevs -= self.repo.revs(
455 'descendants(%ld) and not %ld', 502 'descendants(%ld) and not %ld',
481 overrides = {('phases', 'new-commit'): destphase} 528 overrides = {('phases', 'new-commit'): destphase}
482 if keepbranch: 529 if keepbranch:
483 overrides[('ui', 'allowemptycommit')] = True 530 overrides[('ui', 'allowemptycommit')] = True
484 with repo.ui.configoverride(overrides, 'rebase'): 531 with repo.ui.configoverride(overrides, 'rebase'):
485 if self.inmemory: 532 if self.inmemory:
486 newnode = commitmemorynode(repo, p1, p2, 533 newnode = commitmemorynode(
534 repo,
535 p1,
536 p2,
487 wctx=self.wctx, 537 wctx=self.wctx,
488 extra=extra, 538 extra=extra,
489 commitmsg=commitmsg, 539 commitmsg=commitmsg,
490 editor=editor, 540 editor=editor,
491 user=ctx.user(), 541 user=ctx.user(),
492 date=date) 542 date=date,
543 )
493 mergemod.mergestate.clean(repo) 544 mergemod.mergestate.clean(repo)
494 else: 545 else:
495 newnode = commitnode(repo, p1, p2, 546 newnode = commitnode(
547 repo,
548 p1,
549 p2,
496 extra=extra, 550 extra=extra,
497 commitmsg=commitmsg, 551 commitmsg=commitmsg,
498 editor=editor, 552 editor=editor,
499 user=ctx.user(), 553 user=ctx.user(),
500 date=date) 554 date=date,
555 )
501 556
502 if newnode is None: 557 if newnode is None:
503 # If it ended up being a no-op commit, then the normal 558 # If it ended up being a no-op commit, then the normal
504 # merge state clean-up path doesn't happen, so do it 559 # merge state clean-up path doesn't happen, so do it
505 # here. Fix issue5494 560 # here. Fix issue5494
511 dest = self.destmap[rev] 566 dest = self.destmap[rev]
512 ctx = repo[rev] 567 ctx = repo[rev]
513 desc = _ctxdesc(ctx) 568 desc = _ctxdesc(ctx)
514 if self.state[rev] == rev: 569 if self.state[rev] == rev:
515 ui.status(_('already rebased %s\n') % desc) 570 ui.status(_('already rebased %s\n') % desc)
516 elif (not allowdivergence 571 elif (
517 and rev in self.obsoletewithoutsuccessorindestination): 572 not allowdivergence
518 msg = _('note: not rebasing %s and its descendants as ' 573 and rev in self.obsoletewithoutsuccessorindestination
519 'this would cause divergence\n') % desc 574 ):
575 msg = (
576 _(
577 'note: not rebasing %s and its descendants as '
578 'this would cause divergence\n'
579 )
580 % desc
581 )
520 repo.ui.status(msg) 582 repo.ui.status(msg)
521 self.skipped.add(rev) 583 self.skipped.add(rev)
522 elif rev in self.obsoletenotrebased: 584 elif rev in self.obsoletenotrebased:
523 succ = self.obsoletenotrebased[rev] 585 succ = self.obsoletenotrebased[rev]
524 if succ is None: 586 if succ is None:
525 msg = _('note: not rebasing %s, it has no ' 587 msg = (
526 'successor\n') % desc 588 _('note: not rebasing %s, it has no ' 'successor\n') % desc
589 )
527 else: 590 else:
528 succdesc = _ctxdesc(repo[succ]) 591 succdesc = _ctxdesc(repo[succ])
529 msg = (_('note: not rebasing %s, already in ' 592 msg = _(
530 'destination as %s\n') % (desc, succdesc)) 593 'note: not rebasing %s, already in ' 'destination as %s\n'
594 ) % (desc, succdesc)
531 repo.ui.status(msg) 595 repo.ui.status(msg)
532 # Make clearrebased aware state[rev] is not a true successor 596 # Make clearrebased aware state[rev] is not a true successor
533 self.skipped.add(rev) 597 self.skipped.add(rev)
534 # Record rev as moved to its desired destination in self.state. 598 # Record rev as moved to its desired destination in self.state.
535 # This helps bookmark and working parent movement. 599 # This helps bookmark and working parent movement.
536 dest = max(adjustdest(repo, rev, self.destmap, self.state, 600 dest = max(
537 self.skipped)) 601 adjustdest(repo, rev, self.destmap, self.state, self.skipped)
602 )
538 self.state[rev] = dest 603 self.state[rev] = dest
539 elif self.state[rev] == revtodo: 604 elif self.state[rev] == revtodo:
540 ui.status(_('rebasing %s\n') % desc) 605 ui.status(_('rebasing %s\n') % desc)
541 progressfn(ctx) 606 progressfn(ctx)
542 p1, p2, base = defineparents(repo, rev, self.destmap, 607 p1, p2, base = defineparents(
543 self.state, self.skipped, 608 repo,
544 self.obsoletenotrebased) 609 rev,
610 self.destmap,
611 self.state,
612 self.skipped,
613 self.obsoletenotrebased,
614 )
545 if not self.inmemory and len(repo[None].parents()) == 2: 615 if not self.inmemory and len(repo[None].parents()) == 2:
546 repo.ui.debug('resuming interrupted rebase\n') 616 repo.ui.debug('resuming interrupted rebase\n')
547 else: 617 else:
548 overrides = {('ui', 'forcemerge'): opts.get('tool', '')} 618 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
549 with ui.configoverride(overrides, 'rebase'): 619 with ui.configoverride(overrides, 'rebase'):
550 stats = rebasenode(repo, rev, p1, base, self.collapsef, 620 stats = rebasenode(
551 dest, wctx=self.wctx) 621 repo,
622 rev,
623 p1,
624 base,
625 self.collapsef,
626 dest,
627 wctx=self.wctx,
628 )
552 if stats.unresolvedcount > 0: 629 if stats.unresolvedcount > 0:
553 if self.inmemory: 630 if self.inmemory:
554 raise error.InMemoryMergeConflictsError() 631 raise error.InMemoryMergeConflictsError()
555 else: 632 else:
556 raise error.InterventionRequired( 633 raise error.InterventionRequired(
557 _('unresolved conflicts (see hg ' 634 _(
558 'resolve, then hg rebase --continue)')) 635 'unresolved conflicts (see hg '
636 'resolve, then hg rebase --continue)'
637 )
638 )
559 if not self.collapsef: 639 if not self.collapsef:
560 merging = p2 != nullrev 640 merging = p2 != nullrev
561 editform = cmdutil.mergeeditform(merging, 'rebase') 641 editform = cmdutil.mergeeditform(merging, 'rebase')
562 editor = cmdutil.getcommiteditor(editform=editform, 642 editor = cmdutil.getcommiteditor(
563 **pycompat.strkwargs(opts)) 643 editform=editform, **pycompat.strkwargs(opts)
644 )
564 newnode = self._concludenode(rev, p1, p2, editor) 645 newnode = self._concludenode(rev, p1, p2, editor)
565 else: 646 else:
566 # Skip commit if we are collapsing 647 # Skip commit if we are collapsing
567 if self.inmemory: 648 if self.inmemory:
568 self.wctx.setbase(repo[p1]) 649 self.wctx.setbase(repo[p1])
573 if newnode is not None: 654 if newnode is not None:
574 self.state[rev] = repo[newnode].rev() 655 self.state[rev] = repo[newnode].rev()
575 ui.debug('rebased as %s\n' % short(newnode)) 656 ui.debug('rebased as %s\n' % short(newnode))
576 else: 657 else:
577 if not self.collapsef: 658 if not self.collapsef:
578 ui.warn(_('note: not rebasing %s, its destination already ' 659 ui.warn(
579 'has all its changes\n') % desc) 660 _(
661 'note: not rebasing %s, its destination already '
662 'has all its changes\n'
663 )
664 % desc
665 )
580 self.skipped.add(rev) 666 self.skipped.add(rev)
581 self.state[rev] = p1 667 self.state[rev] = p1
582 ui.debug('next revision set to %d\n' % p1) 668 ui.debug('next revision set to %d\n' % p1)
583 else: 669 else:
584 ui.status(_('already rebased %s as %s\n') % 670 ui.status(
585 (desc, repo[self.state[rev]])) 671 _('already rebased %s as %s\n') % (desc, repo[self.state[rev]])
672 )
586 if not tr: 673 if not tr:
587 # When not using single transaction, store state after each 674 # When not using single transaction, store state after each
588 # commit is completely done. On InterventionRequired, we thus 675 # commit is completely done. On InterventionRequired, we thus
589 # won't store the status. Instead, we'll hit the "len(parents) == 2" 676 # won't store the status. Instead, we'll hit the "len(parents) == 2"
590 # case and realize that the commit was in progress. 677 # case and realize that the commit was in progress.
593 def _finishrebase(self): 680 def _finishrebase(self):
594 repo, ui, opts = self.repo, self.ui, self.opts 681 repo, ui, opts = self.repo, self.ui, self.opts
595 fm = ui.formatter('rebase', opts) 682 fm = ui.formatter('rebase', opts)
596 fm.startitem() 683 fm.startitem()
597 if self.collapsef: 684 if self.collapsef:
598 p1, p2, _base = defineparents(repo, min(self.state), self.destmap, 685 p1, p2, _base = defineparents(
599 self.state, self.skipped, 686 repo,
600 self.obsoletenotrebased) 687 min(self.state),
688 self.destmap,
689 self.state,
690 self.skipped,
691 self.obsoletenotrebased,
692 )
601 editopt = opts.get('edit') 693 editopt = opts.get('edit')
602 editform = 'rebase.collapse' 694 editform = 'rebase.collapse'
603 if self.collapsemsg: 695 if self.collapsemsg:
604 commitmsg = self.collapsemsg 696 commitmsg = self.collapsemsg
605 else: 697 else:
609 commitmsg += '\n* %s' % repo[rebased].description() 701 commitmsg += '\n* %s' % repo[rebased].description()
610 editopt = True 702 editopt = True
611 editor = cmdutil.getcommiteditor(edit=editopt, editform=editform) 703 editor = cmdutil.getcommiteditor(edit=editopt, editform=editform)
612 revtoreuse = max(self.state) 704 revtoreuse = max(self.state)
613 705
614 newnode = self._concludenode(revtoreuse, p1, self.external, 706 newnode = self._concludenode(
615 editor, commitmsg=commitmsg) 707 revtoreuse, p1, self.external, editor, commitmsg=commitmsg
708 )
616 709
617 if newnode is not None: 710 if newnode is not None:
618 newrev = repo[newnode].rev() 711 newrev = repo[newnode].rev()
619 for oldrev in self.state: 712 for oldrev in self.state:
620 self.state[oldrev] = newrev 713 self.state[oldrev] = newrev
621 714
622 if 'qtip' in repo.tags(): 715 if 'qtip' in repo.tags():
623 updatemq(repo, self.state, self.skipped, 716 updatemq(repo, self.state, self.skipped, **pycompat.strkwargs(opts))
624 **pycompat.strkwargs(opts))
625 717
626 # restore original working directory 718 # restore original working directory
627 # (we do this before stripping) 719 # (we do this before stripping)
628 newwd = self.state.get(self.originalwd, self.originalwd) 720 newwd = self.state.get(self.originalwd, self.originalwd)
629 if newwd < 0: 721 if newwd < 0:
634 hg.updaterepo(repo, newwd, overwrite=False) 726 hg.updaterepo(repo, newwd, overwrite=False)
635 727
636 collapsedas = None 728 collapsedas = None
637 if self.collapsef and not self.keepf: 729 if self.collapsef and not self.keepf:
638 collapsedas = newnode 730 collapsedas = newnode
639 clearrebased(ui, repo, self.destmap, self.state, self.skipped, 731 clearrebased(
640 collapsedas, self.keepf, fm=fm, backup=self.backupf) 732 ui,
733 repo,
734 self.destmap,
735 self.state,
736 self.skipped,
737 collapsedas,
738 self.keepf,
739 fm=fm,
740 backup=self.backupf,
741 )
641 742
642 clearstatus(repo) 743 clearstatus(repo)
643 clearcollapsemsg(repo) 744 clearcollapsemsg(repo)
644 745
645 ui.note(_("rebase completed\n")) 746 ui.note(_("rebase completed\n"))
647 if self.skipped: 748 if self.skipped:
648 skippedlen = len(self.skipped) 749 skippedlen = len(self.skipped)
649 ui.note(_("%d revisions have been skipped\n") % skippedlen) 750 ui.note(_("%d revisions have been skipped\n") % skippedlen)
650 fm.end() 751 fm.end()
651 752
652 if (self.activebookmark and self.activebookmark in repo._bookmarks and 753 if (
653 repo['.'].node() == repo._bookmarks[self.activebookmark]): 754 self.activebookmark
654 bookmarks.activate(repo, self.activebookmark) 755 and self.activebookmark in repo._bookmarks
756 and repo['.'].node() == repo._bookmarks[self.activebookmark]
757 ):
758 bookmarks.activate(repo, self.activebookmark)
655 759
656 def _abort(self, backup=True, suppwarns=False): 760 def _abort(self, backup=True, suppwarns=False):
657 '''Restore the repository to its original state.''' 761 '''Restore the repository to its original state.'''
658 762
659 repo = self.repo 763 repo = self.repo
660 try: 764 try:
661 # If the first commits in the rebased set get skipped during the 765 # If the first commits in the rebased set get skipped during the
662 # rebase, their values within the state mapping will be the dest 766 # rebase, their values within the state mapping will be the dest
663 # rev id. The rebased list must must not contain the dest rev 767 # rev id. The rebased list must must not contain the dest rev
664 # (issue4896) 768 # (issue4896)
665 rebased = [s for r, s in self.state.items() 769 rebased = [
666 if s >= 0 and s != r and s != self.destmap[r]] 770 s
771 for r, s in self.state.items()
772 if s >= 0 and s != r and s != self.destmap[r]
773 ]
667 immutable = [d for d in rebased if not repo[d].mutable()] 774 immutable = [d for d in rebased if not repo[d].mutable()]
668 cleanup = True 775 cleanup = True
669 if immutable: 776 if immutable:
670 repo.ui.warn(_("warning: can't clean up public changesets %s\n") 777 repo.ui.warn(
671 % ', '.join(bytes(repo[r]) for r in immutable), 778 _("warning: can't clean up public changesets %s\n")
672 hint=_("see 'hg help phases' for details")) 779 % ', '.join(bytes(repo[r]) for r in immutable),
780 hint=_("see 'hg help phases' for details"),
781 )
673 cleanup = False 782 cleanup = False
674 783
675 descendants = set() 784 descendants = set()
676 if rebased: 785 if rebased:
677 descendants = set(repo.changelog.descendants(rebased)) 786 descendants = set(repo.changelog.descendants(rebased))
678 if descendants - set(rebased): 787 if descendants - set(rebased):
679 repo.ui.warn(_("warning: new changesets detected on " 788 repo.ui.warn(
680 "destination branch, can't strip\n")) 789 _(
790 "warning: new changesets detected on "
791 "destination branch, can't strip\n"
792 )
793 )
681 cleanup = False 794 cleanup = False
682 795
683 if cleanup: 796 if cleanup:
684 shouldupdate = False 797 shouldupdate = False
685 if rebased: 798 if rebased:
686 strippoints = [ 799 strippoints = [
687 c.node() for c in repo.set('roots(%ld)', rebased)] 800 c.node() for c in repo.set('roots(%ld)', rebased)
801 ]
688 802
689 updateifonnodes = set(rebased) 803 updateifonnodes = set(rebased)
690 updateifonnodes.update(self.destmap.values()) 804 updateifonnodes.update(self.destmap.values())
691 updateifonnodes.add(self.originalwd) 805 updateifonnodes.add(self.originalwd)
692 shouldupdate = repo['.'].rev() in updateifonnodes 806 shouldupdate = repo['.'].rev() in updateifonnodes
693 807
694 # Update away from the rebase if necessary 808 # Update away from the rebase if necessary
695 if shouldupdate or needupdate(repo, self.state): 809 if shouldupdate or needupdate(repo, self.state):
696 mergemod.update(repo, self.originalwd, branchmerge=False, 810 mergemod.update(
697 force=True) 811 repo, self.originalwd, branchmerge=False, force=True
812 )
698 813
699 # Strip from the first rebased revision 814 # Strip from the first rebased revision
700 if rebased: 815 if rebased:
701 repair.strip(repo.ui, repo, strippoints, backup=backup) 816 repair.strip(repo.ui, repo, strippoints, backup=backup)
702 817
708 clearcollapsemsg(repo) 823 clearcollapsemsg(repo)
709 if not suppwarns: 824 if not suppwarns:
710 repo.ui.warn(_('rebase aborted\n')) 825 repo.ui.warn(_('rebase aborted\n'))
711 return 0 826 return 0
712 827
713 @command('rebase', 828
714 [('s', 'source', '', 829 @command(
715 _('rebase the specified changeset and descendants'), _('REV')), 830 'rebase',
716 ('b', 'base', '', 831 [
717 _('rebase everything from branching point of specified changeset'), 832 (
718 _('REV')), 833 's',
719 ('r', 'rev', [], 834 'source',
720 _('rebase these revisions'), 835 '',
721 _('REV')), 836 _('rebase the specified changeset and descendants'),
722 ('d', 'dest', '', 837 _('REV'),
723 _('rebase onto the specified changeset'), _('REV')), 838 ),
724 ('', 'collapse', False, _('collapse the rebased changesets')), 839 (
725 ('m', 'message', '', 840 'b',
726 _('use text as collapse commit message'), _('TEXT')), 841 'base',
727 ('e', 'edit', False, _('invoke editor on commit messages')), 842 '',
728 ('l', 'logfile', '', 843 _('rebase everything from branching point of specified changeset'),
729 _('read collapse commit message from file'), _('FILE')), 844 _('REV'),
730 ('k', 'keep', False, _('keep original changesets')), 845 ),
731 ('', 'keepbranches', False, _('keep original branch names')), 846 ('r', 'rev', [], _('rebase these revisions'), _('REV')),
732 ('D', 'detach', False, _('(DEPRECATED)')), 847 ('d', 'dest', '', _('rebase onto the specified changeset'), _('REV')),
733 ('i', 'interactive', False, _('(DEPRECATED)')), 848 ('', 'collapse', False, _('collapse the rebased changesets')),
734 ('t', 'tool', '', _('specify merge tool')), 849 (
735 ('', 'stop', False, _('stop interrupted rebase')), 850 'm',
736 ('c', 'continue', False, _('continue an interrupted rebase')), 851 'message',
737 ('a', 'abort', False, _('abort an interrupted rebase')), 852 '',
738 ('', 'auto-orphans', '', _('automatically rebase orphan revisions ' 853 _('use text as collapse commit message'),
739 'in the specified revset (EXPERIMENTAL)')), 854 _('TEXT'),
740 ] + cmdutil.dryrunopts + cmdutil.formatteropts + cmdutil.confirmopts, 855 ),
856 ('e', 'edit', False, _('invoke editor on commit messages')),
857 (
858 'l',
859 'logfile',
860 '',
861 _('read collapse commit message from file'),
862 _('FILE'),
863 ),
864 ('k', 'keep', False, _('keep original changesets')),
865 ('', 'keepbranches', False, _('keep original branch names')),
866 ('D', 'detach', False, _('(DEPRECATED)')),
867 ('i', 'interactive', False, _('(DEPRECATED)')),
868 ('t', 'tool', '', _('specify merge tool')),
869 ('', 'stop', False, _('stop interrupted rebase')),
870 ('c', 'continue', False, _('continue an interrupted rebase')),
871 ('a', 'abort', False, _('abort an interrupted rebase')),
872 (
873 '',
874 'auto-orphans',
875 '',
876 _(
877 'automatically rebase orphan revisions '
878 'in the specified revset (EXPERIMENTAL)'
879 ),
880 ),
881 ]
882 + cmdutil.dryrunopts
883 + cmdutil.formatteropts
884 + cmdutil.confirmopts,
741 _('[-s REV | -b REV] [-d REV] [OPTION]'), 885 _('[-s REV | -b REV] [-d REV] [OPTION]'),
742 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT) 886 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
887 )
743 def rebase(ui, repo, **opts): 888 def rebase(ui, repo, **opts):
744 """move changeset (and descendants) to a different branch 889 """move changeset (and descendants) to a different branch
745 890
746 Rebase uses repeated merging to graft changesets from one part of 891 Rebase uses repeated merging to graft changesets from one part of
747 history (the source) onto another (the destination). This can be 892 history (the source) onto another (the destination). This can be
867 inmemory = ui.configbool('rebase', 'experimental.inmemory') 1012 inmemory = ui.configbool('rebase', 'experimental.inmemory')
868 dryrun = opts.get('dry_run') 1013 dryrun = opts.get('dry_run')
869 confirm = opts.get('confirm') 1014 confirm = opts.get('confirm')
870 selactions = [k for k in ['abort', 'stop', 'continue'] if opts.get(k)] 1015 selactions = [k for k in ['abort', 'stop', 'continue'] if opts.get(k)]
871 if len(selactions) > 1: 1016 if len(selactions) > 1:
872 raise error.Abort(_('cannot use --%s with --%s') 1017 raise error.Abort(
873 % tuple(selactions[:2])) 1018 _('cannot use --%s with --%s') % tuple(selactions[:2])
1019 )
874 action = selactions[0] if selactions else None 1020 action = selactions[0] if selactions else None
875 if dryrun and action: 1021 if dryrun and action:
876 raise error.Abort(_('cannot specify both --dry-run and --%s') % action) 1022 raise error.Abort(_('cannot specify both --dry-run and --%s') % action)
877 if confirm and action: 1023 if confirm and action:
878 raise error.Abort(_('cannot specify both --confirm and --%s') % action) 1024 raise error.Abort(_('cannot specify both --confirm and --%s') % action)
886 inmemory = False 1032 inmemory = False
887 1033
888 if opts.get('auto_orphans'): 1034 if opts.get('auto_orphans'):
889 for key in opts: 1035 for key in opts:
890 if key != 'auto_orphans' and opts.get(key): 1036 if key != 'auto_orphans' and opts.get(key):
891 raise error.Abort(_('--auto-orphans is incompatible with %s') % 1037 raise error.Abort(
892 ('--' + key)) 1038 _('--auto-orphans is incompatible with %s') % ('--' + key)
1039 )
893 userrevs = list(repo.revs(opts.get('auto_orphans'))) 1040 userrevs = list(repo.revs(opts.get('auto_orphans')))
894 opts['rev'] = [revsetlang.formatspec('%ld and orphan()', userrevs)] 1041 opts['rev'] = [revsetlang.formatspec('%ld and orphan()', userrevs)]
895 opts['dest'] = '_destautoorphanrebase(SRC)' 1042 opts['dest'] = '_destautoorphanrebase(SRC)'
896 1043
897 if dryrun or confirm: 1044 if dryrun or confirm:
902 rbsrt.restorestatus() 1049 rbsrt.restorestatus()
903 if rbsrt.collapsef: 1050 if rbsrt.collapsef:
904 raise error.Abort(_("cannot stop in --collapse session")) 1051 raise error.Abort(_("cannot stop in --collapse session"))
905 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt) 1052 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
906 if not (rbsrt.keepf or allowunstable): 1053 if not (rbsrt.keepf or allowunstable):
907 raise error.Abort(_("cannot remove original changesets with" 1054 raise error.Abort(
908 " unrebased descendants"), 1055 _(
909 hint=_('either enable obsmarkers to allow unstable ' 1056 "cannot remove original changesets with"
910 'revisions or use --keep to keep original ' 1057 " unrebased descendants"
911 'changesets')) 1058 ),
1059 hint=_(
1060 'either enable obsmarkers to allow unstable '
1061 'revisions or use --keep to keep original '
1062 'changesets'
1063 ),
1064 )
912 if needupdate(repo, rbsrt.state): 1065 if needupdate(repo, rbsrt.state):
913 # update to the current working revision 1066 # update to the current working revision
914 # to clear interrupted merge 1067 # to clear interrupted merge
915 hg.updaterepo(repo, rbsrt.originalwd, overwrite=True) 1068 hg.updaterepo(repo, rbsrt.originalwd, overwrite=True)
916 rbsrt._finishrebase() 1069 rbsrt._finishrebase()
921 # and re-run as an on-disk merge. 1074 # and re-run as an on-disk merge.
922 overrides = {('rebase', 'singletransaction'): True} 1075 overrides = {('rebase', 'singletransaction'): True}
923 with ui.configoverride(overrides, 'rebase'): 1076 with ui.configoverride(overrides, 'rebase'):
924 return _dorebase(ui, repo, action, opts, inmemory=inmemory) 1077 return _dorebase(ui, repo, action, opts, inmemory=inmemory)
925 except error.InMemoryMergeConflictsError: 1078 except error.InMemoryMergeConflictsError:
926 ui.warn(_('hit merge conflicts; re-running rebase without in-memory' 1079 ui.warn(
927 ' merge\n')) 1080 _(
1081 'hit merge conflicts; re-running rebase without in-memory'
1082 ' merge\n'
1083 )
1084 )
928 # TODO: Make in-memory merge not use the on-disk merge state, so 1085 # TODO: Make in-memory merge not use the on-disk merge state, so
929 # we don't have to clean it here 1086 # we don't have to clean it here
930 mergemod.mergestate.clean(repo) 1087 mergemod.mergestate.clean(repo)
931 clearstatus(repo) 1088 clearstatus(repo)
932 clearcollapsemsg(repo) 1089 clearcollapsemsg(repo)
933 return _dorebase(ui, repo, action, opts, inmemory=False) 1090 return _dorebase(ui, repo, action, opts, inmemory=False)
934 else: 1091 else:
935 return _dorebase(ui, repo, action, opts) 1092 return _dorebase(ui, repo, action, opts)
936 1093
1094
937 def _dryrunrebase(ui, repo, action, opts): 1095 def _dryrunrebase(ui, repo, action, opts):
938 rbsrt = rebaseruntime(repo, ui, inmemory=True, opts=opts) 1096 rbsrt = rebaseruntime(repo, ui, inmemory=True, opts=opts)
939 confirm = opts.get('confirm') 1097 confirm = opts.get('confirm')
940 if confirm: 1098 if confirm:
941 ui.status(_('starting in-memory rebase\n')) 1099 ui.status(_('starting in-memory rebase\n'))
942 else: 1100 else:
943 ui.status(_('starting dry-run rebase; repository will not be ' 1101 ui.status(
944 'changed\n')) 1102 _('starting dry-run rebase; repository will not be ' 'changed\n')
1103 )
945 with repo.wlock(), repo.lock(): 1104 with repo.wlock(), repo.lock():
946 needsabort = True 1105 needsabort = True
947 try: 1106 try:
948 overrides = {('rebase', 'singletransaction'): True} 1107 overrides = {('rebase', 'singletransaction'): True}
949 with ui.configoverride(overrides, 'rebase'): 1108 with ui.configoverride(overrides, 'rebase'):
950 _origrebase(ui, repo, action, opts, rbsrt, inmemory=True, 1109 _origrebase(
951 leaveunfinished=True) 1110 ui,
1111 repo,
1112 action,
1113 opts,
1114 rbsrt,
1115 inmemory=True,
1116 leaveunfinished=True,
1117 )
952 except error.InMemoryMergeConflictsError: 1118 except error.InMemoryMergeConflictsError:
953 ui.status(_('hit a merge conflict\n')) 1119 ui.status(_('hit a merge conflict\n'))
954 return 1 1120 return 1
955 except error.Abort: 1121 except error.Abort:
956 needsabort = False 1122 needsabort = False
957 raise 1123 raise
958 else: 1124 else:
959 if confirm: 1125 if confirm:
960 ui.status(_('rebase completed successfully\n')) 1126 ui.status(_('rebase completed successfully\n'))
961 if not ui.promptchoice(_(b'apply changes (yn)?' 1127 if not ui.promptchoice(
962 b'$$ &Yes $$ &No')): 1128 _(b'apply changes (yn)?' b'$$ &Yes $$ &No')
1129 ):
963 # finish unfinished rebase 1130 # finish unfinished rebase
964 rbsrt._finishrebase() 1131 rbsrt._finishrebase()
965 else: 1132 else:
966 rbsrt._prepareabortorcontinue(isabort=True, backup=False, 1133 rbsrt._prepareabortorcontinue(
967 suppwarns=True) 1134 isabort=True, backup=False, suppwarns=True
1135 )
968 needsabort = False 1136 needsabort = False
969 else: 1137 else:
970 ui.status(_('dry-run rebase completed successfully; run without' 1138 ui.status(
971 ' -n/--dry-run to perform this rebase\n')) 1139 _(
1140 'dry-run rebase completed successfully; run without'
1141 ' -n/--dry-run to perform this rebase\n'
1142 )
1143 )
972 return 0 1144 return 0
973 finally: 1145 finally:
974 if needsabort: 1146 if needsabort:
975 # no need to store backup in case of dryrun 1147 # no need to store backup in case of dryrun
976 rbsrt._prepareabortorcontinue(isabort=True, backup=False, 1148 rbsrt._prepareabortorcontinue(
977 suppwarns=True) 1149 isabort=True, backup=False, suppwarns=True
1150 )
1151
978 1152
979 def _dorebase(ui, repo, action, opts, inmemory=False): 1153 def _dorebase(ui, repo, action, opts, inmemory=False):
980 rbsrt = rebaseruntime(repo, ui, inmemory, opts) 1154 rbsrt = rebaseruntime(repo, ui, inmemory, opts)
981 return _origrebase(ui, repo, action, opts, rbsrt, inmemory=inmemory) 1155 return _origrebase(ui, repo, action, opts, rbsrt, inmemory=inmemory)
982 1156
983 def _origrebase(ui, repo, action, opts, rbsrt, inmemory=False, 1157
984 leaveunfinished=False): 1158 def _origrebase(
1159 ui, repo, action, opts, rbsrt, inmemory=False, leaveunfinished=False
1160 ):
985 assert action != 'stop' 1161 assert action != 'stop'
986 with repo.wlock(), repo.lock(): 1162 with repo.wlock(), repo.lock():
987 # Validate input and define rebasing points 1163 # Validate input and define rebasing points
988 destf = opts.get('dest', None) 1164 destf = opts.get('dest', None)
989 srcf = opts.get('source', None) 1165 srcf = opts.get('source', None)
997 if extensions.find('histedit'): 1173 if extensions.find('histedit'):
998 enablehistedit = '' 1174 enablehistedit = ''
999 except KeyError: 1175 except KeyError:
1000 enablehistedit = " --config extensions.histedit=" 1176 enablehistedit = " --config extensions.histedit="
1001 help = "hg%s help -e histedit" % enablehistedit 1177 help = "hg%s help -e histedit" % enablehistedit
1002 msg = _("interactive history editing is supported by the " 1178 msg = (
1003 "'histedit' extension (see \"%s\")") % help 1179 _(
1180 "interactive history editing is supported by the "
1181 "'histedit' extension (see \"%s\")"
1182 )
1183 % help
1184 )
1004 raise error.Abort(msg) 1185 raise error.Abort(msg)
1005 1186
1006 if rbsrt.collapsemsg and not rbsrt.collapsef: 1187 if rbsrt.collapsemsg and not rbsrt.collapsef:
1007 raise error.Abort( 1188 raise error.Abort(_('message can only be specified with collapse'))
1008 _('message can only be specified with collapse'))
1009 1189
1010 if action: 1190 if action:
1011 if rbsrt.collapsef: 1191 if rbsrt.collapsef:
1012 raise error.Abort( 1192 raise error.Abort(
1013 _('cannot use collapse with continue or abort')) 1193 _('cannot use collapse with continue or abort')
1194 )
1014 if srcf or basef or destf: 1195 if srcf or basef or destf:
1015 raise error.Abort( 1196 raise error.Abort(
1016 _('abort and continue do not allow specifying revisions')) 1197 _('abort and continue do not allow specifying revisions')
1198 )
1017 if action == 'abort' and opts.get('tool', False): 1199 if action == 'abort' and opts.get('tool', False):
1018 ui.warn(_('tool option will be ignored\n')) 1200 ui.warn(_('tool option will be ignored\n'))
1019 if action == 'continue': 1201 if action == 'continue':
1020 ms = mergemod.mergestate.read(repo) 1202 ms = mergemod.mergestate.read(repo)
1021 mergeutil.checkunresolved(ms) 1203 mergeutil.checkunresolved(ms)
1022 1204
1023 retcode = rbsrt._prepareabortorcontinue(isabort=(action == 'abort')) 1205 retcode = rbsrt._prepareabortorcontinue(isabort=(action == 'abort'))
1024 if retcode is not None: 1206 if retcode is not None:
1025 return retcode 1207 return retcode
1026 else: 1208 else:
1027 destmap = _definedestmap(ui, repo, inmemory, destf, srcf, basef, 1209 destmap = _definedestmap(
1028 revf, destspace=destspace) 1210 ui,
1211 repo,
1212 inmemory,
1213 destf,
1214 srcf,
1215 basef,
1216 revf,
1217 destspace=destspace,
1218 )
1029 retcode = rbsrt._preparenewrebase(destmap) 1219 retcode = rbsrt._preparenewrebase(destmap)
1030 if retcode is not None: 1220 if retcode is not None:
1031 return retcode 1221 return retcode
1032 storecollapsemsg(repo, rbsrt.collapsemsg) 1222 storecollapsemsg(repo, rbsrt.collapsemsg)
1033 1223
1049 with util.acceptintervention(dsguard): 1239 with util.acceptintervention(dsguard):
1050 rbsrt._performrebase(tr) 1240 rbsrt._performrebase(tr)
1051 if not leaveunfinished: 1241 if not leaveunfinished:
1052 rbsrt._finishrebase() 1242 rbsrt._finishrebase()
1053 1243
1054 def _definedestmap(ui, repo, inmemory, destf=None, srcf=None, basef=None, 1244
1055 revf=None, destspace=None): 1245 def _definedestmap(
1246 ui,
1247 repo,
1248 inmemory,
1249 destf=None,
1250 srcf=None,
1251 basef=None,
1252 revf=None,
1253 destspace=None,
1254 ):
1056 """use revisions argument to define destmap {srcrev: destrev}""" 1255 """use revisions argument to define destmap {srcrev: destrev}"""
1057 if revf is None: 1256 if revf is None:
1058 revf = [] 1257 revf = []
1059 1258
1060 # destspace is here to work around issues with `hg pull --rebase` see 1259 # destspace is here to work around issues with `hg pull --rebase` see
1069 if not inmemory: 1268 if not inmemory:
1070 cmdutil.checkunfinished(repo) 1269 cmdutil.checkunfinished(repo)
1071 cmdutil.bailifchanged(repo) 1270 cmdutil.bailifchanged(repo)
1072 1271
1073 if ui.configbool('commands', 'rebase.requiredest') and not destf: 1272 if ui.configbool('commands', 'rebase.requiredest') and not destf:
1074 raise error.Abort(_('you must specify a destination'), 1273 raise error.Abort(
1075 hint=_('use: hg rebase -d REV')) 1274 _('you must specify a destination'), hint=_('use: hg rebase -d REV')
1275 )
1076 1276
1077 dest = None 1277 dest = None
1078 1278
1079 if revf: 1279 if revf:
1080 rebaseset = scmutil.revrange(repo, revf) 1280 rebaseset = scmutil.revrange(repo, revf)
1089 rebaseset = repo.revs('(%ld)::', src) 1289 rebaseset = repo.revs('(%ld)::', src)
1090 assert rebaseset 1290 assert rebaseset
1091 else: 1291 else:
1092 base = scmutil.revrange(repo, [basef or '.']) 1292 base = scmutil.revrange(repo, [basef or '.'])
1093 if not base: 1293 if not base:
1094 ui.status(_('empty "base" revision set - ' 1294 ui.status(
1095 "can't compute rebase set\n")) 1295 _('empty "base" revision set - ' "can't compute rebase set\n")
1296 )
1096 return None 1297 return None
1097 if destf: 1298 if destf:
1098 # --base does not support multiple destinations 1299 # --base does not support multiple destinations
1099 dest = scmutil.revsingle(repo, destf) 1300 dest = scmutil.revsingle(repo, destf)
1100 else: 1301 else:
1101 dest = repo[_destrebase(repo, base, destspace=destspace)] 1302 dest = repo[_destrebase(repo, base, destspace=destspace)]
1102 destf = bytes(dest) 1303 destf = bytes(dest)
1103 1304
1104 roots = [] # selected children of branching points 1305 roots = [] # selected children of branching points
1105 bpbase = {} # {branchingpoint: [origbase]} 1306 bpbase = {} # {branchingpoint: [origbase]}
1106 for b in base: # group bases by branching points 1307 for b in base: # group bases by branching points
1107 bp = repo.revs('ancestor(%d, %d)', b, dest.rev()).first() 1308 bp = repo.revs('ancestor(%d, %d)', b, dest.rev()).first()
1108 bpbase[bp] = bpbase.get(bp, []) + [b] 1309 bpbase[bp] = bpbase.get(bp, []) + [b]
1109 if None in bpbase: 1310 if None in bpbase:
1110 # emulate the old behavior, showing "nothing to rebase" (a better 1311 # emulate the old behavior, showing "nothing to rebase" (a better
1111 # behavior may be abort with "cannot find branching point" error) 1312 # behavior may be abort with "cannot find branching point" error)
1112 bpbase.clear() 1313 bpbase.clear()
1113 for bp, bs in bpbase.iteritems(): # calculate roots 1314 for bp, bs in bpbase.iteritems(): # calculate roots
1114 roots += list(repo.revs('children(%d) & ancestors(%ld)', bp, bs)) 1315 roots += list(repo.revs('children(%d) & ancestors(%ld)', bp, bs))
1115 1316
1116 rebaseset = repo.revs('%ld::', roots) 1317 rebaseset = repo.revs('%ld::', roots)
1117 1318
1118 if not rebaseset: 1319 if not rebaseset:
1119 # transform to list because smartsets are not comparable to 1320 # transform to list because smartsets are not comparable to
1120 # lists. This should be improved to honor laziness of 1321 # lists. This should be improved to honor laziness of
1121 # smartset. 1322 # smartset.
1122 if list(base) == [dest.rev()]: 1323 if list(base) == [dest.rev()]:
1123 if basef: 1324 if basef:
1124 ui.status(_('nothing to rebase - %s is both "base"' 1325 ui.status(
1125 ' and destination\n') % dest) 1326 _(
1327 'nothing to rebase - %s is both "base"'
1328 ' and destination\n'
1329 )
1330 % dest
1331 )
1126 else: 1332 else:
1127 ui.status(_('nothing to rebase - working directory ' 1333 ui.status(
1128 'parent is also destination\n')) 1334 _(
1335 'nothing to rebase - working directory '
1336 'parent is also destination\n'
1337 )
1338 )
1129 elif not repo.revs('%ld - ::%d', base, dest.rev()): 1339 elif not repo.revs('%ld - ::%d', base, dest.rev()):
1130 if basef: 1340 if basef:
1131 ui.status(_('nothing to rebase - "base" %s is ' 1341 ui.status(
1132 'already an ancestor of destination ' 1342 _(
1133 '%s\n') % 1343 'nothing to rebase - "base" %s is '
1134 ('+'.join(bytes(repo[r]) for r in base), 1344 'already an ancestor of destination '
1135 dest)) 1345 '%s\n'
1346 )
1347 % ('+'.join(bytes(repo[r]) for r in base), dest)
1348 )
1136 else: 1349 else:
1137 ui.status(_('nothing to rebase - working ' 1350 ui.status(
1138 'directory parent is already an ' 1351 _(
1139 'ancestor of destination %s\n') % dest) 1352 'nothing to rebase - working '
1140 else: # can it happen? 1353 'directory parent is already an '
1141 ui.status(_('nothing to rebase from %s to %s\n') % 1354 'ancestor of destination %s\n'
1142 ('+'.join(bytes(repo[r]) for r in base), dest)) 1355 )
1356 % dest
1357 )
1358 else: # can it happen?
1359 ui.status(
1360 _('nothing to rebase from %s to %s\n')
1361 % ('+'.join(bytes(repo[r]) for r in base), dest)
1362 )
1143 return None 1363 return None
1144 1364
1145 rebasingwcp = repo['.'].rev() in rebaseset 1365 rebasingwcp = repo['.'].rev() in rebaseset
1146 ui.log("rebase", "rebasing working copy parent: %r\n", rebasingwcp, 1366 ui.log(
1147 rebase_rebasing_wcp=rebasingwcp) 1367 "rebase",
1368 "rebasing working copy parent: %r\n",
1369 rebasingwcp,
1370 rebase_rebasing_wcp=rebasingwcp,
1371 )
1148 if inmemory and rebasingwcp: 1372 if inmemory and rebasingwcp:
1149 # Check these since we did not before. 1373 # Check these since we did not before.
1150 cmdutil.checkunfinished(repo) 1374 cmdutil.checkunfinished(repo)
1151 cmdutil.bailifchanged(repo) 1375 cmdutil.bailifchanged(repo)
1152 1376
1173 if size == 1: 1397 if size == 1:
1174 destmap[r] = destset.first() 1398 destmap[r] = destset.first()
1175 elif size == 0: 1399 elif size == 0:
1176 ui.note(_('skipping %s - empty destination\n') % repo[r]) 1400 ui.note(_('skipping %s - empty destination\n') % repo[r])
1177 else: 1401 else:
1178 raise error.Abort(_('rebase destination for %s is not ' 1402 raise error.Abort(
1179 'unique') % repo[r]) 1403 _('rebase destination for %s is not ' 'unique')
1404 % repo[r]
1405 )
1180 1406
1181 if dest is not None: 1407 if dest is not None:
1182 # single-dest case: assign dest to each rev in rebaseset 1408 # single-dest case: assign dest to each rev in rebaseset
1183 destrev = dest.rev() 1409 destrev = dest.rev()
1184 destmap = {r: destrev for r in rebaseset} # {srcrev: destrev} 1410 destmap = {r: destrev for r in rebaseset} # {srcrev: destrev}
1185 1411
1186 if not destmap: 1412 if not destmap:
1187 ui.status(_('nothing to rebase - empty destination\n')) 1413 ui.status(_('nothing to rebase - empty destination\n'))
1188 return None 1414 return None
1189 1415
1190 return destmap 1416 return destmap
1417
1191 1418
1192 def externalparent(repo, state, destancestors): 1419 def externalparent(repo, state, destancestors):
1193 """Return the revision that should be used as the second parent 1420 """Return the revision that should be used as the second parent
1194 when the revisions in state is collapsed on top of destancestors. 1421 when the revisions in state is collapsed on top of destancestors.
1195 Abort if there is more than one parent. 1422 Abort if there is more than one parent.
1198 source = min(state) 1425 source = min(state)
1199 for rev in state: 1426 for rev in state:
1200 if rev == source: 1427 if rev == source:
1201 continue 1428 continue
1202 for p in repo[rev].parents(): 1429 for p in repo[rev].parents():
1203 if (p.rev() not in state 1430 if p.rev() not in state and p.rev() not in destancestors:
1204 and p.rev() not in destancestors):
1205 parents.add(p.rev()) 1431 parents.add(p.rev())
1206 if not parents: 1432 if not parents:
1207 return nullrev 1433 return nullrev
1208 if len(parents) == 1: 1434 if len(parents) == 1:
1209 return parents.pop() 1435 return parents.pop()
1210 raise error.Abort(_('unable to collapse on top of %d, there is more ' 1436 raise error.Abort(
1211 'than one external parent: %s') % 1437 _(
1212 (max(destancestors), 1438 'unable to collapse on top of %d, there is more '
1213 ', '.join("%d" % p for p in sorted(parents)))) 1439 'than one external parent: %s'
1440 )
1441 % (max(destancestors), ', '.join("%d" % p for p in sorted(parents)))
1442 )
1443
1214 1444
1215 def commitmemorynode(repo, p1, p2, wctx, editor, extra, user, date, commitmsg): 1445 def commitmemorynode(repo, p1, p2, wctx, editor, extra, user, date, commitmsg):
1216 '''Commit the memory changes with parents p1 and p2. 1446 '''Commit the memory changes with parents p1 and p2.
1217 Return node of committed revision.''' 1447 Return node of committed revision.'''
1218 # Replicates the empty check in ``repo.commit``. 1448 # Replicates the empty check in ``repo.commit``.
1223 # ``branch`` (used when passing ``--keepbranches``). 1453 # ``branch`` (used when passing ``--keepbranches``).
1224 branch = repo[p1].branch() 1454 branch = repo[p1].branch()
1225 if 'branch' in extra: 1455 if 'branch' in extra:
1226 branch = extra['branch'] 1456 branch = extra['branch']
1227 1457
1228 memctx = wctx.tomemctx(commitmsg, parents=(p1, p2), date=date, 1458 memctx = wctx.tomemctx(
1229 extra=extra, user=user, branch=branch, editor=editor) 1459 commitmsg,
1460 parents=(p1, p2),
1461 date=date,
1462 extra=extra,
1463 user=user,
1464 branch=branch,
1465 editor=editor,
1466 )
1230 commitres = repo.commitctx(memctx) 1467 commitres = repo.commitctx(memctx)
1231 wctx.clean() # Might be reused 1468 wctx.clean() # Might be reused
1232 return commitres 1469 return commitres
1470
1233 1471
1234 def commitnode(repo, p1, p2, editor, extra, user, date, commitmsg): 1472 def commitnode(repo, p1, p2, editor, extra, user, date, commitmsg):
1235 '''Commit the wd changes with parents p1 and p2. 1473 '''Commit the wd changes with parents p1 and p2.
1236 Return node of committed revision.''' 1474 Return node of committed revision.'''
1237 dsguard = util.nullcontextmanager() 1475 dsguard = util.nullcontextmanager()
1239 dsguard = dirstateguard.dirstateguard(repo, 'rebase') 1477 dsguard = dirstateguard.dirstateguard(repo, 'rebase')
1240 with dsguard: 1478 with dsguard:
1241 repo.setparents(repo[p1].node(), repo[p2].node()) 1479 repo.setparents(repo[p1].node(), repo[p2].node())
1242 1480
1243 # Commit might fail if unresolved files exist 1481 # Commit might fail if unresolved files exist
1244 newnode = repo.commit(text=commitmsg, user=user, date=date, 1482 newnode = repo.commit(
1245 extra=extra, editor=editor) 1483 text=commitmsg, user=user, date=date, extra=extra, editor=editor
1484 )
1246 1485
1247 repo.dirstate.setbranch(repo[newnode].branch()) 1486 repo.dirstate.setbranch(repo[newnode].branch())
1248 return newnode 1487 return newnode
1488
1249 1489
1250 def rebasenode(repo, rev, p1, base, collapse, dest, wctx): 1490 def rebasenode(repo, rev, p1, base, collapse, dest, wctx):
1251 'Rebase a single revision rev on top of p1 using base as merge ancestor' 1491 'Rebase a single revision rev on top of p1 using base as merge ancestor'
1252 # Merge phase 1492 # Merge phase
1253 # Update to destination and merge it with local 1493 # Update to destination and merge it with local
1266 repo.ui.debug(" merge against %d:%s\n" % (rev, repo[rev])) 1506 repo.ui.debug(" merge against %d:%s\n" % (rev, repo[rev]))
1267 if base is not None: 1507 if base is not None:
1268 repo.ui.debug(" detach base %d:%s\n" % (base, repo[base])) 1508 repo.ui.debug(" detach base %d:%s\n" % (base, repo[base]))
1269 # When collapsing in-place, the parent is the common ancestor, we 1509 # When collapsing in-place, the parent is the common ancestor, we
1270 # have to allow merging with it. 1510 # have to allow merging with it.
1271 stats = mergemod.update(repo, rev, branchmerge=True, force=True, 1511 stats = mergemod.update(
1272 ancestor=base, mergeancestor=collapse, 1512 repo,
1273 labels=['dest', 'source'], wc=wctx) 1513 rev,
1514 branchmerge=True,
1515 force=True,
1516 ancestor=base,
1517 mergeancestor=collapse,
1518 labels=['dest', 'source'],
1519 wc=wctx,
1520 )
1274 if collapse: 1521 if collapse:
1275 copies.duplicatecopies(repo, wctx, rev, dest) 1522 copies.duplicatecopies(repo, wctx, rev, dest)
1276 else: 1523 else:
1277 # If we're not using --collapse, we need to 1524 # If we're not using --collapse, we need to
1278 # duplicate copies between the revision we're 1525 # duplicate copies between the revision we're
1280 # duplicate any copies that have already been 1527 # duplicate any copies that have already been
1281 # performed in the destination. 1528 # performed in the destination.
1282 p1rev = repo[rev].p1().rev() 1529 p1rev = repo[rev].p1().rev()
1283 copies.duplicatecopies(repo, wctx, rev, p1rev, skiprev=dest) 1530 copies.duplicatecopies(repo, wctx, rev, p1rev, skiprev=dest)
1284 return stats 1531 return stats
1532
1285 1533
1286 def adjustdest(repo, rev, destmap, state, skipped): 1534 def adjustdest(repo, rev, destmap, state, skipped):
1287 r"""adjust rebase destination given the current rebase state 1535 r"""adjust rebase destination given the current rebase state
1288 1536
1289 rev is what is being rebased. Return a list of two revs, which are the 1537 rev is what is being rebased. Return a list of two revs, which are the
1335 \ / 1583 \ /
1336 A 1584 A
1337 """ 1585 """
1338 # pick already rebased revs with same dest from state as interesting source 1586 # pick already rebased revs with same dest from state as interesting source
1339 dest = destmap[rev] 1587 dest = destmap[rev]
1340 source = [s for s, d in state.items() 1588 source = [
1341 if d > 0 and destmap[s] == dest and s not in skipped] 1589 s
1590 for s, d in state.items()
1591 if d > 0 and destmap[s] == dest and s not in skipped
1592 ]
1342 1593
1343 result = [] 1594 result = []
1344 for prev in repo.changelog.parentrevs(rev): 1595 for prev in repo.changelog.parentrevs(rev):
1345 adjusted = dest 1596 adjusted = dest
1346 if prev != nullrev: 1597 if prev != nullrev:
1350 if adjusted == dest and dest in state: 1601 if adjusted == dest and dest in state:
1351 adjusted = state[dest] 1602 adjusted = state[dest]
1352 if adjusted == revtodo: 1603 if adjusted == revtodo:
1353 # sortsource should produce an order that makes this impossible 1604 # sortsource should produce an order that makes this impossible
1354 raise error.ProgrammingError( 1605 raise error.ProgrammingError(
1355 'rev %d should be rebased already at this time' % dest) 1606 'rev %d should be rebased already at this time' % dest
1607 )
1356 result.append(adjusted) 1608 result.append(adjusted)
1357 return result 1609 return result
1610
1358 1611
1359 def _checkobsrebase(repo, ui, rebaseobsrevs, rebaseobsskipped): 1612 def _checkobsrebase(repo, ui, rebaseobsrevs, rebaseobsskipped):
1360 """ 1613 """
1361 Abort if rebase will create divergence or rebase is noop because of markers 1614 Abort if rebase will create divergence or rebase is noop because of markers
1362 1615
1363 `rebaseobsrevs`: set of obsolete revision in source 1616 `rebaseobsrevs`: set of obsolete revision in source
1364 `rebaseobsskipped`: set of revisions from source skipped because they have 1617 `rebaseobsskipped`: set of revisions from source skipped because they have
1365 successors in destination or no non-obsolete successor. 1618 successors in destination or no non-obsolete successor.
1366 """ 1619 """
1367 # Obsolete node with successors not in dest leads to divergence 1620 # Obsolete node with successors not in dest leads to divergence
1368 divergenceok = ui.configbool('experimental', 1621 divergenceok = ui.configbool('experimental', 'evolution.allowdivergence')
1369 'evolution.allowdivergence')
1370 divergencebasecandidates = rebaseobsrevs - rebaseobsskipped 1622 divergencebasecandidates = rebaseobsrevs - rebaseobsskipped
1371 1623
1372 if divergencebasecandidates and not divergenceok: 1624 if divergencebasecandidates and not divergenceok:
1373 divhashes = (bytes(repo[r]) 1625 divhashes = (bytes(repo[r]) for r in divergencebasecandidates)
1374 for r in divergencebasecandidates) 1626 msg = _("this rebase will cause " "divergences from: %s")
1375 msg = _("this rebase will cause " 1627 h = _(
1376 "divergences from: %s") 1628 "to force the rebase please set "
1377 h = _("to force the rebase please set " 1629 "experimental.evolution.allowdivergence=True"
1378 "experimental.evolution.allowdivergence=True") 1630 )
1379 raise error.Abort(msg % (",".join(divhashes),), hint=h) 1631 raise error.Abort(msg % (",".join(divhashes),), hint=h)
1632
1380 1633
1381 def successorrevs(unfi, rev): 1634 def successorrevs(unfi, rev):
1382 """yield revision numbers for successors of rev""" 1635 """yield revision numbers for successors of rev"""
1383 assert unfi.filtername is None 1636 assert unfi.filtername is None
1384 nodemap = unfi.changelog.nodemap 1637 nodemap = unfi.changelog.nodemap
1385 for s in obsutil.allsuccessors(unfi.obsstore, [unfi[rev].node()]): 1638 for s in obsutil.allsuccessors(unfi.obsstore, [unfi[rev].node()]):
1386 if s in nodemap: 1639 if s in nodemap:
1387 yield nodemap[s] 1640 yield nodemap[s]
1388 1641
1642
1389 def defineparents(repo, rev, destmap, state, skipped, obsskipped): 1643 def defineparents(repo, rev, destmap, state, skipped, obsskipped):
1390 """Return new parents and optionally a merge base for rev being rebased 1644 """Return new parents and optionally a merge base for rev being rebased
1391 1645
1392 The destination specified by "dest" cannot always be used directly because 1646 The destination specified by "dest" cannot always be used directly because
1393 previously rebase result could affect destination. For example, 1647 previously rebase result could affect destination. For example,
1405 assert repo.filtername is None 1659 assert repo.filtername is None
1406 cl = repo.changelog 1660 cl = repo.changelog
1407 isancestor = cl.isancestorrev 1661 isancestor = cl.isancestorrev
1408 1662
1409 dest = destmap[rev] 1663 dest = destmap[rev]
1410 oldps = repo.changelog.parentrevs(rev) # old parents 1664 oldps = repo.changelog.parentrevs(rev) # old parents
1411 newps = [nullrev, nullrev] # new parents 1665 newps = [nullrev, nullrev] # new parents
1412 dests = adjustdest(repo, rev, destmap, state, skipped) 1666 dests = adjustdest(repo, rev, destmap, state, skipped)
1413 bases = list(oldps) # merge base candidates, initially just old parents 1667 bases = list(oldps) # merge base candidates, initially just old parents
1414 1668
1415 if all(r == nullrev for r in oldps[1:]): 1669 if all(r == nullrev for r in oldps[1:]):
1416 # For non-merge changeset, just move p to adjusted dest as requested. 1670 # For non-merge changeset, just move p to adjusted dest as requested.
1417 newps[0] = dests[0] 1671 newps[0] = dests[0]
1418 else: 1672 else:
1437 # A B D # B (using rule "2."), since B will be rebased. 1691 # A B D # B (using rule "2."), since B will be rebased.
1438 # 1692 #
1439 # The loop tries to be not rely on the fact that a Mercurial node has 1693 # The loop tries to be not rely on the fact that a Mercurial node has
1440 # at most 2 parents. 1694 # at most 2 parents.
1441 for i, p in enumerate(oldps): 1695 for i, p in enumerate(oldps):
1442 np = p # new parent 1696 np = p # new parent
1443 if any(isancestor(x, dests[i]) for x in successorrevs(repo, p)): 1697 if any(isancestor(x, dests[i]) for x in successorrevs(repo, p)):
1444 np = dests[i] 1698 np = dests[i]
1445 elif p in state and state[p] > 0: 1699 elif p in state and state[p] > 0:
1446 np = state[p] 1700 np = state[p]
1447 1701
1463 1717
1464 # If one parent becomes an ancestor of the other, drop the ancestor 1718 # If one parent becomes an ancestor of the other, drop the ancestor
1465 for j, x in enumerate(newps[:i]): 1719 for j, x in enumerate(newps[:i]):
1466 if x == nullrev: 1720 if x == nullrev:
1467 continue 1721 continue
1468 if isancestor(np, x): # CASE-1 1722 if isancestor(np, x): # CASE-1
1469 np = nullrev 1723 np = nullrev
1470 elif isancestor(x, np): # CASE-2 1724 elif isancestor(x, np): # CASE-2
1471 newps[j] = np 1725 newps[j] = np
1472 np = nullrev 1726 np = nullrev
1473 # New parents forming an ancestor relationship does not 1727 # New parents forming an ancestor relationship does not
1474 # mean the old parents have a similar relationship. Do not 1728 # mean the old parents have a similar relationship. Do not
1475 # set bases[x] to nullrev. 1729 # set bases[x] to nullrev.
1490 # 1744 #
1491 # C # rebase -r C -d D 1745 # C # rebase -r C -d D
1492 # /| # None of A and B will be changed to D and rebase fails. 1746 # /| # None of A and B will be changed to D and rebase fails.
1493 # A B D 1747 # A B D
1494 if set(newps) == set(oldps) and dest not in newps: 1748 if set(newps) == set(oldps) and dest not in newps:
1495 raise error.Abort(_('cannot rebase %d:%s without ' 1749 raise error.Abort(
1496 'moving at least one of its parents') 1750 _(
1497 % (rev, repo[rev])) 1751 'cannot rebase %d:%s without '
1752 'moving at least one of its parents'
1753 )
1754 % (rev, repo[rev])
1755 )
1498 1756
1499 # Source should not be ancestor of dest. The check here guarantees it's 1757 # Source should not be ancestor of dest. The check here guarantees it's
1500 # impossible. With multi-dest, the initial check does not cover complex 1758 # impossible. With multi-dest, the initial check does not cover complex
1501 # cases since we don't have abstractions to dry-run rebase cheaply. 1759 # cases since we don't have abstractions to dry-run rebase cheaply.
1502 if any(p != nullrev and isancestor(rev, p) for p in newps): 1760 if any(p != nullrev and isancestor(rev, p) for p in newps):
1522 # 1780 #
1523 # But our merge base candidates (D and E in above case) could still be 1781 # But our merge base candidates (D and E in above case) could still be
1524 # better than the default (ancestor(F, Z) == null). Therefore still 1782 # better than the default (ancestor(F, Z) == null). Therefore still
1525 # pick one (so choose p1 above). 1783 # pick one (so choose p1 above).
1526 if sum(1 for b in bases if b != nullrev) > 1: 1784 if sum(1 for b in bases if b != nullrev) > 1:
1527 unwanted = [None, None] # unwanted[i]: unwanted revs if choose bases[i] 1785 unwanted = [None, None] # unwanted[i]: unwanted revs if choose bases[i]
1528 for i, base in enumerate(bases): 1786 for i, base in enumerate(bases):
1529 if base == nullrev: 1787 if base == nullrev:
1530 continue 1788 continue
1531 # Revisions in the side (not chosen as merge base) branch that 1789 # Revisions in the side (not chosen as merge base) branch that
1532 # might contain "surprising" contents 1790 # might contain "surprising" contents
1533 siderevs = list(repo.revs('((%ld-%d) %% (%d+%d))', 1791 siderevs = list(
1534 bases, base, base, dest)) 1792 repo.revs('((%ld-%d) %% (%d+%d))', bases, base, base, dest)
1793 )
1535 1794
1536 # If those revisions are covered by rebaseset, the result is good. 1795 # If those revisions are covered by rebaseset, the result is good.
1537 # A merge in rebaseset would be considered to cover its ancestors. 1796 # A merge in rebaseset would be considered to cover its ancestors.
1538 if siderevs: 1797 if siderevs:
1539 rebaseset = [r for r, d in state.items() 1798 rebaseset = [
1540 if d > 0 and r not in obsskipped] 1799 r for r, d in state.items() if d > 0 and r not in obsskipped
1541 merges = [r for r in rebaseset 1800 ]
1542 if cl.parentrevs(r)[1] != nullrev] 1801 merges = [
1543 unwanted[i] = list(repo.revs('%ld - (::%ld) - %ld', 1802 r for r in rebaseset if cl.parentrevs(r)[1] != nullrev
1544 siderevs, merges, rebaseset)) 1803 ]
1804 unwanted[i] = list(
1805 repo.revs(
1806 '%ld - (::%ld) - %ld', siderevs, merges, rebaseset
1807 )
1808 )
1545 1809
1546 # Choose a merge base that has a minimal number of unwanted revs. 1810 # Choose a merge base that has a minimal number of unwanted revs.
1547 l, i = min((len(revs), i) 1811 l, i = min(
1548 for i, revs in enumerate(unwanted) if revs is not None) 1812 (len(revs), i)
1813 for i, revs in enumerate(unwanted)
1814 if revs is not None
1815 )
1549 base = bases[i] 1816 base = bases[i]
1550 1817
1551 # newps[0] should match merge base if possible. Currently, if newps[i] 1818 # newps[0] should match merge base if possible. Currently, if newps[i]
1552 # is nullrev, the only case is newps[i] and newps[j] (j < i), one is 1819 # is nullrev, the only case is newps[i] and newps[j] (j < i), one is
1553 # the other's ancestor. In that case, it's fine to not swap newps here. 1820 # the other's ancestor. In that case, it's fine to not swap newps here.
1557 1824
1558 # The merge will include unwanted revisions. Abort now. Revisit this if 1825 # The merge will include unwanted revisions. Abort now. Revisit this if
1559 # we have a more advanced merge algorithm that handles multiple bases. 1826 # we have a more advanced merge algorithm that handles multiple bases.
1560 if l > 0: 1827 if l > 0:
1561 unwanteddesc = _(' or ').join( 1828 unwanteddesc = _(' or ').join(
1562 (', '.join('%d:%s' % (r, repo[r]) for r in revs) 1829 (
1563 for revs in unwanted if revs is not None)) 1830 ', '.join('%d:%s' % (r, repo[r]) for r in revs)
1831 for revs in unwanted
1832 if revs is not None
1833 )
1834 )
1564 raise error.Abort( 1835 raise error.Abort(
1565 _('rebasing %d:%s will include unwanted changes from %s') 1836 _('rebasing %d:%s will include unwanted changes from %s')
1566 % (rev, repo[rev], unwanteddesc)) 1837 % (rev, repo[rev], unwanteddesc)
1838 )
1567 1839
1568 repo.ui.debug(" future parents are %d and %d\n" % tuple(newps)) 1840 repo.ui.debug(" future parents are %d and %d\n" % tuple(newps))
1569 1841
1570 return newps[0], newps[1], base 1842 return newps[0], newps[1], base
1843
1571 1844
1572 def isagitpatch(repo, patchname): 1845 def isagitpatch(repo, patchname):
1573 'Return true if the given patch is in git format' 1846 'Return true if the given patch is in git format'
1574 mqpatch = os.path.join(repo.mq.path, patchname) 1847 mqpatch = os.path.join(repo.mq.path, patchname)
1575 for line in patch.linereader(open(mqpatch, 'rb')): 1848 for line in patch.linereader(open(mqpatch, 'rb')):
1576 if line.startswith('diff --git'): 1849 if line.startswith('diff --git'):
1577 return True 1850 return True
1578 return False 1851 return False
1579 1852
1853
1580 def updatemq(repo, state, skipped, **opts): 1854 def updatemq(repo, state, skipped, **opts):
1581 'Update rebased mq patches - finalize and then import them' 1855 'Update rebased mq patches - finalize and then import them'
1582 mqrebase = {} 1856 mqrebase = {}
1583 mq = repo.mq 1857 mq = repo.mq
1584 original_series = mq.fullseries[:] 1858 original_series = mq.fullseries[:]
1585 skippedpatches = set() 1859 skippedpatches = set()
1586 1860
1587 for p in mq.applied: 1861 for p in mq.applied:
1588 rev = repo[p.node].rev() 1862 rev = repo[p.node].rev()
1589 if rev in state: 1863 if rev in state:
1590 repo.ui.debug('revision %d is an mq patch (%s), finalize it.\n' % 1864 repo.ui.debug(
1591 (rev, p.name)) 1865 'revision %d is an mq patch (%s), finalize it.\n'
1866 % (rev, p.name)
1867 )
1592 mqrebase[rev] = (p.name, isagitpatch(repo, p.name)) 1868 mqrebase[rev] = (p.name, isagitpatch(repo, p.name))
1593 else: 1869 else:
1594 # Applied but not rebased, not sure this should happen 1870 # Applied but not rebased, not sure this should happen
1595 skippedpatches.add(p.name) 1871 skippedpatches.add(p.name)
1596 1872
1599 1875
1600 # We must start import from the newest revision 1876 # We must start import from the newest revision
1601 for rev in sorted(mqrebase, reverse=True): 1877 for rev in sorted(mqrebase, reverse=True):
1602 if rev not in skipped: 1878 if rev not in skipped:
1603 name, isgit = mqrebase[rev] 1879 name, isgit = mqrebase[rev]
1604 repo.ui.note(_('updating mq patch %s to %d:%s\n') % 1880 repo.ui.note(
1605 (name, state[rev], repo[state[rev]])) 1881 _('updating mq patch %s to %d:%s\n')
1606 mq.qimport(repo, (), patchname=name, git=isgit, 1882 % (name, state[rev], repo[state[rev]])
1607 rev=["%d" % state[rev]]) 1883 )
1884 mq.qimport(
1885 repo, (), patchname=name, git=isgit, rev=["%d" % state[rev]]
1886 )
1608 else: 1887 else:
1609 # Rebased and skipped 1888 # Rebased and skipped
1610 skippedpatches.add(mqrebase[rev][0]) 1889 skippedpatches.add(mqrebase[rev][0])
1611 1890
1612 # Patches were either applied and rebased and imported in 1891 # Patches were either applied and rebased and imported in
1613 # order, applied and removed or unapplied. Discard the removed 1892 # order, applied and removed or unapplied. Discard the removed
1614 # ones while preserving the original series order and guards. 1893 # ones while preserving the original series order and guards.
1615 newseries = [s for s in original_series 1894 newseries = [
1616 if mq.guard_re.split(s, 1)[0] not in skippedpatches] 1895 s
1896 for s in original_series
1897 if mq.guard_re.split(s, 1)[0] not in skippedpatches
1898 ]
1617 mq.fullseries[:] = newseries 1899 mq.fullseries[:] = newseries
1618 mq.seriesdirty = True 1900 mq.seriesdirty = True
1619 mq.savedirty() 1901 mq.savedirty()
1902
1620 1903
1621 def storecollapsemsg(repo, collapsemsg): 1904 def storecollapsemsg(repo, collapsemsg):
1622 'Store the collapse message to allow recovery' 1905 'Store the collapse message to allow recovery'
1623 collapsemsg = collapsemsg or '' 1906 collapsemsg = collapsemsg or ''
1624 f = repo.vfs("last-message.txt", "w") 1907 f = repo.vfs("last-message.txt", "w")
1625 f.write("%s\n" % collapsemsg) 1908 f.write("%s\n" % collapsemsg)
1626 f.close() 1909 f.close()
1627 1910
1911
1628 def clearcollapsemsg(repo): 1912 def clearcollapsemsg(repo):
1629 'Remove collapse message file' 1913 'Remove collapse message file'
1630 repo.vfs.unlinkpath("last-message.txt", ignoremissing=True) 1914 repo.vfs.unlinkpath("last-message.txt", ignoremissing=True)
1915
1631 1916
1632 def restorecollapsemsg(repo, isabort): 1917 def restorecollapsemsg(repo, isabort):
1633 'Restore previously stored collapse message' 1918 'Restore previously stored collapse message'
1634 try: 1919 try:
1635 f = repo.vfs("last-message.txt") 1920 f = repo.vfs("last-message.txt")
1643 collapsemsg = '' 1928 collapsemsg = ''
1644 else: 1929 else:
1645 raise error.Abort(_('missing .hg/last-message.txt for rebase')) 1930 raise error.Abort(_('missing .hg/last-message.txt for rebase'))
1646 return collapsemsg 1931 return collapsemsg
1647 1932
1933
1648 def clearstatus(repo): 1934 def clearstatus(repo):
1649 'Remove the status files' 1935 'Remove the status files'
1650 # Make sure the active transaction won't write the state file 1936 # Make sure the active transaction won't write the state file
1651 tr = repo.currenttransaction() 1937 tr = repo.currenttransaction()
1652 if tr: 1938 if tr:
1653 tr.removefilegenerator('rebasestate') 1939 tr.removefilegenerator('rebasestate')
1654 repo.vfs.unlinkpath("rebasestate", ignoremissing=True) 1940 repo.vfs.unlinkpath("rebasestate", ignoremissing=True)
1655 1941
1942
1656 def needupdate(repo, state): 1943 def needupdate(repo, state):
1657 '''check whether we should `update --clean` away from a merge, or if 1944 '''check whether we should `update --clean` away from a merge, or if
1658 somehow the working dir got forcibly updated, e.g. by older hg''' 1945 somehow the working dir got forcibly updated, e.g. by older hg'''
1659 parents = [p.rev() for p in repo[None].parents()] 1946 parents = [p.rev() for p in repo[None].parents()]
1660 1947
1661 # Are we in a merge state at all? 1948 # Are we in a merge state at all?
1662 if len(parents) < 2: 1949 if len(parents) < 2:
1663 return False 1950 return False
1664 1951
1665 # We should be standing on the first as-of-yet unrebased commit. 1952 # We should be standing on the first as-of-yet unrebased commit.
1666 firstunrebased = min([old for old, new in state.iteritems() 1953 firstunrebased = min(
1667 if new == nullrev]) 1954 [old for old, new in state.iteritems() if new == nullrev]
1955 )
1668 if firstunrebased in parents: 1956 if firstunrebased in parents:
1669 return True 1957 return True
1670 1958
1671 return False 1959 return False
1960
1672 1961
1673 def sortsource(destmap): 1962 def sortsource(destmap):
1674 """yield source revisions in an order that we only rebase things once 1963 """yield source revisions in an order that we only rebase things once
1675 1964
1676 If source and destination overlaps, we should filter out revisions 1965 If source and destination overlaps, we should filter out revisions
1693 if not result: 1982 if not result:
1694 raise error.Abort(_('source and destination form a cycle')) 1983 raise error.Abort(_('source and destination form a cycle'))
1695 srcset -= set(result) 1984 srcset -= set(result)
1696 yield result 1985 yield result
1697 1986
1987
1698 def buildstate(repo, destmap, collapse): 1988 def buildstate(repo, destmap, collapse):
1699 '''Define which revisions are going to be rebased and where 1989 '''Define which revisions are going to be rebased and where
1700 1990
1701 repo: repo 1991 repo: repo
1702 destmap: {srcrev: destrev} 1992 destmap: {srcrev: destrev}
1711 mqapplied = set(repo[s.node].rev() for s in repo.mq.applied) 2001 mqapplied = set(repo[s.node].rev() for s in repo.mq.applied)
1712 if set(destmap.values()) & mqapplied: 2002 if set(destmap.values()) & mqapplied:
1713 raise error.Abort(_('cannot rebase onto an applied mq patch')) 2003 raise error.Abort(_('cannot rebase onto an applied mq patch'))
1714 2004
1715 # Get "cycle" error early by exhausting the generator. 2005 # Get "cycle" error early by exhausting the generator.
1716 sortedsrc = list(sortsource(destmap)) # a list of sorted revs 2006 sortedsrc = list(sortsource(destmap)) # a list of sorted revs
1717 if not sortedsrc: 2007 if not sortedsrc:
1718 raise error.Abort(_('no matching revisions')) 2008 raise error.Abort(_('no matching revisions'))
1719 2009
1720 # Only check the first batch of revisions to rebase not depending on other 2010 # Only check the first batch of revisions to rebase not depending on other
1721 # rebaseset. This means "source is ancestor of destination" for the second 2011 # rebaseset. This means "source is ancestor of destination" for the second
1722 # (and following) batches of revisions are not checked here. We rely on 2012 # (and following) batches of revisions are not checked here. We rely on
1723 # "defineparents" to do that check. 2013 # "defineparents" to do that check.
1724 roots = list(repo.set('roots(%ld)', sortedsrc[0])) 2014 roots = list(repo.set('roots(%ld)', sortedsrc[0]))
1725 if not roots: 2015 if not roots:
1726 raise error.Abort(_('no matching revisions')) 2016 raise error.Abort(_('no matching revisions'))
2017
1727 def revof(r): 2018 def revof(r):
1728 return r.rev() 2019 return r.rev()
2020
1729 roots = sorted(roots, key=revof) 2021 roots = sorted(roots, key=revof)
1730 state = dict.fromkeys(rebaseset, revtodo) 2022 state = dict.fromkeys(rebaseset, revtodo)
1731 emptyrebase = (len(sortedsrc) == 1) 2023 emptyrebase = len(sortedsrc) == 1
1732 for root in roots: 2024 for root in roots:
1733 dest = repo[destmap[root.rev()]] 2025 dest = repo[destmap[root.rev()]]
1734 commonbase = root.ancestor(dest) 2026 commonbase = root.ancestor(dest)
1735 if commonbase == root: 2027 if commonbase == root:
1736 raise error.Abort(_('source is ancestor of destination')) 2028 raise error.Abort(_('source is ancestor of destination'))
1757 # if all parents of this revision are done, then so is this revision 2049 # if all parents of this revision are done, then so is this revision
1758 if parents and all((state.get(p) == p for p in parents)): 2050 if parents and all((state.get(p) == p for p in parents)):
1759 state[rev] = rev 2051 state[rev] = rev
1760 return originalwd, destmap, state 2052 return originalwd, destmap, state
1761 2053
1762 def clearrebased(ui, repo, destmap, state, skipped, collapsedas=None, 2054
1763 keepf=False, fm=None, backup=True): 2055 def clearrebased(
2056 ui,
2057 repo,
2058 destmap,
2059 state,
2060 skipped,
2061 collapsedas=None,
2062 keepf=False,
2063 fm=None,
2064 backup=True,
2065 ):
1764 """dispose of rebased revision at the end of the rebase 2066 """dispose of rebased revision at the end of the rebase
1765 2067
1766 If `collapsedas` is not None, the rebase was a collapse whose result if the 2068 If `collapsedas` is not None, the rebase was a collapse whose result if the
1767 `collapsedas` node. 2069 `collapsedas` node.
1768 2070
1807 fm.data(nodechanges=nodechanges) 2109 fm.data(nodechanges=nodechanges)
1808 if keepf: 2110 if keepf:
1809 replacements = {} 2111 replacements = {}
1810 scmutil.cleanupnodes(repo, replacements, 'rebase', moves, backup=backup) 2112 scmutil.cleanupnodes(repo, replacements, 'rebase', moves, backup=backup)
1811 2113
2114
1812 def pullrebase(orig, ui, repo, *args, **opts): 2115 def pullrebase(orig, ui, repo, *args, **opts):
1813 'Call rebase after pull if the latter has been invoked with --rebase' 2116 'Call rebase after pull if the latter has been invoked with --rebase'
1814 if opts.get(r'rebase'): 2117 if opts.get(r'rebase'):
1815 if ui.configbool('commands', 'rebase.requiredest'): 2118 if ui.configbool('commands', 'rebase.requiredest'):
1816 msg = _('rebase destination required by configuration') 2119 msg = _('rebase destination required by configuration')
1818 raise error.Abort(msg, hint=hint) 2121 raise error.Abort(msg, hint=hint)
1819 2122
1820 with repo.wlock(), repo.lock(): 2123 with repo.wlock(), repo.lock():
1821 if opts.get(r'update'): 2124 if opts.get(r'update'):
1822 del opts[r'update'] 2125 del opts[r'update']
1823 ui.debug('--update and --rebase are not compatible, ignoring ' 2126 ui.debug(
1824 'the update flag\n') 2127 '--update and --rebase are not compatible, ignoring '
2128 'the update flag\n'
2129 )
1825 2130
1826 cmdutil.checkunfinished(repo, skipmerge=True) 2131 cmdutil.checkunfinished(repo, skipmerge=True)
1827 cmdutil.bailifchanged(repo, hint=_('cannot pull with rebase: ' 2132 cmdutil.bailifchanged(
1828 'please commit or shelve your changes first')) 2133 repo,
2134 hint=_(
2135 'cannot pull with rebase: '
2136 'please commit or shelve your changes first'
2137 ),
2138 )
1829 2139
1830 revsprepull = len(repo) 2140 revsprepull = len(repo)
1831 origpostincoming = commands.postincoming 2141 origpostincoming = commands.postincoming
2142
1832 def _dummy(*args, **kwargs): 2143 def _dummy(*args, **kwargs):
1833 pass 2144 pass
2145
1834 commands.postincoming = _dummy 2146 commands.postincoming = _dummy
1835 try: 2147 try:
1836 ret = orig(ui, repo, *args, **opts) 2148 ret = orig(ui, repo, *args, **opts)
1837 finally: 2149 finally:
1838 commands.postincoming = origpostincoming 2150 commands.postincoming = origpostincoming
1866 raise error.Abort(_('--tool can only be used with --rebase')) 2178 raise error.Abort(_('--tool can only be used with --rebase'))
1867 ret = orig(ui, repo, *args, **opts) 2179 ret = orig(ui, repo, *args, **opts)
1868 2180
1869 return ret 2181 return ret
1870 2182
2183
1871 def _filterobsoleterevs(repo, revs): 2184 def _filterobsoleterevs(repo, revs):
1872 """returns a set of the obsolete revisions in revs""" 2185 """returns a set of the obsolete revisions in revs"""
1873 return set(r for r in revs if repo[r].obsolete()) 2186 return set(r for r in revs if repo[r].obsolete())
2187
1874 2188
1875 def _computeobsoletenotrebased(repo, rebaseobsrevs, destmap): 2189 def _computeobsoletenotrebased(repo, rebaseobsrevs, destmap):
1876 """Return (obsoletenotrebased, obsoletewithoutsuccessorindestination). 2190 """Return (obsoletenotrebased, obsoletewithoutsuccessorindestination).
1877 2191
1878 `obsoletenotrebased` is a mapping mapping obsolete => successor for all 2192 `obsoletenotrebased` is a mapping mapping obsolete => successor for all
1922 obsoletenotrebased, 2236 obsoletenotrebased,
1923 obsoletewithoutsuccessorindestination, 2237 obsoletewithoutsuccessorindestination,
1924 obsoleteextinctsuccessors, 2238 obsoleteextinctsuccessors,
1925 ) 2239 )
1926 2240
2241
1927 def abortrebase(ui, repo): 2242 def abortrebase(ui, repo):
1928 with repo.wlock(), repo.lock(): 2243 with repo.wlock(), repo.lock():
1929 rbsrt = rebaseruntime(repo, ui) 2244 rbsrt = rebaseruntime(repo, ui)
1930 rbsrt._prepareabortorcontinue(isabort=True) 2245 rbsrt._prepareabortorcontinue(isabort=True)
2246
1931 2247
1932 def continuerebase(ui, repo): 2248 def continuerebase(ui, repo):
1933 with repo.wlock(), repo.lock(): 2249 with repo.wlock(), repo.lock():
1934 rbsrt = rebaseruntime(repo, ui) 2250 rbsrt = rebaseruntime(repo, ui)
1935 ms = mergemod.mergestate.read(repo) 2251 ms = mergemod.mergestate.read(repo)
1937 retcode = rbsrt._prepareabortorcontinue(isabort=False) 2253 retcode = rbsrt._prepareabortorcontinue(isabort=False)
1938 if retcode is not None: 2254 if retcode is not None:
1939 return retcode 2255 return retcode
1940 rbsrt._performrebase(None) 2256 rbsrt._performrebase(None)
1941 rbsrt._finishrebase() 2257 rbsrt._finishrebase()
2258
1942 2259
1943 def summaryhook(ui, repo): 2260 def summaryhook(ui, repo):
1944 if not repo.vfs.exists('rebasestate'): 2261 if not repo.vfs.exists('rebasestate'):
1945 return 2262 return
1946 try: 2263 try:
1952 msg = _('rebase: (use "hg rebase --abort" to clear broken state)\n') 2269 msg = _('rebase: (use "hg rebase --abort" to clear broken state)\n')
1953 ui.write(msg) 2270 ui.write(msg)
1954 return 2271 return
1955 numrebased = len([i for i in state.itervalues() if i >= 0]) 2272 numrebased = len([i for i in state.itervalues() if i >= 0])
1956 # i18n: column positioning for "hg summary" 2273 # i18n: column positioning for "hg summary"
1957 ui.write(_('rebase: %s, %s (rebase --continue)\n') % 2274 ui.write(
1958 (ui.label(_('%d rebased'), 'rebase.rebased') % numrebased, 2275 _('rebase: %s, %s (rebase --continue)\n')
1959 ui.label(_('%d remaining'), 'rebase.remaining') % 2276 % (
1960 (len(state) - numrebased))) 2277 ui.label(_('%d rebased'), 'rebase.rebased') % numrebased,
2278 ui.label(_('%d remaining'), 'rebase.remaining')
2279 % (len(state) - numrebased),
2280 )
2281 )
2282
1961 2283
1962 def uisetup(ui): 2284 def uisetup(ui):
1963 #Replace pull with a decorator to provide --rebase option 2285 # Replace pull with a decorator to provide --rebase option
1964 entry = extensions.wrapcommand(commands.table, 'pull', pullrebase) 2286 entry = extensions.wrapcommand(commands.table, 'pull', pullrebase)
1965 entry[1].append(('', 'rebase', None, 2287 entry[1].append(
1966 _("rebase working directory to branch head"))) 2288 ('', 'rebase', None, _("rebase working directory to branch head"))
1967 entry[1].append(('t', 'tool', '', 2289 )
1968 _("specify merge tool for rebase"))) 2290 entry[1].append(('t', 'tool', '', _("specify merge tool for rebase")))
1969 cmdutil.summaryhooks.add('rebase', summaryhook) 2291 cmdutil.summaryhooks.add('rebase', summaryhook)
1970 statemod.addunfinished('rebase', fname='rebasestate', stopflag=True, 2292 statemod.addunfinished(
1971 continueflag=True, abortfunc=abortrebase, 2293 'rebase',
1972 continuefunc=continuerebase) 2294 fname='rebasestate',
2295 stopflag=True,
2296 continueflag=True,
2297 abortfunc=abortrebase,
2298 continuefunc=continuerebase,
2299 )