Patchwork [3,of,3] rebase: do not consider extincts for divergence detection (issue5782)

login
register
mail settings
Submitter Denis Laxalde
Date Feb. 10, 2018, 9:28 a.m.
Message ID <efb6929261e3fc640941.1518254888@marimba>
Download mbox | patch
Permalink /patch/27518/
State Accepted
Headers show

Comments

Denis Laxalde - Feb. 10, 2018, 9:28 a.m.
# HG changeset patch
# User Denis Laxalde <denis@laxalde.org>
# Date 1518212960 -3600
#      Fri Feb 09 22:49:20 2018 +0100
# Node ID efb6929261e3fc640941c1b8fc9b0e378722d379
# Parent  864f2bc67aa90f1ae762206925906950b6258c2f
# EXP-Topic issue5782
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.
Yuya Nishihara - Feb. 10, 2018, 12:10 p.m.
On Sat, 10 Feb 2018 10:28:08 +0100, Denis Laxalde wrote:
> # HG changeset patch
> # User Denis Laxalde <denis@laxalde.org>
> # Date 1518212960 -3600
> #      Fri Feb 09 22:49:20 2018 +0100
> # Node ID efb6929261e3fc640941c1b8fc9b0e378722d379
> # Parent  864f2bc67aa90f1ae762206925906950b6258c2f
> # EXP-Topic issue5782
> rebase: do not consider extincts for divergence detection (issue5782)

Looks good. Queued, thanks.

>      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 @@ def _computeobsoletenotrebased(repo, reb
>          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:

Perhaps it's better to keep successors a set. Can you send a followup?

Patch

diff --git a/hgext/rebase.py b/hgext/rebase.py
--- a/hgext/rebase.py
+++ b/hgext/rebase.py
@@ -312,10 +312,13 @@  class rebaseruntime(object):
         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 @@  def _checkobsrebase(repo, ui, rebaseobsr
 
     `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 @@  def _computeobsoletenotrebased(repo, reb
 
     `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 @@  def _computeobsoletenotrebased(repo, reb
         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 @@  def _computeobsoletenotrebased(repo, reb
                 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'):
diff --git a/tests/test-rebase-obsolete.t b/tests/test-rebase-obsolete.t
--- a/tests/test-rebase-obsolete.t
+++ b/tests/test-rebase-obsolete.t
@@ -1244,10 +1244,6 @@  issue5782
   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