changeset 35995:b7e2cf114e85

rebase: do not consider extincts for divergence detection (issue5782) Extinct obsolete changesets cannot cause divergence upon rebase. We compute these obsoletes without a non-obsolete successor (extincts) in _computeobsoletenotrebased() and then filter them out from the set of obsolete revisions to rebase before getting into _checkobsrebase() to check for divergence candidates.
author Denis Laxalde <denis@laxalde.org>
date Fri, 09 Feb 2018 22:49:20 +0100
parents ae0d25071fca
children de0666564bde
files hgext/rebase.py tests/test-rebase-obsolete.t
diffstat 2 files changed, 19 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/hgext/rebase.py	Fri Feb 09 21:45:16 2018 +0100
+++ b/hgext/rebase.py	Fri Feb 09 22:49:20 2018 +0100
@@ -312,10 +312,13 @@
         if not self.ui.configbool('experimental', 'rebaseskipobsolete'):
             return
         obsoleteset = set(obsoleterevs)
-        self.obsoletenotrebased, self.obsoletewithoutsuccessorindestination = \
-            _computeobsoletenotrebased(self.repo, obsoleteset, destmap)
+        (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(self, isabort):
@@ -1221,7 +1224,7 @@
 
     `rebaseobsrevs`: set of obsolete revision in source
     `rebaseobsskipped`: set of revisions from source skipped because they have
-    successors in destination
+    successors in destination or no non-obsolete successor.
     """
     # Obsolete node with successors not in dest leads to divergence
     divergenceok = ui.configbool('experimental',
@@ -1786,13 +1789,18 @@
 
     `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
     nodemap = cl.nodemap
+    extinctnodes = set(cl.node(r) for r in repo.revs('extinct()'))
     for srcrev in rebaseobsrevs:
         srcnode = cl.node(srcrev)
         destnode = cl.node(destmap[srcrev])
@@ -1800,6 +1808,9 @@
         successors = list(obsutil.allsuccessors(repo.obsstore, [srcnode]))
         # obsutil.allsuccessors includes node itself
         successors.remove(srcnode)
+        if set(successors).issubset(extinctnodes):
+            # all successors are extinct
+            obsoleteextinctsuccessors.add(srcrev)
         if not successors:
             # no successor
             obsoletenotrebased[srcrev] = None
@@ -1817,7 +1828,11 @@
                 if any(nodemap[s] in destmap for s in successors):
                     obsoletewithoutsuccessorindestination.add(srcrev)
 
-    return obsoletenotrebased, obsoletewithoutsuccessorindestination
+    return (
+        obsoletenotrebased,
+        obsoletewithoutsuccessorindestination,
+        obsoleteextinctsuccessors,
+    )
 
 def summaryhook(ui, repo):
     if not repo.vfs.exists('rebasestate'):
--- a/tests/test-rebase-obsolete.t	Fri Feb 09 21:45:16 2018 +0100
+++ b/tests/test-rebase-obsolete.t	Fri Feb 09 22:49:20 2018 +0100
@@ -1244,10 +1244,6 @@
   o  0:b173517d0057 a
   
   $ hg rebase -d 0 -r 2
-  abort: this rebase will cause divergences from: a82ac2b38757
-  (to force the rebase please set experimental.evolution.allowdivergence=True)
-  [255]
-  $ hg rebase -d 0 -r 2 --config experimental.evolution.allowdivergence=True
   rebasing 2:a82ac2b38757 "c" (c)
   $ hg log -G -r 'a': --hidden
   o  5:69ad416a4a26 c