hgext/obsolete.py
changeset 298 f597421662f7
parent 297 590ac023c536
child 299 eda6491ca269
--- 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()