comparison mercurial/commands.py @ 41054:bad05a6afdc8

pull: fix inconsistent view of bookmarks during pull (issue4700) I had a share where a pull apparently pulled a bookmark but not the revision pointed to by the bookmark, which I suspect is due to this (and if not, we might as well remove known issues in this area). I do this by combining doing all the queries that could read the bookmarks in one round trip. I had to change the handling of the case where the server doesn't support the lookup query, because if it fails, it would otherwise make fremotebookmark.result() block forever. This is due to wireprotov1peer.peerexecutor.sendcommands's behavior (it fills a single future if any query fails synchronously and leaves all other futures unchanged), but I don't know if the fix is to cancel all other futures, or to keep going with the other queries. Differential Revision: https://phab.mercurial-scm.org/D5449
author Valentin Gatien-Baron <valentin.gatienbaron@gmail.com>
date Thu, 20 Dec 2018 22:28:39 -0500
parents 92c574684f75
children 4506f801e492
comparison
equal deleted inserted replaced
41053:6faaf3a1c6ec 41054:bad05a6afdc8
4412 other = hg.peer(repo, opts, source) 4412 other = hg.peer(repo, opts, source)
4413 try: 4413 try:
4414 revs, checkout = hg.addbranchrevs(repo, other, branches, 4414 revs, checkout = hg.addbranchrevs(repo, other, branches,
4415 opts.get('rev')) 4415 opts.get('rev'))
4416 4416
4417
4418 pullopargs = {} 4417 pullopargs = {}
4419 if opts.get('bookmark'): 4418
4420 if not revs: 4419 nodes = None
4421 revs = [] 4420 if opts['bookmark'] or revs:
4422 # The list of bookmark used here is not the one used to actually 4421 # The list of bookmark used here is the same used to actually update
4423 # update the bookmark name. This can result in the revision pulled 4422 # the bookmark names, to avoid the race from issue 4689 and we do
4424 # not ending up with the name of the bookmark because of a race 4423 # all lookup and bookmark queries in one go so they see the same
4425 # condition on the server. (See issue 4689 for details) 4424 # version of the server state (issue 4700).
4426 remotebookmarks = other.listkeys('bookmarks') 4425 nodes = []
4426 fnodes = []
4427 revs = revs or []
4428 if revs and not other.capable('lookup'):
4429 err = _("other repository doesn't support revision lookup, "
4430 "so a rev cannot be specified.")
4431 raise error.Abort(err)
4432 with other.commandexecutor() as e:
4433 fremotebookmarks = e.callcommand('listkeys', {
4434 'namespace': 'bookmarks'
4435 })
4436 for r in revs:
4437 fnodes.append(e.callcommand('lookup', {'key': r}))
4438 remotebookmarks = fremotebookmarks.result()
4427 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks) 4439 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
4428 pullopargs['remotebookmarks'] = remotebookmarks 4440 pullopargs['remotebookmarks'] = remotebookmarks
4429 for b in opts['bookmark']: 4441 for b in opts['bookmark']:
4430 b = repo._bookmarks.expandname(b) 4442 b = repo._bookmarks.expandname(b)
4431 if b not in remotebookmarks: 4443 if b not in remotebookmarks:
4432 raise error.Abort(_('remote bookmark %s not found!') % b) 4444 raise error.Abort(_('remote bookmark %s not found!') % b)
4433 revs.append(hex(remotebookmarks[b])) 4445 nodes.append(remotebookmarks[b])
4434 4446 for i, rev in enumerate(revs):
4435 if revs: 4447 node = fnodes[i].result()
4436 try: 4448 nodes.append(node)
4437 # When 'rev' is a bookmark name, we cannot guarantee that it 4449 if rev == checkout:
4438 # will be updated with that name because of a race condition 4450 checkout = node
4439 # server side. (See issue 4689 for details)
4440 oldrevs = revs
4441 revs = [] # actually, nodes
4442 for r in oldrevs:
4443 with other.commandexecutor() as e:
4444 node = e.callcommand('lookup', {'key': r}).result()
4445
4446 revs.append(node)
4447 if r == checkout:
4448 checkout = node
4449 except error.CapabilityError:
4450 err = _("other repository doesn't support revision lookup, "
4451 "so a rev cannot be specified.")
4452 raise error.Abort(err)
4453 4451
4454 wlock = util.nullcontextmanager() 4452 wlock = util.nullcontextmanager()
4455 if opts.get('update'): 4453 if opts.get('update'):
4456 wlock = repo.wlock() 4454 wlock = repo.wlock()
4457 with wlock: 4455 with wlock:
4458 pullopargs.update(opts.get('opargs', {})) 4456 pullopargs.update(opts.get('opargs', {}))
4459 modheads = exchange.pull(repo, other, heads=revs, 4457 modheads = exchange.pull(repo, other, heads=nodes,
4460 force=opts.get('force'), 4458 force=opts.get('force'),
4461 bookmarks=opts.get('bookmark', ()), 4459 bookmarks=opts.get('bookmark', ()),
4462 opargs=pullopargs).cgresult 4460 opargs=pullopargs).cgresult
4463 4461
4464 # brev is a name, which might be a bookmark to be activated at 4462 # brev is a name, which might be a bookmark to be activated at