rebase: skip obsolete commits even if they have pruned successors
authorMartin von Zweigbergk <martinvonz@google.com>
Fri, 19 Mar 2021 12:08:46 -0700
changeset 46801 32399d0813e0
parent 46800 186c0f6fbc16
child 46803 13d973690ecd
rebase: skip obsolete commits even if they have pruned successors Issue 5782 reported that `hg rebase -r <obsolete commit with pruned successor>` failed with an error saying that it would cause divergence. Commit b7e2cf114e85 (rebase: do not consider extincts for divergence detection (issue5782), 2018-02-09) fixed it by letting you rebase the commit. However, that fix seems inconsistent with how we handle `hg rebase -r <pruned commit>`. To me, it should make no difference whether a commit is pruned itself or if it has (only) pruned successors. This patch changes it so we treat these two kinds of commits the same way. I let the message we print remain "note: not rebasing <commit>, it has no successor" even though that last part is not technically correct for commits with pruned successors. I doubt it will confuse users. Differential Revision: https://phab.mercurial-scm.org/D10240
hgext/rebase.py
tests/test-rebase-obsolete.t
--- a/hgext/rebase.py	Sat Mar 20 00:37:57 2021 +0100
+++ b/hgext/rebase.py	Fri Mar 19 12:08:46 2021 -0700
@@ -361,11 +361,9 @@
         (
             self.obsoletenotrebased,
             self.obsoletewithoutsuccessorindestination,
-            obsoleteextinctsuccessors,
         ) = _computeobsoletenotrebased(self.repo, obsoleteset, destmap)
         skippedset = set(self.obsoletenotrebased)
         skippedset.update(self.obsoletewithoutsuccessorindestination)
-        skippedset.update(obsoleteextinctsuccessors)
         _checkobsrebase(self.repo, self.ui, obsoleteset, skippedset)
 
     def _prepareabortorcontinue(
@@ -2192,13 +2190,9 @@
 
     `obsoletewithoutsuccessorindestination` is a set with obsolete revisions
     without a successor in destination.
-
-    `obsoleteextinctsuccessors` is a set of obsolete revisions with only
-    obsolete successors.
     """
     obsoletenotrebased = {}
     obsoletewithoutsuccessorindestination = set()
-    obsoleteextinctsuccessors = set()
 
     assert repo.filtername is None
     cl = repo.changelog
@@ -2212,11 +2206,8 @@
         successors.remove(srcnode)
         succrevs = {get_rev(s) for s in successors}
         succrevs.discard(None)
-        if succrevs.issubset(extinctrevs):
-            # all successors are extinct
-            obsoleteextinctsuccessors.add(srcrev)
-        if not successors:
-            # no successor
+        if not successors or succrevs.issubset(extinctrevs):
+            # no successor, or all successors are extinct
             obsoletenotrebased[srcrev] = None
         else:
             dstrev = destmap[srcrev]
@@ -2231,11 +2222,7 @@
                 if srcrev in extinctrevs or any(s in destmap for s in succrevs):
                     obsoletewithoutsuccessorindestination.add(srcrev)
 
-    return (
-        obsoletenotrebased,
-        obsoletewithoutsuccessorindestination,
-        obsoleteextinctsuccessors,
-    )
+    return obsoletenotrebased, obsoletewithoutsuccessorindestination
 
 
 def abortrebase(ui, repo):
--- a/tests/test-rebase-obsolete.t	Sat Mar 20 00:37:57 2021 +0100
+++ b/tests/test-rebase-obsolete.t	Fri Mar 19 12:08:46 2021 -0700
@@ -1294,18 +1294,16 @@
   o  0:b173517d0057 a
   
   $ hg rebase -d 0 -r 2
-  rebasing 2:a82ac2b38757 c "c"
+  note: not rebasing 2:a82ac2b38757 c "c", it has no successor
   $ hg log -G -r 'a': --hidden
-  o  5:69ad416a4a26 c
+  *  4:76be324c128b d
   |
-  | *  4:76be324c128b d
+  | x  3:ef8a456de8fa c1 (pruned)
   | |
-  | | x  3:ef8a456de8fa c1 (pruned)
-  | | |
-  | x |  2:a82ac2b38757 c (rewritten using replace as 3:ef8a456de8fa rewritten using rebase as 5:69ad416a4a26)
-  | |/
-  | o  1:488e1b7e7341 b
+  x |  2:a82ac2b38757 c (rewritten using replace as 3:ef8a456de8fa)
   |/
+  o  1:488e1b7e7341 b
+  |
   o  0:b173517d0057 a
   
   $ cd ..