Patchwork [v2] histedit: handle obsolete commits unknown to histedit state

login
register
mail settings
Submitter Kostia Balytskyi
Date Jan. 17, 2016, 5:04 p.m.
Message ID <ce177c38c9199fc85be2.1453050246@ikostia-mbp>
Download mbox | patch
Permalink /patch/12808/
State Superseded
Delegated to: Pierre-Yves David
Headers show

Comments

Kostia Balytskyi - Jan. 17, 2016, 5:04 p.m.
# HG changeset patch
# User Kostia Balytskyi <ikostia@fb.com>
# Date 1453047321 0
#      Sun Jan 17 16:15:21 2016 +0000
# Node ID ce177c38c9199fc85be2db8fd194e97f839d9d90
# Parent  443848eece189002c542339dc1cf84f49a94c824
histedit: handle obsolete commits unknown to histedit state

This fix is intended to solve issue4800. It takes sets of
final and new commits from histedit's state and replaces
them with their successor sets.

Patch

diff --git a/hgext/histedit.py b/hgext/histedit.py
--- a/hgext/histedit.py
+++ b/hgext/histedit.py
@@ -1362,6 +1362,27 @@ 
     tmpnodes = allsuccs & replaced
     return newnodes, tmpnodes
 
+def nonobsoletesuccessors(repo, nodes):
+    """find all non-obsolete successors for each of the nodes
+
+    This fails if any of the nodes has more than one successor
+    set, e.g. if it diverged at some point and then became obsolete.
+    """
+    result = []
+    for cl in nodes:
+        succset = obsolete.successorssets(repo, cl)
+        if len(succset) > 1:
+            # successorsset for diverged changeset
+            # weird situation that should not happen while
+            # editing history, indicates an error
+            msg = _("diverged obsolete changeset found "
+                    "among nodes in histedit: %s")
+            raise error.Abort(msg % node.hex(cl))
+        elif len(succset) == 1:
+            # non-divergent successor set
+            result += succset[0]
+        # else: changeset has been pruned, nothing needs to be done
+    return result
 
 def processreplacement(state):
     """process the list of replacements to return
@@ -1408,11 +1429,13 @@ 
     # turn `final` into list (topologically sorted)
     nm = state.repo.changelog.nodemap
     for prec, succs in final.items():
+        succs = nonobsoletesuccessors(state.repo, succs)
         final[prec] = sorted(succs, key=nm.get)
 
+    nonobsoletenew = nonobsoletesuccessors(state.repo, new)
     # computed topmost element (necessary for bookmark)
-    if new:
-        newtopmost = sorted(new, key=state.repo.changelog.rev)[-1]
+    if nonobsoletenew:
+        newtopmost = sorted(nonobsoletenew, key=state.repo.changelog.rev)[-1]
     elif not final:
         # Nothing rewritten at all. we won't need `newtopmost`
         # It is the same as `oldtopmost` and `processreplacement` know it
@@ -1422,7 +1445,7 @@ 
         r = state.repo.changelog.rev
         newtopmost = state.repo[sorted(final, key=r)[0]].p1().node()
 
-    return final, tmpnodes, new, newtopmost
+    return final, tmpnodes, nonobsoletenew, newtopmost
 
 def movebookmarks(ui, repo, mapping, oldtopmost, newtopmost):
     """Move bookmark from old to newly created node"""