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.
--- 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