changeset 298:f597421662f7

obsolete: unify collapsed revisions markers handling When collapsing A, B and C into D, amend was registering: A -> D B -> D A -> B C -> D A -> C while the rebase wrapper was doing: A -> D B -> D C -> D At this point, I have no argument to favor one or another or even a new one like: A -> B B -> C C -> D so I am aligning the rebase implementation on the older amend one. At least we can now change them all at once.
author Patrick Mezard <patrick@mezard.eu>
date Thu, 21 Jun 2012 19:58:57 +0200
parents 590ac023c536
children eda6491ca269
files hgext/evolve.py hgext/obsolete.py tests/test-obsolete-rebase.t
diffstat 3 files changed, 32 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- a/hgext/evolve.py	Thu Jun 21 19:24:19 2012 +0200
+++ b/hgext/evolve.py	Thu Jun 21 19:58:57 2012 +0200
@@ -142,10 +142,8 @@
                 bookmarks.write(repo)
 
             # add evolution metadata
-            repo.addobsolete(new.node(), old.node())
-            for u in updates:
-                repo.addobsolete(u.node(), old.node())
-                repo.addobsolete(new.node(), u.node())
+            collapsed = set([u.node() for u in updates] + [old.node()])
+            repo.addcollapsedobsolete(collapsed, new.node())
             oldbookmarks = repo.nodebookmarks(old.node())
             for book in oldbookmarks:
                 repo._bookmarks[book] = new.node()
--- a/hgext/obsolete.py	Thu Jun 21 19:24:19 2012 +0200
+++ b/hgext/obsolete.py	Thu Jun 21 19:58:57 2012 +0200
@@ -267,27 +267,34 @@
         repo._rebasestate = dict(p for p in repo._rebasestate.iteritems()
                                  if p[1] >= 0)
         if not res and not kwargs.get('abort') and repo._rebasestate:
-            # We have to tell rewritten revisions from removed
-            # ones. When collapsing, removed revisions are considered
-            # to be collapsed onto the final one, while in the normal
-            # case their are marked obsolete without successor.
-            emptynode = nullid
-            if kwargs.get('collapse'):
-                emptynode = repo[max(repo._rebasestate.values())].node()
             # Rebased revisions are assumed to be descendants of
             # targetrev. If a source revision is mapped to targetrev
             # or to another rebased revision, it must have been
             # removed.
             targetrev = repo[repo._rebasetarget].rev()
             newrevs = set([targetrev])
+            replacements = {}
             for rev, newrev in sorted(repo._rebasestate.items()):
                 oldnode = repo[rev].node()
                 if newrev not in newrevs:
                     newnode = repo[newrev].node()
                     newrevs.add(newrev)
                 else:
-                    newnode = emptynode
-                repo.addobsolete(newnode, oldnode)
+                    newnode = nullid
+                replacements[oldnode] = newnode
+
+            if kwargs.get('collapse'):
+                newnodes = set(n for n in replacements.values() if n != nullid)
+                if newnodes:
+                    # Collapsing into more than one revision?
+                    assert len(newnodes) == 1, newnodes
+                    newnode = newnodes.pop()
+                else:
+                    newnode = nullid
+                repo.addcollapsedobsolete(replacements, newnode)
+            else:
+                for oldnode, newnode in replacements.iteritems():
+                    repo.addobsolete(newnode, oldnode)
         return res
     finally:
         delattr(repo, '_rebasestate')
@@ -813,6 +820,17 @@
             finally:
                 lock.release()
 
+        def addcollapsedobsolete(self, oldnodes, newnode):
+            """Mark oldnodes as collapsed into newnode."""
+            # Assume oldnodes are all descendants of a single rev
+            rootrevs = self.revs('roots(%ln)', oldnodes)
+            assert len(rootrevs) == 1, rootrevs
+            rootnode = self[rootrevs[0]].node()
+            for n in oldnodes:
+                if n != rootnode:
+                    self.addobsolete(n, rootnode)
+                self.addobsolete(newnode, n)
+
         def _turn_extinct_secret(self):
             """ensure all extinct changeset are secret"""
             self._clearobsoletecache()
--- a/tests/test-obsolete-rebase.t	Thu Jun 21 19:24:19 2012 +0200
+++ b/tests/test-obsolete-rebase.t	Thu Jun 21 19:58:57 2012 +0200
@@ -109,6 +109,7 @@
   
   $ hg debugsuccessors
   03f31481307a a7773ffa7edc
+  076e9b2ffbe1 03f31481307a
   076e9b2ffbe1 a7773ffa7edc
   4e322f7ce8e3 000000000000
   98e4a024635e 9c5494949763
@@ -176,8 +177,9 @@
   $ diff -u ../successors.old ../successors.new
   --- ../successors.old* (glob)
   +++ ../successors.new* (glob)
-  @@ -1,4 +1,6 @@
+  @@ -1,5 +1,7 @@
    03f31481307a a7773ffa7edc
+   076e9b2ffbe1 03f31481307a
    076e9b2ffbe1 a7773ffa7edc
   +4b9d80f48523 1951ead97108
    4e322f7ce8e3 000000000000