comparison hgext/rebase.py @ 46834:535de0e34a79

rebase: filter out descendants of divergence-causing commits earlier `hg rebase` treats obsolete commits differently depending what has happened to the commit: 1) Obsolete commit without non-obsolete successors: Skipped, and a note is printed ("it has no successor"). 2) Obsolete commit with a successor in the destination (ancestor of it): Skipped, and a note is printed ("already in destination"). 3) Obsolete commit with a successor in the rebase set: The commit and its descendants are skipped, and a note is printed ("not rebasing <commit> and its descendants as this would cause divergence"), unless `allowdivergence` config set. 4) Obsolete commit with a successor elsewhere: Error ("this rebase will cause divergences"), unless `allowdivergence` config set. Before this patch, we did all those checks up front, except for (3), which was checked later. The later check consisted of two parts: 1) filtering out of descendants, and 2) conditionally printing message if the `allowdivergence` config was not set. This patch makes it so we do the filtering early. A consequence of filtering out divergence-causing commits earlier is that we rebase commits in slightly different order, which has some impact on tests. Differential Revision: https://phab.mercurial-scm.org/D10249
author Martin von Zweigbergk <martinvonz@google.com>
date Fri, 19 Mar 2021 22:52:59 -0700
parents 47c251a14525
children c2438f2f635c
comparison
equal deleted inserted replaced
46833:47c251a14525 46834:535de0e34a79
359 self.obsolete_with_successor_in_rebase_set, 359 self.obsolete_with_successor_in_rebase_set,
360 ) = _compute_obsolete_sets(self.repo, obsoleteset, self.destmap) 360 ) = _compute_obsolete_sets(self.repo, obsoleteset, self.destmap)
361 skippedset = set(self.obsolete_with_successor_in_destination) 361 skippedset = set(self.obsolete_with_successor_in_destination)
362 skippedset.update(self.obsolete_with_successor_in_rebase_set) 362 skippedset.update(self.obsolete_with_successor_in_rebase_set)
363 _checkobsrebase(self.repo, self.ui, obsoleteset, skippedset) 363 _checkobsrebase(self.repo, self.ui, obsoleteset, skippedset)
364 allowdivergence = self.ui.configbool(
365 b'experimental', b'evolution.allowdivergence'
366 )
367 if allowdivergence:
368 self.obsolete_with_successor_in_rebase_set = set()
369 else:
370 for rev in self.repo.revs(
371 b'descendants(%ld) and not %ld',
372 self.obsolete_with_successor_in_rebase_set,
373 self.obsolete_with_successor_in_rebase_set,
374 ):
375 self.state.pop(rev, None)
376 self.destmap.pop(rev, None)
364 377
365 def _prepareabortorcontinue( 378 def _prepareabortorcontinue(
366 self, isabort, backup=True, suppwarns=False, dryrun=False, confirm=False 379 self, isabort, backup=True, suppwarns=False, dryrun=False, confirm=False
367 ): 380 ):
368 self.resume = True 381 self.resume = True
491 ) 504 )
492 505
493 def progress(ctx): 506 def progress(ctx):
494 p.increment(item=(b"%d:%s" % (ctx.rev(), ctx))) 507 p.increment(item=(b"%d:%s" % (ctx.rev(), ctx)))
495 508
496 allowdivergence = self.ui.configbool(
497 b'experimental', b'evolution.allowdivergence'
498 )
499 for subset in sortsource(self.destmap): 509 for subset in sortsource(self.destmap):
500 sortedrevs = self.repo.revs(b'sort(%ld, -topo)', subset) 510 sortedrevs = self.repo.revs(b'sort(%ld, -topo)', subset)
501 if not allowdivergence:
502 sortedrevs -= self.repo.revs(
503 b'descendants(%ld) and not %ld',
504 self.obsolete_with_successor_in_rebase_set,
505 self.obsolete_with_successor_in_rebase_set,
506 )
507 for rev in sortedrevs: 511 for rev in sortedrevs:
508 self._rebasenode(tr, rev, allowdivergence, progress) 512 self._rebasenode(tr, rev, progress)
509 p.complete() 513 p.complete()
510 ui.note(_(b'rebase merging completed\n')) 514 ui.note(_(b'rebase merging completed\n'))
511 515
512 def _concludenode(self, rev, editor, commitmsg=None): 516 def _concludenode(self, rev, editor, commitmsg=None):
513 """Commit the wd changes with parents p1 and p2. 517 """Commit the wd changes with parents p1 and p2.
565 date=date, 569 date=date,
566 ) 570 )
567 571
568 return newnode 572 return newnode
569 573
570 def _rebasenode(self, tr, rev, allowdivergence, progressfn): 574 def _rebasenode(self, tr, rev, progressfn):
571 repo, ui, opts = self.repo, self.ui, self.opts 575 repo, ui, opts = self.repo, self.ui, self.opts
572 ctx = repo[rev] 576 ctx = repo[rev]
573 desc = _ctxdesc(ctx) 577 desc = _ctxdesc(ctx)
574 if self.state[rev] == rev: 578 if self.state[rev] == rev:
575 ui.status(_(b'already rebased %s\n') % desc) 579 ui.status(_(b'already rebased %s\n') % desc)
576 elif ( 580 elif rev in self.obsolete_with_successor_in_rebase_set:
577 not allowdivergence
578 and rev in self.obsolete_with_successor_in_rebase_set
579 ):
580 msg = ( 581 msg = (
581 _( 582 _(
582 b'note: not rebasing %s and its descendants as ' 583 b'note: not rebasing %s and its descendants as '
583 b'this would cause divergence\n' 584 b'this would cause divergence\n'
584 ) 585 )