428 pos = self._performrebasesubset(tr, subset, pos, total) |
428 pos = self._performrebasesubset(tr, subset, pos, total) |
429 ui.progress(_('rebasing'), None) |
429 ui.progress(_('rebasing'), None) |
430 ui.note(_('rebase merging completed\n')) |
430 ui.note(_('rebase merging completed\n')) |
431 |
431 |
432 def _performrebasesubset(self, tr, subset, pos, total): |
432 def _performrebasesubset(self, tr, subset, pos, total): |
433 repo, ui, opts = self.repo, self.ui, self.opts |
433 sortedrevs = self.repo.revs('sort(%ld, -topo)', subset) |
434 sortedrevs = repo.revs('sort(%ld, -topo)', subset) |
|
435 allowdivergence = self.ui.configbool( |
434 allowdivergence = self.ui.configbool( |
436 'experimental', 'evolution.allowdivergence') |
435 'experimental', 'evolution.allowdivergence') |
437 if not allowdivergence: |
436 if not allowdivergence: |
438 sortedrevs -= repo.revs( |
437 sortedrevs -= self.repo.revs( |
439 'descendants(%ld) and not %ld', |
438 'descendants(%ld) and not %ld', |
440 self.obsoletewithoutsuccessorindestination, |
439 self.obsoletewithoutsuccessorindestination, |
441 self.obsoletewithoutsuccessorindestination, |
440 self.obsoletewithoutsuccessorindestination, |
442 ) |
441 ) |
|
442 posholder = [pos] |
|
443 def progress(ctx): |
|
444 posholder[0] += 1 |
|
445 self.repo.ui.progress(_("rebasing"), posholder[0], |
|
446 ("%d:%s" % (ctx.rev(), ctx)), _('changesets'), |
|
447 total) |
443 for rev in sortedrevs: |
448 for rev in sortedrevs: |
444 dest = self.destmap[rev] |
449 self._rebasenode(tr, rev, allowdivergence, progress) |
445 ctx = repo[rev] |
450 return posholder[0] |
446 desc = _ctxdesc(ctx) |
451 |
447 if self.state[rev] == rev: |
452 def _rebasenode(self, tr, rev, allowdivergence, progressfn): |
448 ui.status(_('already rebased %s\n') % desc) |
453 repo, ui, opts = self.repo, self.ui, self.opts |
449 elif (not allowdivergence |
454 dest = self.destmap[rev] |
450 and rev in self.obsoletewithoutsuccessorindestination): |
455 ctx = repo[rev] |
451 msg = _('note: not rebasing %s and its descendants as ' |
456 desc = _ctxdesc(ctx) |
452 'this would cause divergence\n') % desc |
457 if self.state[rev] == rev: |
453 repo.ui.status(msg) |
458 ui.status(_('already rebased %s\n') % desc) |
454 self.skipped.add(rev) |
459 elif (not allowdivergence |
455 elif rev in self.obsoletenotrebased: |
460 and rev in self.obsoletewithoutsuccessorindestination): |
456 succ = self.obsoletenotrebased[rev] |
461 msg = _('note: not rebasing %s and its descendants as ' |
457 if succ is None: |
462 'this would cause divergence\n') % desc |
458 msg = _('note: not rebasing %s, it has no ' |
463 repo.ui.status(msg) |
459 'successor\n') % desc |
464 self.skipped.add(rev) |
|
465 elif rev in self.obsoletenotrebased: |
|
466 succ = self.obsoletenotrebased[rev] |
|
467 if succ is None: |
|
468 msg = _('note: not rebasing %s, it has no ' |
|
469 'successor\n') % desc |
|
470 else: |
|
471 succdesc = _ctxdesc(repo[succ]) |
|
472 msg = (_('note: not rebasing %s, already in ' |
|
473 'destination as %s\n') % (desc, succdesc)) |
|
474 repo.ui.status(msg) |
|
475 # Make clearrebased aware state[rev] is not a true successor |
|
476 self.skipped.add(rev) |
|
477 # Record rev as moved to its desired destination in self.state. |
|
478 # This helps bookmark and working parent movement. |
|
479 dest = max(adjustdest(repo, rev, self.destmap, self.state, |
|
480 self.skipped)) |
|
481 self.state[rev] = dest |
|
482 elif self.state[rev] == revtodo: |
|
483 ui.status(_('rebasing %s\n') % desc) |
|
484 progressfn(ctx) |
|
485 p1, p2, base = defineparents(repo, rev, self.destmap, |
|
486 self.state, self.skipped, |
|
487 self.obsoletenotrebased) |
|
488 self.storestatus(tr=tr) |
|
489 if len(repo[None].parents()) == 2: |
|
490 repo.ui.debug('resuming interrupted rebase\n') |
|
491 else: |
|
492 overrides = {('ui', 'forcemerge'): opts.get('tool', '')} |
|
493 with ui.configoverride(overrides, 'rebase'): |
|
494 stats = rebasenode(repo, rev, p1, base, self.collapsef, |
|
495 dest, wctx=self.wctx) |
|
496 if stats and stats[3] > 0: |
|
497 if self.wctx.isinmemory(): |
|
498 raise error.InMemoryMergeConflictsError() |
|
499 else: |
|
500 raise error.InterventionRequired( |
|
501 _('unresolved conflicts (see hg ' |
|
502 'resolve, then hg rebase --continue)')) |
|
503 if not self.collapsef: |
|
504 merging = p2 != nullrev |
|
505 editform = cmdutil.mergeeditform(merging, 'rebase') |
|
506 editor = cmdutil.getcommiteditor(editform=editform, |
|
507 **pycompat.strkwargs(opts)) |
|
508 if self.wctx.isinmemory(): |
|
509 newnode = concludememorynode(repo, rev, p1, p2, |
|
510 wctx=self.wctx, |
|
511 extrafn=_makeextrafn(self.extrafns), |
|
512 editor=editor, |
|
513 keepbranches=self.keepbranchesf, |
|
514 date=self.date) |
|
515 mergemod.mergestate.clean(repo) |
460 else: |
516 else: |
461 succdesc = _ctxdesc(repo[succ]) |
517 newnode = concludenode(repo, rev, p1, p2, |
462 msg = (_('note: not rebasing %s, already in ' |
518 extrafn=_makeextrafn(self.extrafns), |
463 'destination as %s\n') % (desc, succdesc)) |
519 editor=editor, |
464 repo.ui.status(msg) |
520 keepbranches=self.keepbranchesf, |
465 # Make clearrebased aware state[rev] is not a true successor |
521 date=self.date) |
466 self.skipped.add(rev) |
522 |
467 # Record rev as moved to its desired destination in self.state. |
523 if newnode is None: |
468 # This helps bookmark and working parent movement. |
524 # If it ended up being a no-op commit, then the normal |
469 dest = max(adjustdest(repo, rev, self.destmap, self.state, |
525 # merge state clean-up path doesn't happen, so do it |
470 self.skipped)) |
526 # here. Fix issue5494 |
471 self.state[rev] = dest |
527 mergemod.mergestate.clean(repo) |
472 elif self.state[rev] == revtodo: |
528 else: |
473 pos += 1 |
529 # Skip commit if we are collapsing |
474 ui.status(_('rebasing %s\n') % desc) |
530 if self.wctx.isinmemory(): |
475 ui.progress(_("rebasing"), pos, ("%d:%s" % (rev, ctx)), |
531 self.wctx.setbase(repo[p1]) |
476 _('changesets'), total) |
|
477 p1, p2, base = defineparents(repo, rev, self.destmap, |
|
478 self.state, self.skipped, |
|
479 self.obsoletenotrebased) |
|
480 self.storestatus(tr=tr) |
|
481 if len(repo[None].parents()) == 2: |
|
482 repo.ui.debug('resuming interrupted rebase\n') |
|
483 else: |
532 else: |
484 overrides = {('ui', 'forcemerge'): opts.get('tool', '')} |
533 repo.setparents(repo[p1].node()) |
485 with ui.configoverride(overrides, 'rebase'): |
534 newnode = None |
486 stats = rebasenode(repo, rev, p1, base, self.collapsef, |
535 # Update the state |
487 dest, wctx=self.wctx) |
536 if newnode is not None: |
488 if stats and stats[3] > 0: |
537 self.state[rev] = repo[newnode].rev() |
489 if self.wctx.isinmemory(): |
538 ui.debug('rebased as %s\n' % short(newnode)) |
490 raise error.InMemoryMergeConflictsError() |
539 else: |
491 else: |
|
492 raise error.InterventionRequired( |
|
493 _('unresolved conflicts (see hg ' |
|
494 'resolve, then hg rebase --continue)')) |
|
495 if not self.collapsef: |
540 if not self.collapsef: |
496 merging = p2 != nullrev |
541 ui.warn(_('note: rebase of %d:%s created no changes ' |
497 editform = cmdutil.mergeeditform(merging, 'rebase') |
542 'to commit\n') % (rev, ctx)) |
498 editor = cmdutil.getcommiteditor(editform=editform, |
543 self.skipped.add(rev) |
499 **pycompat.strkwargs(opts)) |
544 self.state[rev] = p1 |
500 if self.wctx.isinmemory(): |
545 ui.debug('next revision set to %d\n' % p1) |
501 newnode = concludememorynode(repo, rev, p1, p2, |
546 else: |
502 wctx=self.wctx, |
547 ui.status(_('already rebased %s as %s\n') % |
503 extrafn=_makeextrafn(self.extrafns), |
548 (desc, repo[self.state[rev]])) |
504 editor=editor, |
|
505 keepbranches=self.keepbranchesf, |
|
506 date=self.date) |
|
507 mergemod.mergestate.clean(repo) |
|
508 else: |
|
509 newnode = concludenode(repo, rev, p1, p2, |
|
510 extrafn=_makeextrafn(self.extrafns), |
|
511 editor=editor, |
|
512 keepbranches=self.keepbranchesf, |
|
513 date=self.date) |
|
514 |
|
515 if newnode is None: |
|
516 # If it ended up being a no-op commit, then the normal |
|
517 # merge state clean-up path doesn't happen, so do it |
|
518 # here. Fix issue5494 |
|
519 mergemod.mergestate.clean(repo) |
|
520 else: |
|
521 # Skip commit if we are collapsing |
|
522 if self.wctx.isinmemory(): |
|
523 self.wctx.setbase(repo[p1]) |
|
524 else: |
|
525 repo.setparents(repo[p1].node()) |
|
526 newnode = None |
|
527 # Update the state |
|
528 if newnode is not None: |
|
529 self.state[rev] = repo[newnode].rev() |
|
530 ui.debug('rebased as %s\n' % short(newnode)) |
|
531 else: |
|
532 if not self.collapsef: |
|
533 ui.warn(_('note: rebase of %d:%s created no changes ' |
|
534 'to commit\n') % (rev, ctx)) |
|
535 self.skipped.add(rev) |
|
536 self.state[rev] = p1 |
|
537 ui.debug('next revision set to %d\n' % p1) |
|
538 else: |
|
539 ui.status(_('already rebased %s as %s\n') % |
|
540 (desc, repo[self.state[rev]])) |
|
541 return pos |
|
542 |
549 |
543 def _finishrebase(self): |
550 def _finishrebase(self): |
544 repo, ui, opts = self.repo, self.ui, self.opts |
551 repo, ui, opts = self.repo, self.ui, self.opts |
545 fm = ui.formatter('rebase', opts) |
552 fm = ui.formatter('rebase', opts) |
546 fm.startitem() |
553 fm.startitem() |