diff --git a/mercurial/exchange.py b/mercurial/exchange.py
index ef880ced6d07f0ec9009efef7fb403ed1263de8d_bWVyY3VyaWFsL2V4Y2hhbmdlLnB5..7d0bbb6dd73006d423c061fc4147e16135189e97_bWVyY3VyaWFsL2V4Y2hhbmdlLnB5 100644
--- a/mercurial/exchange.py
+++ b/mercurial/exchange.py
@@ -104,6 +104,7 @@
             _pushdiscovery(pushop)
             if _pushcheckoutgoing(pushop):
                 _pushchangeset(pushop)
+            _pushcomputecommonheads(pushop)
             _pushsyncphase(pushop)
             _pushobsolete(pushop)
         finally:
@@ -207,6 +208,40 @@
         pushop.ret = pushop.remote.addchangegroup(cg, 'push',
                                                               pushop.repo.url())
 
+def _pushcomputecommonheads(pushop):
+    unfi = pushop.repo.unfiltered()
+    if pushop.ret:
+        # push succeed, synchronize target of the push
+        cheads = pushop.outgoing.missingheads
+    elif pushop.revs is None:
+        # All out push fails. synchronize all common
+        cheads = pushop.outgoing.commonheads
+    else:
+        # I want cheads = heads(::missingheads and ::commonheads)
+        # (missingheads is revs with secret changeset filtered out)
+        #
+        # This can be expressed as:
+        #     cheads = ( (missingheads and ::commonheads)
+        #              + (commonheads and ::missingheads))"
+        #              )
+        #
+        # while trying to push we already computed the following:
+        #     common = (::commonheads)
+        #     missing = ((commonheads::missingheads) - commonheads)
+        #
+        # We can pick:
+        # * missingheads part of common (::commonheads)
+        common = set(pushop.outgoing.common)
+        nm = pushop.repo.changelog.nodemap
+        cheads = [node for node in pushop.revs if nm[node] in common]
+        # and
+        # * commonheads parents on missing
+        revset = unfi.set('%ln and parents(roots(%ln))',
+                         pushop.outgoing.commonheads,
+                         pushop.outgoing.missing)
+        cheads.extend(c.node() for c in revset)
+    pushop.commonheads = cheads
+
 def _pushsyncphase(pushop):
     """synchronise phase information locally and remotly"""
     unfi = pushop.repo.unfiltered()
@@ -210,6 +245,7 @@
 def _pushsyncphase(pushop):
     """synchronise phase information locally and remotly"""
     unfi = pushop.repo.unfiltered()
+    cheads = pushop.commonheads
     if pushop.ret:
         # push succeed, synchronize target of the push
         cheads = pushop.outgoing.missingheads