171 # we return an integer indicating remote head count |
171 # we return an integer indicating remote head count |
172 # change |
172 # change |
173 pushop.ret = pushop.remote.addchangegroup(cg, 'push', |
173 pushop.ret = pushop.remote.addchangegroup(cg, 'push', |
174 pushop.repo.url()) |
174 pushop.repo.url()) |
175 |
175 |
176 if pushop.ret: |
176 _pushsyncphase(pushop) |
177 # push succeed, synchronize target of the push |
|
178 cheads = pushop.outgoing.missingheads |
|
179 elif pushop.revs is None: |
|
180 # All out push fails. synchronize all common |
|
181 cheads = pushop.outgoing.commonheads |
|
182 else: |
|
183 # I want cheads = heads(::missingheads and ::commonheads) |
|
184 # (missingheads is revs with secret changeset filtered out) |
|
185 # |
|
186 # This can be expressed as: |
|
187 # cheads = ( (missingheads and ::commonheads) |
|
188 # + (commonheads and ::missingheads))" |
|
189 # ) |
|
190 # |
|
191 # while trying to push we already computed the following: |
|
192 # common = (::commonheads) |
|
193 # missing = ((commonheads::missingheads) - commonheads) |
|
194 # |
|
195 # We can pick: |
|
196 # * missingheads part of common (::commonheads) |
|
197 common = set(pushop.outgoing.common) |
|
198 nm = pushop.repo.changelog.nodemap |
|
199 cheads = [node for node in pushop.revs if nm[node] in common] |
|
200 # and |
|
201 # * commonheads parents on missing |
|
202 revset = unfi.set('%ln and parents(roots(%ln))', |
|
203 pushop.outgoing.commonheads, |
|
204 pushop.outgoing.missing) |
|
205 cheads.extend(c.node() for c in revset) |
|
206 # even when we don't push, exchanging phase data is useful |
|
207 remotephases = pushop.remote.listkeys('phases') |
|
208 if (pushop.ui.configbool('ui', '_usedassubrepo', False) |
|
209 and remotephases # server supports phases |
|
210 and pushop.ret is None # nothing was pushed |
|
211 and remotephases.get('publishing', False)): |
|
212 # When: |
|
213 # - this is a subrepo push |
|
214 # - and remote support phase |
|
215 # - and no changeset was pushed |
|
216 # - and remote is publishing |
|
217 # We may be in issue 3871 case! |
|
218 # We drop the possible phase synchronisation done by |
|
219 # courtesy to publish changesets possibly locally draft |
|
220 # on the remote. |
|
221 remotephases = {'publishing': 'True'} |
|
222 if not remotephases: # old server or public only rer |
|
223 _localphasemove(pushop, cheads) |
|
224 # don't push any phase data as there is nothing to push |
|
225 else: |
|
226 ana = phases.analyzeremotephases(pushop.repo, cheads, |
|
227 remotephases) |
|
228 pheads, droots = ana |
|
229 ### Apply remote phase on local |
|
230 if remotephases.get('publishing', False): |
|
231 _localphasemove(pushop, cheads) |
|
232 else: # publish = False |
|
233 _localphasemove(pushop, pheads) |
|
234 _localphasemove(pushop, cheads, phases.draft) |
|
235 ### Apply local phase on remote |
|
236 |
|
237 # Get the list of all revs draft on remote by public here. |
|
238 # XXX Beware that revset break if droots is not strictly |
|
239 # XXX root we may want to ensure it is but it is costly |
|
240 outdated = unfi.set('heads((%ln::%ln) and public())', |
|
241 droots, cheads) |
|
242 for newremotehead in outdated: |
|
243 r = pushop.remote.pushkey('phases', |
|
244 newremotehead.hex(), |
|
245 str(phases.draft), |
|
246 str(phases.public)) |
|
247 if not r: |
|
248 pushop.ui.warn(_('updating %s to public failed!\n') |
|
249 % newremotehead) |
|
250 _pushobsolete(pushop) |
177 _pushobsolete(pushop) |
251 finally: |
178 finally: |
252 if lock is not None: |
179 if lock is not None: |
253 lock.release() |
180 lock.release() |
254 finally: |
181 finally: |
255 if locallock is not None: |
182 if locallock is not None: |
256 locallock.release() |
183 locallock.release() |
257 |
184 |
258 _pushbookmark(pushop) |
185 _pushbookmark(pushop) |
259 return pushop.ret |
186 return pushop.ret |
|
187 |
|
188 def _pushsyncphase(pushop): |
|
189 """synchronise phase information locally and remotly""" |
|
190 unfi = pushop.repo.unfiltered() |
|
191 if pushop.ret: |
|
192 # push succeed, synchronize target of the push |
|
193 cheads = pushop.outgoing.missingheads |
|
194 elif pushop.revs is None: |
|
195 # All out push fails. synchronize all common |
|
196 cheads = pushop.outgoing.commonheads |
|
197 else: |
|
198 # I want cheads = heads(::missingheads and ::commonheads) |
|
199 # (missingheads is revs with secret changeset filtered out) |
|
200 # |
|
201 # This can be expressed as: |
|
202 # cheads = ( (missingheads and ::commonheads) |
|
203 # + (commonheads and ::missingheads))" |
|
204 # ) |
|
205 # |
|
206 # while trying to push we already computed the following: |
|
207 # common = (::commonheads) |
|
208 # missing = ((commonheads::missingheads) - commonheads) |
|
209 # |
|
210 # We can pick: |
|
211 # * missingheads part of common (::commonheads) |
|
212 common = set(pushop.outgoing.common) |
|
213 nm = pushop.repo.changelog.nodemap |
|
214 cheads = [node for node in pushop.revs if nm[node] in common] |
|
215 # and |
|
216 # * commonheads parents on missing |
|
217 revset = unfi.set('%ln and parents(roots(%ln))', |
|
218 pushop.outgoing.commonheads, |
|
219 pushop.outgoing.missing) |
|
220 cheads.extend(c.node() for c in revset) |
|
221 # even when we don't push, exchanging phase data is useful |
|
222 remotephases = pushop.remote.listkeys('phases') |
|
223 if (pushop.ui.configbool('ui', '_usedassubrepo', False) |
|
224 and remotephases # server supports phases |
|
225 and pushop.ret is None # nothing was pushed |
|
226 and remotephases.get('publishing', False)): |
|
227 # When: |
|
228 # - this is a subrepo push |
|
229 # - and remote support phase |
|
230 # - and no changeset was pushed |
|
231 # - and remote is publishing |
|
232 # We may be in issue 3871 case! |
|
233 # We drop the possible phase synchronisation done by |
|
234 # courtesy to publish changesets possibly locally draft |
|
235 # on the remote. |
|
236 remotephases = {'publishing': 'True'} |
|
237 if not remotephases: # old server or public only rer |
|
238 _localphasemove(pushop, cheads) |
|
239 # don't push any phase data as there is nothing to push |
|
240 else: |
|
241 ana = phases.analyzeremotephases(pushop.repo, cheads, |
|
242 remotephases) |
|
243 pheads, droots = ana |
|
244 ### Apply remote phase on local |
|
245 if remotephases.get('publishing', False): |
|
246 _localphasemove(pushop, cheads) |
|
247 else: # publish = False |
|
248 _localphasemove(pushop, pheads) |
|
249 _localphasemove(pushop, cheads, phases.draft) |
|
250 ### Apply local phase on remote |
|
251 |
|
252 # Get the list of all revs draft on remote by public here. |
|
253 # XXX Beware that revset break if droots is not strictly |
|
254 # XXX root we may want to ensure it is but it is costly |
|
255 outdated = unfi.set('heads((%ln::%ln) and public())', |
|
256 droots, cheads) |
|
257 for newremotehead in outdated: |
|
258 r = pushop.remote.pushkey('phases', |
|
259 newremotehead.hex(), |
|
260 str(phases.draft), |
|
261 str(phases.public)) |
|
262 if not r: |
|
263 pushop.ui.warn(_('updating %s to public failed!\n') |
|
264 % newremotehead) |
260 |
265 |
261 def _localphasemove(pushop, nodes, phase=phases.public): |
266 def _localphasemove(pushop, nodes, phase=phases.public): |
262 """move <nodes> to <phase> in the local source repo""" |
267 """move <nodes> to <phase> in the local source repo""" |
263 if pushop.locallocked: |
268 if pushop.locallocked: |
264 phases.advanceboundary(pushop.repo, phase, nodes) |
269 phases.advanceboundary(pushop.repo, phase, nodes) |