diff 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
line wrap: on
line diff
--- a/hgext/rebase.py	Fri Mar 19 10:34:16 2021 -0700
+++ b/hgext/rebase.py	Fri Mar 19 22:52:59 2021 -0700
@@ -361,6 +361,19 @@
         skippedset = set(self.obsolete_with_successor_in_destination)
         skippedset.update(self.obsolete_with_successor_in_rebase_set)
         _checkobsrebase(self.repo, self.ui, obsoleteset, skippedset)
+        allowdivergence = self.ui.configbool(
+            b'experimental', b'evolution.allowdivergence'
+        )
+        if allowdivergence:
+            self.obsolete_with_successor_in_rebase_set = set()
+        else:
+            for rev in self.repo.revs(
+                b'descendants(%ld) and not %ld',
+                self.obsolete_with_successor_in_rebase_set,
+                self.obsolete_with_successor_in_rebase_set,
+            ):
+                self.state.pop(rev, None)
+                self.destmap.pop(rev, None)
 
     def _prepareabortorcontinue(
         self, isabort, backup=True, suppwarns=False, dryrun=False, confirm=False
@@ -493,19 +506,10 @@
         def progress(ctx):
             p.increment(item=(b"%d:%s" % (ctx.rev(), ctx)))
 
-        allowdivergence = self.ui.configbool(
-            b'experimental', b'evolution.allowdivergence'
-        )
         for subset in sortsource(self.destmap):
             sortedrevs = self.repo.revs(b'sort(%ld, -topo)', subset)
-            if not allowdivergence:
-                sortedrevs -= self.repo.revs(
-                    b'descendants(%ld) and not %ld',
-                    self.obsolete_with_successor_in_rebase_set,
-                    self.obsolete_with_successor_in_rebase_set,
-                )
             for rev in sortedrevs:
-                self._rebasenode(tr, rev, allowdivergence, progress)
+                self._rebasenode(tr, rev, progress)
         p.complete()
         ui.note(_(b'rebase merging completed\n'))
 
@@ -567,16 +571,13 @@
 
             return newnode
 
-    def _rebasenode(self, tr, rev, allowdivergence, progressfn):
+    def _rebasenode(self, tr, rev, progressfn):
         repo, ui, opts = self.repo, self.ui, self.opts
         ctx = repo[rev]
         desc = _ctxdesc(ctx)
         if self.state[rev] == rev:
             ui.status(_(b'already rebased %s\n') % desc)
-        elif (
-            not allowdivergence
-            and rev in self.obsolete_with_successor_in_rebase_set
-        ):
+        elif rev in self.obsolete_with_successor_in_rebase_set:
             msg = (
                 _(
                     b'note: not rebasing %s and its descendants as '