##// END OF EJS Templates
graph: in hgrc specify line width for main branch...
graph: in hgrc specify line width for main branch You can specify width to visually distinguish main branch (trunk) on hgweb's graph page. Settings format is branch_name.width = value, where width in px e.g.: [graph] default.width = 3

File last commit:

r15986:ba959f6e stable
r16129:5e50982c default
Show More
discovery.py
238 lines | 9.3 KiB | text/x-python | PythonLexer
Dirkjan Ochtman
discovery: fix description line
r11313 # discovery.py - protocol changeset discovery functions
Dirkjan Ochtman
move discovery methods from localrepo into new discovery module
r11301 #
Dirkjan Ochtman
discovery: fix description line
r11313 # Copyright 2010 Matt Mackall <mpm@selenic.com>
Dirkjan Ochtman
move discovery methods from localrepo into new discovery module
r11301 #
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
from node import nullid, short
from i18n import _
Pierre-Yves David
phases: make outgoing object and discovery aware of exclusion...
r15838 import util, setdiscovery, treediscovery, phases
Dirkjan Ochtman
move discovery methods from localrepo into new discovery module
r11301
Peter Arrenbrecht
discovery: drop findoutgoing and simplify findcommonincoming's api...
r14073 def findcommonincoming(repo, remote, heads=None, force=False):
"""Return a tuple (common, anyincoming, heads) used to identify the common
subset of nodes between repo and remote.
Dirkjan Ochtman
move discovery methods from localrepo into new discovery module
r11301
Peter Arrenbrecht
discovery: drop findoutgoing and simplify findcommonincoming's api...
r14073 "common" is a list of (at least) the heads of the common subset.
"anyincoming" is testable as a boolean indicating if any nodes are missing
locally. If remote does not support getbundle, this actually is a list of
roots of the nodes that would be incoming, to be supplied to
changegroupsubset. No code except for pull should be relying on this fact
any longer.
"heads" is either the supplied heads, or else the remote's heads.
Peter Arrenbrecht
discovery: add new set-based discovery...
r14164
If you pass heads and they are all known locally, the reponse lists justs
these heads in "common" and in "heads".
Peter Arrenbrecht
discovery: resurrect findoutgoing as findcommonoutgoing for extension hooks...
r14213
Please use findcommonoutgoing to compute the set of outgoing nodes to give
extensions a good hook into outgoing.
Dirkjan Ochtman
move discovery methods from localrepo into new discovery module
r11301 """
Peter Arrenbrecht
discovery: drop findoutgoing and simplify findcommonincoming's api...
r14073
Peter Arrenbrecht
discovery: add new set-based discovery...
r14164 if not remote.capable('getbundle'):
return treediscovery.findcommonincoming(repo, remote, heads, force)
Dirkjan Ochtman
move discovery methods from localrepo into new discovery module
r11301
Peter Arrenbrecht
discovery: add new set-based discovery...
r14164 if heads:
allknown = True
nm = repo.changelog.nodemap
for h in heads:
if nm.get(h) is None:
allknown = False
break
if allknown:
return (heads, False, heads)
Dirkjan Ochtman
move discovery methods from localrepo into new discovery module
r11301
Peter Arrenbrecht
discovery: add new set-based discovery...
r14164 res = setdiscovery.findcommonheads(repo.ui, repo, remote,
abortwhenunrelated=not force)
common, anyinc, srvheads = res
return (list(common), anyinc, heads or list(srvheads))
Dirkjan Ochtman
move discovery methods from localrepo into new discovery module
r11301
Pierre-Yves David
discovery: introduce outgoing object for result of findcommonoutgoing...
r15837 class outgoing(object):
'''Represents the set of nodes present in a local repo but not in a
(possibly) remote one.
Members:
missing is a list of all nodes present in local but not in remote.
common is a list of all nodes shared between the two repos.
Pierre-Yves David
phases: make outgoing object and discovery aware of exclusion...
r15838 excluded is the list of missing changeset that shouldn't be sent remotely.
Pierre-Yves David
discovery: introduce outgoing object for result of findcommonoutgoing...
r15837 missingheads is the list of heads of missing.
commonheads is the list of heads of common.
The sets are computed on demand from the heads, unless provided upfront
by discovery.'''
def __init__(self, revlog, commonheads, missingheads):
self.commonheads = commonheads
self.missingheads = missingheads
self._revlog = revlog
self._common = None
self._missing = None
Pierre-Yves David
phases: make outgoing object and discovery aware of exclusion...
r15838 self.excluded = []
Pierre-Yves David
discovery: introduce outgoing object for result of findcommonoutgoing...
r15837
def _computecommonmissing(self):
sets = self._revlog.findcommonmissing(self.commonheads,
self.missingheads)
self._common, self._missing = sets
@util.propertycache
def common(self):
if self._common is None:
self._computecommonmissing()
return self._common
@util.propertycache
def missing(self):
if self._missing is None:
self._computecommonmissing()
return self._missing
Peter Arrenbrecht
discovery: resurrect findoutgoing as findcommonoutgoing for extension hooks...
r14213 def findcommonoutgoing(repo, other, onlyheads=None, force=False, commoninc=None):
Pierre-Yves David
discovery: introduce outgoing object for result of findcommonoutgoing...
r15837 '''Return an outgoing instance to identify the nodes present in repo but
not in other.
Peter Arrenbrecht
discovery: resurrect findoutgoing as findcommonoutgoing for extension hooks...
r14213
If onlyheads is given, only nodes ancestral to nodes in onlyheads (inclusive)
are included. If you already know the local repo's heads, passing them in
onlyheads is faster than letting them be recomputed here.
If commoninc is given, it must the the result of a prior call to
Pierre-Yves David
discovery: introduce outgoing object for result of findcommonoutgoing...
r15837 findcommonincoming(repo, other, force) to avoid recomputing it here.'''
Pierre-Yves David
phases: make outgoing object and discovery aware of exclusion...
r15838 # declare an empty outgoing object to be filled later
og = outgoing(repo.changelog, None, None)
# get common set if not provided
if commoninc is None:
commoninc = findcommonincoming(repo, other, force=force)
og.commonheads, _any, _hds = commoninc
# compute outgoing
if not repo._phaseroots[phases.secret]:
og.missingheads = onlyheads or repo.heads()
elif onlyheads is None:
# use visible heads as it should be cached
og.missingheads = phases.visibleheads(repo)
og.excluded = [ctx.node() for ctx in repo.set('secret()')]
else:
# compute common, missing and exclude secret stuff
sets = repo.changelog.findcommonmissing(og.commonheads, onlyheads)
og._common, allmissing = sets
og._missing = missing = []
Pierre-Yves David
phases: properly register excluded changeset when revision are specified...
r15951 og.excluded = excluded = []
Pierre-Yves David
phases: make outgoing object and discovery aware of exclusion...
r15838 for node in allmissing:
if repo[node].phase() >= phases.secret:
excluded.append(node)
else:
missing.append(node)
if excluded:
# update missing heads
Pierre-Yves David
discovery: ensure that missingheads are always heads of everything we tried...
r15955 missingheads = phases.newheads(repo, onlyheads, excluded)
Pierre-Yves David
phases: make outgoing object and discovery aware of exclusion...
r15838 else:
missingheads = onlyheads
og.missingheads = missingheads
return og
Peter Arrenbrecht
discovery: resurrect findoutgoing as findcommonoutgoing for extension hooks...
r14213
Pierre-Yves David
discovery: fix regression when checking heads for pre 1.4 client (issue3218)...
r15986 def checkheads(repo, remote, outgoing, remoteheads, newbranch=False, inc=False):
Pierre-Yves David
discovery: diet discovery.prepush from non-discovery code...
r15932 """Check that a push won't add any outgoing head
Dirkjan Ochtman
move discovery methods from localrepo into new discovery module
r11301
Pierre-Yves David
discovery: diet discovery.prepush from non-discovery code...
r15932 raise Abort error and display ui message as needed.
"""
if remoteheads == [nullid]:
# remote is empty, nothing to check.
return
Dirkjan Ochtman
move discovery methods from localrepo into new discovery module
r11301
cl = repo.changelog
Pierre-Yves David
discovery: diet discovery.prepush from non-discovery code...
r15932 if remote.capable('branchmap'):
# Check for each named branch if we're creating new remote heads.
# To be a remote head after push, node must be either:
# - unknown locally
# - a local outgoing head descended from update
# - a remote head that's known locally and not
# ancestral to an outgoing head
Dirkjan Ochtman
move discovery methods from localrepo into new discovery module
r11301
Pierre-Yves David
discovery: diet discovery.prepush from non-discovery code...
r15932 # 1. Create set of branches involved in the push.
branches = set(repo[n].branch() for n in outgoing.missing)
Dirkjan Ochtman
move discovery methods from localrepo into new discovery module
r11301
Pierre-Yves David
discovery: diet discovery.prepush from non-discovery code...
r15932 # 2. Check for new branches on the remote.
remotemap = remote.branchmap()
newbranches = branches - set(remotemap)
if newbranches and not newbranch: # new branch requires --new-branch
branchnames = ', '.join(sorted(newbranches))
raise util.Abort(_("push creates new remote branches: %s!")
% branchnames,
hint=_("use 'hg push --new-branch' to create"
" new remote branches"))
branches.difference_update(newbranches)
Dirkjan Ochtman
move discovery methods from localrepo into new discovery module
r11301
Pierre-Yves David
discovery: diet discovery.prepush from non-discovery code...
r15932 # 3. Construct the initial oldmap and newmap dicts.
# They contain information about the remote heads before and
# after the push, respectively.
# Heads not found locally are not included in either dict,
# since they won't be affected by the push.
# unsynced contains all branches with incoming changesets.
oldmap = {}
newmap = {}
unsynced = set()
for branch in branches:
remotebrheads = remotemap[branch]
prunedbrheads = [h for h in remotebrheads if h in cl.nodemap]
oldmap[branch] = prunedbrheads
newmap[branch] = list(prunedbrheads)
if len(remotebrheads) > len(prunedbrheads):
unsynced.add(branch)
Dirkjan Ochtman
move discovery methods from localrepo into new discovery module
r11301
Pierre-Yves David
discovery: diet discovery.prepush from non-discovery code...
r15932 # 4. Update newmap with outgoing changes.
# This will possibly add new heads and remove existing ones.
ctxgen = (repo[n] for n in outgoing.missing)
repo._updatebranchcache(newmap, ctxgen)
Dirkjan Ochtman
move discovery methods from localrepo into new discovery module
r11301
Pierre-Yves David
discovery: diet discovery.prepush from non-discovery code...
r15932 else:
# 1-4b. old servers: Check for new topological heads.
# Construct {old,new}map with branch = None (topological branch).
# (code based on _updatebranchcache)
oldheads = set(h for h in remoteheads if h in cl.nodemap)
Pierre-Yves David
discovery: fix regression when checking heads for pre 1.4 client (issue3218)...
r15986 newheads = oldheads.union(outgoing.missing)
Pierre-Yves David
discovery: diet discovery.prepush from non-discovery code...
r15932 if len(newheads) > 1:
Pierre-Yves David
discovery: fix regression when checking heads for pre 1.4 client (issue3218)...
r15986 for latest in reversed(outgoing.missing):
Pierre-Yves David
discovery: diet discovery.prepush from non-discovery code...
r15932 if latest not in newheads:
continue
minhrev = min(cl.rev(h) for h in newheads)
reachable = cl.reachable(latest, cl.node(minhrev))
reachable.remove(latest)
newheads.difference_update(reachable)
branches = set([None])
newmap = {None: newheads}
oldmap = {None: oldheads}
unsynced = inc and branches or set()
Benoit Boissinot
discovery: remove duplication for new remote head discovery
r11578
Pierre-Yves David
discovery: diet discovery.prepush from non-discovery code...
r15932 # 5. Check for new heads.
# If there are more heads after the push than before, a suitable
# error message, depending on unsynced status, is displayed.
error = None
for branch in branches:
newhs = set(newmap[branch])
oldhs = set(oldmap[branch])
if len(newhs) > len(oldhs):
dhs = list(newhs - oldhs)
if error is None:
if branch not in ('default', None):
error = _("push creates new remote head %s "
"on branch '%s'!") % (short(dhs[0]), branch)
else:
error = _("push creates new remote head %s!"
) % short(dhs[0])
if branch in unsynced:
hint = _("you should pull and merge or "
"use push -f to force")
else:
hint = _("did you forget to merge? "
"use push -f to force")
if branch is not None:
repo.ui.note(_("new remote heads on branch '%s'\n") % branch)
for h in dhs:
repo.ui.note(_("new remote head %s\n") % short(h))
if error:
raise util.Abort(error, hint=hint)
Benoit Boissinot
discovery: remove duplication for new remote head discovery
r11578
Pierre-Yves David
discovery: diet discovery.prepush from non-discovery code...
r15932 # 6. Check for unsynced changes on involved branches.
if unsynced:
repo.ui.warn(_("note: unsynced remote changes!\n"))