[PATCH 2 of 2] histedit: make histedit aware of obsoletions not stored in state (issue4800)

Kostia Balytskyi ikostia at fb.com
Tue Feb 16 16:29:26 EST 2016


# HG changeset patch
# User Kostia Balytskyi <ikostia at fb.com>
# Date 1455658079 0
#      Tue Feb 16 21:27:59 2016 +0000
# Node ID c4c7a4ca3132fac82a7e6f3c74a3ff247a309cc6
# Parent  34ffbe866b265b837c8a592f95293a53fa310dce
histedit: make histedit aware of obsoletions not stored in state (issue4800)

Before this change, when histedit exited to interactive session (during edit
command for example), user could introduce obsoletion changes that would not
be known to histedit. For example, user could've amended one of the commits
(introducing an obsoletion change). The fact of this amendment would not be
stored in histedit's state file and later, when histedit would try to process
all the replacements that happened, one of the final successors (in its opinion)
would turn out to be hidden. This behavior is described in issue4800. This
commit fixes it.

diff --git a/hgext/histedit.py b/hgext/histedit.py
--- a/hgext/histedit.py
+++ b/hgext/histedit.py
@@ -1386,6 +1386,31 @@
                 hint=_('use "drop %s" to discard, see also: '
                        '"hg help -e histedit.config"') % missing[0][:12])
 
+def adjustreplacementsfrommarkers(repo, allsuccs, replaced, fullmapping):
+    """Adjusts `replaced`, `allsuccs` and `fullmapping` structures
+    with data from obsoletion markers
+
+    These structures are originally generated only based on
+    histedit state and do not account for changes that are
+    not recorded there. This function fixes that"""
+    if not obsolete.isenabled(repo, obsolete.createmarkersopt):
+        return
+
+    cache = {}
+    originalsuccs = set(allsuccs)
+    for n in originalsuccs:
+        finals = set()
+        finals.update(*obsolete.successorssets(repo, n, cache=cache))
+        if len(finals) == 1 and n in finals:
+            continue
+
+        allnsuccs = set(obsolete.allsuccessors(repo.obsstore, [n]))
+        allsuccs.update(allnsuccs)
+        replaced.update(allnsuccs - finals)
+        fullmapping.setdefault(n, set()).update(finals)
+        if n in fullmapping[n]:
+            fullmapping[n].remove(n)
+
 def processreplacement(state):
     """process the list of replacements to return
 
@@ -1402,6 +1427,7 @@
         allsuccs.update(rep[1])
         replaced.add(rep[0])
         fullmapping.setdefault(rep[0], set()).update(rep[1])
+    adjustreplacementsfrommarkers(state.repo, allsuccs, replaced, fullmapping)
     new = allsuccs - replaced
     tmpnodes = allsuccs & replaced
     # Reduce content fullmapping into direct relation between original nodes
diff --git a/tests/test-histedit-obsolete.t b/tests/test-histedit-obsolete.t
--- a/tests/test-histedit-obsolete.t
+++ b/tests/test-histedit-obsolete.t
@@ -14,6 +14,36 @@
   > rebase=
   > EOF
 
+Test that histedit learns about obsoletions not stored in histedit state
+  $ hg init boo
+  $ cd boo
+  $ echo a > a
+  $ hg ci -Am a
+  adding a
+  $ echo a > b
+  $ echo a > c
+  $ echo a > c
+  $ hg ci -Am b
+  adding b
+  adding c
+  $ echo a > d
+  $ hg ci -Am c
+  adding d
+  $ echo "pick `hg log -r 0 -T '{node|short}'`" > plan
+  $ echo "pick `hg log -r 2 -T '{node|short}'`" >> plan
+  $ echo "edit `hg log -r 1 -T '{node|short}'`" >> plan
+  $ hg histedit -r 'all()' --commands plan
+  Editing (1b2d564fad96), you may commit or record as needed now.
+  (hg histedit --continue to resume)
+  [1]
+  $ hg st
+  A b
+  A c
+  ? plan
+  $ hg commit --amend b
+  $ hg histedit --continue
+  $ cd ..
+
   $ hg init base
   $ cd base
 


More information about the Mercurial-devel mailing list