diff -r 90cb4ec8df64 -r 16ada4cbb1a9 mercurial/exchange.py --- a/mercurial/exchange.py Mon May 29 05:52:13 2017 +0200 +++ b/mercurial/exchange.py Mon May 29 05:53:58 2017 +0200 @@ -323,8 +323,21 @@ self.bkresult = None # discover.outgoing object (contains common and outgoing data) self.outgoing = None - # all remote heads before the push + # all remote topological heads before the push self.remoteheads = None + # Details of the remote branch pre and post push + # + # mapping: {'branch': ([remoteheads], + # [newheads], + # [unsyncedheads], + # [discardedheads])} + # - branch: the branch name + # - remoteheads: the list of remote heads known locally + # None if the branch is new + # - newheads: the new remote heads (known locally) with outgoing pushed + # - unsyncedheads: the list of remote heads unknown locally. + # - discardedheads: the list of remote heads made obsolete by the push + self.pushbranchmap = None # testable as a boolean indicating if any nodes are missing locally. self.incoming = None # phases changes that must be pushed along side the changesets @@ -712,8 +725,23 @@ Exists as an independent function to aid extensions """ - if not pushop.force: - bundler.newpart('check:heads', data=iter(pushop.remoteheads)) + # * 'force' do not check for push race, + # * if we don't push anything, there are nothing to check. + if not pushop.force and pushop.outgoing.missingheads: + allowunrelated = 'related' in bundler.capabilities.get('checkheads', ()) + if not allowunrelated: + bundler.newpart('check:heads', data=iter(pushop.remoteheads)) + else: + affected = set() + for branch, heads in pushop.pushbranchmap.iteritems(): + remoteheads, newheads, unsyncedheads, discardedheads = heads + if remoteheads is not None: + remote = set(remoteheads) + affected |= set(discardedheads) & remote + affected |= remote - set(newheads) + if affected: + data = iter(sorted(affected)) + bundler.newpart('check:updated-heads', data=data) @b2partsgenerator('changeset') def _pushb2ctx(pushop, bundler):