obsolete: do no complain when push create a new head but obsolete an old one.
Do not read the code or your eyes will burn.
The (+1 heads) message still appear (see mercurial issue 3394).
--- a/hgext/obsolete.py Tue Apr 24 16:30:58 2012 +0200
+++ b/hgext/obsolete.py Thu Apr 26 16:49:15 2012 +0200
@@ -305,7 +305,12 @@
return outgoing
def wrapcheckheads(orig, repo, remote, outgoing, *args, **kwargs):
- """wrap mercurial.discovery.checkheads to prevent unstability to be pushed"""
+ """wrap mercurial.discovery.checkheads
+
+ * prevent unstability to be pushed
+ * patch remote to ignore obsolete heads on remote
+ """
+ # do not push instability
for h in outgoing.missingheads:
# checking heads only is enought because any thing base on obsolete
# changeset is either obsolete or unstable.
@@ -317,7 +322,58 @@
if ctx.obsolete():
raise util.Abort(_("Trying to push obsolete changeset: %s!") % ctx,
hint=hint)
- return orig(repo, remote, outgoing, *args, **kwargs)
+ ### patch remote branch map
+ # do not read it this burn eyes
+ try:
+ if 'oldbranchmap' not in vars(remote):
+ remote.oldbranchmap = remote.branchmap
+ def branchmap():
+ newbm = {}
+ oldbm = None
+ if (util.safehasattr(phases, 'visiblebranchmap')
+ and not util.safehasattr(remote, 'ignorevisiblebranchmap')
+ ):
+ remote.ignorevisiblebranchmap = False
+ remote.branchmap = remote.oldbranchmap
+ oldbm = phases.visiblebranchmap(remote)
+ remote.branchmap = remote.newbranchmap
+ remote.ignorevisiblebranchmap = True
+ if oldbm is None:
+ oldbm = remote.oldbranchmap()
+ for branch, nodes in oldbm.iteritems():
+ nodes = list(nodes)
+ new = set()
+ while nodes:
+ n = nodes.pop()
+ if n in repo._obsobjrels:
+ newernodes = repo._obsobjrels[n]
+ for newernode in newernodes:
+ if newernode is not None:
+ nodes.append(newernode)
+ else:
+ new.add(n)
+ if new:
+ newbm[branch] = list(new)
+ return newbm
+ remote.ignorevisiblebranchmap = True
+ remote.branchmap = branchmap
+ remote.newbranchmap = branchmap
+ return orig(repo, remote, outgoing, *args, **kwargs)
+ finally:
+ remote.__dict__.pop('branchmap', None) # restore class one
+ remote.__dict__.pop('oldbranchmap', None)
+ remote.__dict__.pop('newbranchmap', None)
+ remote.__dict__.pop('ignorevisiblebranchmap', None)
+
+# eye are still burning
+def wrapvisiblebranchmap(orig, repo):
+ ignore = getattr(repo, 'ignorevisiblebranchmap', None)
+ if ignore is None:
+ return orig(repo)
+ elif ignore:
+ return repo.branchmap()
+ else:
+ return None # break recursion
### New commands
@@ -349,6 +405,8 @@
extensions.wrapcommand(commands.table, "pull", wrapmayobsoletewc)
extensions.wrapfunction(discovery, 'findcommonoutgoing', wrapfindcommonoutgoing)
extensions.wrapfunction(discovery, 'checkheads', wrapcheckheads)
+ if util.safehasattr(phases, 'visiblebranchmap'):
+ extensions.wrapfunction(phases, 'visiblebranchmap', wrapvisiblebranchmap)
### serialisation
#############################
--- a/tests/test-obsolete.t Tue Apr 24 16:30:58 2012 +0200
+++ b/tests/test-obsolete.t Thu Apr 26 16:49:15 2012 +0200
@@ -433,3 +433,24 @@
o 0 - 1f0dee641bb7
+Does not complain about new head if you obsolete the old one
+
+ $ hg push ../other-new --traceback
+ pushing to ../other-new
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 1 changes to 1 files
+ 83b5778897ad try to obsolete immutable changeset 1f0dee641bb7
+ $ hg up -q 10
+ $ mkcommit "obsol_d'''"
+ created new head
+ $ hg debugobsolete 12 11
+ $ hg push ../other-new --traceback
+ pushing to ../other-new
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)