mirror of
https://github.com/facebook/sapling.git
synced 2024-12-29 16:12:23 +03:00
pushrebase: also update remote names
Summary: For now pushrebase updates working parent, bookmarks. This diff makes it also update remote bookmarks. This resolves a race condtion in remotenames where the pulled remote bookmarks have unknown nodes and cause update to silently fail. Reviewed By: sfilipco Differential Revision: D18601035 fbshipit-source-id: 6f2c318cbf6b29a6427eeac6d374c1fb13e6155c
This commit is contained in:
parent
ae2be4c73f
commit
3f9123d94f
@ -462,6 +462,41 @@ def _push(orig, ui, repo, *args, **opts):
|
||||
result = orig(ui, repo, *args, **opts)
|
||||
|
||||
if onto and tracker.replacementsreceived:
|
||||
# move remote bookmark
|
||||
#
|
||||
# Note: 'remotenames' also uses 'listkeys' to update remote
|
||||
# bookmarks after push. However, that's racy and does not always
|
||||
# succeed.
|
||||
try:
|
||||
rmarks = repo.names["remotebookmarks"]
|
||||
except KeyError:
|
||||
# remotenames is not enabled.
|
||||
pass
|
||||
else:
|
||||
from .. import remotenames
|
||||
|
||||
# convert to full name (ex. 'master' -> 'remote/master')
|
||||
fullname = remotenames.hoist2fullname(repo, onto)
|
||||
nodes = rmarks.namemap(repo, fullname)
|
||||
if nodes:
|
||||
rebasednodes = list(tracker.mapping.values())
|
||||
# The server does not tell us the explicit new location of
|
||||
# the 'onto' remote boookmark, but we can infer that from
|
||||
# the rebased commits.
|
||||
newnode = next(repo.nodes("max(%ln)", rebasednodes), None)
|
||||
# remotenames might have moved the bookmark already. If
|
||||
# newnode is already in nodes, there is no need to update
|
||||
# it again.
|
||||
if newnode is not None and newnode not in nodes:
|
||||
if not ui.quiet:
|
||||
# When we do update it in this code path, print
|
||||
# a message. This is used in tests.
|
||||
ui.write_err(
|
||||
_("moving remote bookmark %r to %s\n")
|
||||
% (fullname, short(newnode))
|
||||
)
|
||||
remotenames.setremotebookmark(repo, fullname, newnode)
|
||||
|
||||
# move working copy parent
|
||||
if wnode in tracker.mapping:
|
||||
hg.update(repo, tracker.mapping[wnode])
|
||||
|
@ -98,6 +98,10 @@ configitem("remotenames", "transitionbookmarks", default=[])
|
||||
configitem("remotenames", "transitionmessage", default=None)
|
||||
configitem("remotenames", "upstream", default=[])
|
||||
|
||||
# Perform a pull of remotenames for "push" command. This is racy and does not
|
||||
# always update remote bookmarks! The config option exists for testing purpose.
|
||||
configitem("remotenames", "racy-pull-on-push", default=True)
|
||||
|
||||
namespacepredicate = registrar.namespacepredicate()
|
||||
templatekeyword = registrar.templatekeyword()
|
||||
revsetpredicate = registrar.revsetpredicate()
|
||||
@ -138,7 +142,13 @@ def expush(orig, repo, remote, *args, **kwargs):
|
||||
remotebookmarks = _listremotebookmarks(remote, remotebookmarkskeys)
|
||||
else:
|
||||
remotebookmarks = remote.listkeys("bookmarks")
|
||||
pullremotenames(repo, remote, remotebookmarks)
|
||||
|
||||
# ATTENTION: This might get commits that are unknown to the local repo!
|
||||
# The correct approach is to get the remote names within "orig". But
|
||||
# that requires some complicated server-side changes.
|
||||
# internal config: remotenames.racy-pull-on-push
|
||||
if repo.ui.configbool("remotenames", "racy-pull-on-push"):
|
||||
pullremotenames(repo, remote, remotebookmarks)
|
||||
|
||||
return res
|
||||
|
||||
@ -2072,17 +2082,27 @@ def precachedistance(repo):
|
||||
@command("debugremotebookmark")
|
||||
def debugremotebookmark(ui, repo, name, rev):
|
||||
"""Change a remote bookmark under the 'debugremote' namespace."""
|
||||
data = {} # {'remote': {'master': '<commit hash>'}}
|
||||
node = scmutil.revsingle(repo, rev).node()
|
||||
setremotebookmark(repo, "debugremote/%s" % name, node)
|
||||
|
||||
|
||||
def setremotebookmark(repo, fullname, newnode):
|
||||
"""Update a single remote bookmark"""
|
||||
with repo.wlock(), repo.lock(), repo.transaction("debugremotebookmark"):
|
||||
data = {} # {'remote': {'master': '<commit hash>'}}
|
||||
for hexnode, _nametype, remote, rname in readremotenames(repo):
|
||||
data.setdefault(remote, {})[rname] = hexnode
|
||||
|
||||
hexnode = scmutil.revsingle(repo, rev).hex()
|
||||
data.setdefault("debugremote", {})[name] = hexnode
|
||||
|
||||
remote, name = fullname.split("/", 1)
|
||||
data.setdefault(remote, {})[name] = hex(newnode)
|
||||
saveremotenames(repo, data)
|
||||
|
||||
|
||||
def hoist2fullname(repo, hoistname):
|
||||
"""Convert a hoisted name (ex. 'master') to full name (ex. 'remote/master')"""
|
||||
fullname = "%s/%s" % (repo.ui.config("remotenames", "hoist"), hoistname)
|
||||
return fullname
|
||||
|
||||
|
||||
#########
|
||||
# revsets
|
||||
#########
|
||||
|
@ -81,7 +81,8 @@ Test that pushing to a remotename gets rebased
|
||||
o 0 "initial" default/master
|
||||
|
||||
|
||||
$ hg push --to master
|
||||
(disable remotenames.racy-pull-on-push so we can check pushrebase's fallback behavior on updating remotenames)
|
||||
$ hg push --to master --config remotenames.racy-pull-on-push=0
|
||||
pushing rev 5c3cfb78df2f to destination ssh://user@dummy/server bookmark master
|
||||
searching for changes
|
||||
remote: pushing 1 changeset:
|
||||
@ -92,6 +93,7 @@ Test that pushing to a remotename gets rebased
|
||||
adding file changes
|
||||
added 2 changesets with 1 changes to 2 files
|
||||
updating bookmark master
|
||||
moving remote bookmark 'default/master' to 98d6f1036c3b
|
||||
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
||||
|
||||
$ hg log -G -T '{rev} "{desc}" {remotebookmarks}'
|
||||
|
Loading…
Reference in New Issue
Block a user