##// END OF EJS Templates
config: extra the code showing config in its own module too...
config: extra the code showing config in its own module too This conclude our extract of the main semantic in a dedicated module.

File last commit:

r52756:f4733654 default
r53316:04c3fb88 default
Show More
discovery.py
659 lines | 23.5 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 #
Raphaël Gomès
contributor: change mentions of mpm to olivia...
r47575 # Copyright 2010 Olivia Mackall <olivia@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.
Matt Harbison
typing: add `from __future__ import annotations` to most files...
r52756 from __future__ import annotations
Gregory Szorc
discovery: use absolute_import
r25944
Pierre-Yves David
checkheads: upgrade the obsolescence postprocessing logic (issue4354)...
r32009 import functools
Gregory Szorc
discovery: use absolute_import
r25944 from .i18n import _
from .node import (
Pierre-Yves David
checkheads: upgrade the obsolescence postprocessing logic (issue4354)...
r32009 hex,
Gregory Szorc
discovery: use absolute_import
r25944 short,
)
from . import (
bookmarks,
branchmap,
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 error,
outgoing: rework the handling of the `missingroots` case to be faster...
r52487 node as nodemod,
av6
discovery: port _postprocessobsolete() changes from evolve, add tests...
r49537 obsolete,
Gregory Szorc
discovery: use absolute_import
r25944 phases,
Gregory Szorc
py3: finish porting iteritems() to pycompat and remove source transformer...
r43376 pycompat,
Boris Feld
scmutil: extra utility to display a reasonable amount of nodes...
r35185 scmutil,
Gregory Szorc
discovery: use absolute_import
r25944 setdiscovery,
treediscovery,
util,
)
Dirkjan Ochtman
move discovery methods from localrepo into new discovery module
r11301
Augie Fackler
formatting: blacken the codebase...
r43346
Boris Feld
push: restrict common discovery to the pushed set...
r35306 def findcommonincoming(repo, remote, heads=None, force=False, ancestorsof=None):
Peter Arrenbrecht
discovery: drop findoutgoing and simplify findcommonincoming's api...
r14073 """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.
Boris Feld
push: restrict common discovery to the pushed set...
r35306 "ancestorsof" if not None, restrict the discovery to a subset defined by
Manuel Jacob
discovery: weaken claim about returned common heads if ancestorsof are given...
r45702 these nodes. Changeset outside of this set won't be considered (but may
still appear in "common").
Peter Arrenbrecht
discovery: add new set-based discovery...
r14164
Mads Kiilerich
fix trivial spelling errors
r17424 If you pass heads and they are all known locally, the response lists just
Peter Arrenbrecht
discovery: add new set-based discovery...
r14164 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
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if not remote.capable(b'getbundle'):
Peter Arrenbrecht
discovery: add new set-based discovery...
r14164 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:
Augie Fackler
formatting: blacken the codebase...
r43346 knownnode = repo.changelog.hasnode # no nodemap until it is filtered
Martin von Zweigbergk
discovery: don't reimplement all()...
r35897 if all(knownnode(h) for h in heads):
Peter Arrenbrecht
discovery: add new set-based discovery...
r14164 return (heads, False, heads)
Dirkjan Ochtman
move discovery methods from localrepo into new discovery module
r11301
Augie Fackler
formatting: blacken the codebase...
r43346 res = setdiscovery.findcommonheads(
repo.ui,
repo,
remote,
abortwhenunrelated=not force,
ancestorsof=ancestorsof,
)
Peter Arrenbrecht
discovery: add new set-based discovery...
r14164 common, anyinc, srvheads = res
discovery: avoid wrongly saying there are nothing to pull...
r45166 if heads and not anyinc:
# server could be lying on the advertised heads
has_node = repo.changelog.hasnode
anyinc = any(not has_node(n) for n in heads)
Peter Arrenbrecht
discovery: add new set-based discovery...
r14164 return (list(common), anyinc, heads or list(srvheads))
Dirkjan Ochtman
move discovery methods from localrepo into new discovery module
r11301
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
py3: use class X: instead of class X(object):...
r49801 class outgoing:
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """Represents the result of a findcommonoutgoing() call.
Pierre-Yves David
discovery: introduce outgoing object for result of findcommonoutgoing...
r15837
Members:
Manuel Jacob
discovery: fix docstring of `outgoing` class...
r45703 ancestorsof is a list of the nodes whose ancestors are included in the
outgoing operation.
missing is a list of those ancestors of ancestorsof that are present in
local but not in remote.
common is a set containing revs common between the local and the remote
repository (at least all of those that are ancestors of ancestorsof).
Pierre-Yves David
discovery: introduce outgoing object for result of findcommonoutgoing...
r15837 commonheads is the list of heads of common.
Manuel Jacob
discovery: fix docstring of `outgoing` class...
r45703 excluded is the list of missing changeset that shouldn't be sent
remotely.
Some members are computed on demand from the heads, unless provided upfront
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 by discovery."""
Pierre-Yves David
discovery: introduce outgoing object for result of findcommonoutgoing...
r15837
Augie Fackler
formatting: blacken the codebase...
r43346 def __init__(
Manuel Jacob
discovery: change users of `outgoing.missingheads` to `outgoing.ancestorsof`...
r45704 self, repo, commonheads=None, ancestorsof=None, missingroots=None
Augie Fackler
formatting: blacken the codebase...
r43346 ):
outgoing: rework the handling of the `missingroots` case to be faster...
r52487 # at most one of them must not be set
if commonheads is not None and missingroots is not None:
m = 'commonheads and missingroots arguments are mutually exclusive'
raise error.ProgrammingError(m)
Pierre-Yves David
outgoing: adds some default value for argument...
r29805 cl = repo.changelog
outgoing: add a simple fastpath when there is no common...
r52488 unfi = repo.unfiltered()
ucl = unfi.changelog
to_node = ucl.node
outgoing: rework the handling of the `missingroots` case to be faster...
r52487 missing = None
common = None
outgoing: add a simple fastpath when there is no common...
r52488 arg_anc = ancestorsof
Manuel Jacob
discovery: change users of `outgoing.missingheads` to `outgoing.ancestorsof`...
r45704 if ancestorsof is None:
ancestorsof = cl.heads()
outgoing: add a simple fastpath when there is no common...
r52488
# XXX-perf: do we need all this to be node-list? They would be simpler
# as rev-num sets (and smartset)
if missingroots == [nodemod.nullrev] or missingroots == []:
commonheads = [repo.nullid]
common = set()
if arg_anc is None:
missing = [to_node(r) for r in cl]
else:
missing_rev = repo.revs('::%ln', missingroots, ancestorsof)
missing = [to_node(r) for r in missing_rev]
elif missingroots is not None:
Pierre-Yves David
outgoing: add a 'missingroots' argument...
r29806 # TODO remove call to nodesbetween.
outgoing: rework the handling of the `missingroots` case to be faster...
r52487 missing_rev = repo.revs('%ln::%ln', missingroots, ancestorsof)
ancestorsof = [to_node(r) for r in ucl.headrevs(missing_rev)]
parent_revs = ucl.parentrevs
common_legs = set()
for r in missing_rev:
p1, p2 = parent_revs(r)
if p1 not in missing_rev:
common_legs.add(p1)
if p2 not in missing_rev:
common_legs.add(p2)
common_legs.discard(nodemod.nullrev)
if not common_legs:
commonheads = [repo.nullid]
common = set()
else:
commonheads_revs = unfi.revs(
'heads(%ld::%ld)',
common_legs,
common_legs,
)
commonheads = [to_node(r) for r in commonheads_revs]
common = ucl.ancestors(commonheads_revs, inclusive=True)
missing = [to_node(r) for r in missing_rev]
Pierre-Yves David
outgoing: add a 'missingroots' argument...
r29806 elif not commonheads:
Joerg Sonnenberger
node: replace nullid and friends with nodeconstants class...
r47771 commonheads = [repo.nullid]
Pierre-Yves David
discovery: introduce outgoing object for result of findcommonoutgoing...
r15837 self.commonheads = commonheads
Manuel Jacob
discovery: change users of `outgoing.missingheads` to `outgoing.ancestorsof`...
r45704 self.ancestorsof = ancestorsof
Pierre-Yves David
outgoing: adds some default value for argument...
r29805 self._revlog = cl
outgoing: rework the handling of the `missingroots` case to be faster...
r52487 self._common = common
self._missing = missing
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):
Augie Fackler
formatting: blacken the codebase...
r43346 sets = self._revlog.findcommonmissing(
Manuel Jacob
discovery: change users of `outgoing.missingheads` to `outgoing.ancestorsof`...
r45704 self.commonheads, self.ancestorsof
Augie Fackler
formatting: blacken the codebase...
r43346 )
Pierre-Yves David
discovery: introduce outgoing object for result of findcommonoutgoing...
r15837 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
Augie Fackler
formatting: blacken the codebase...
r43346
def findcommonoutgoing(
repo, other, onlyheads=None, force=False, commoninc=None, portable=False
):
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """Return an outgoing instance to identify the nodes present in repo but
Pierre-Yves David
discovery: introduce outgoing object for result of findcommonoutgoing...
r15837 not in other.
Peter Arrenbrecht
discovery: resurrect findoutgoing as findcommonoutgoing for extension hooks...
r14213
Brodie Rao
cleanup: eradicate long lines
r16683 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.
Peter Arrenbrecht
discovery: resurrect findoutgoing as findcommonoutgoing for extension hooks...
r14213
Mads Kiilerich
help: fix some instances of 'the the'
r17251 If commoninc is given, it must be the result of a prior call to
Sune Foldager
bundle: make bundles more portable (isue3441)...
r16736 findcommonincoming(repo, other, force) to avoid recomputing it here.
Manuel Jacob
discovery: change users of `outgoing.missingheads` to `outgoing.ancestorsof`...
r45704 If portable is given, compute more conservative common and ancestorsof,
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 to make bundles created from the instance more portable."""
Pierre-Yves David
phases: make outgoing object and discovery aware of exclusion...
r15838 # declare an empty outgoing object to be filled later
Pierre-Yves David
outgoing: pass a repo object to the constructor...
r29804 og = outgoing(repo, None, None)
Pierre-Yves David
phases: make outgoing object and discovery aware of exclusion...
r15838
# get common set if not provided
if commoninc is None:
Augie Fackler
formatting: blacken the codebase...
r43346 commoninc = findcommonincoming(
repo, other, force=force, ancestorsof=onlyheads
)
Pierre-Yves David
phases: make outgoing object and discovery aware of exclusion...
r15838 og.commonheads, _any, _hds = commoninc
# compute outgoing
phases: check secret presence the right way during discovery...
r52295 mayexclude = phases.hassecret(repo) or repo.obsstore
Pierre-Yves David
obsolete: do not exchange extinct changesets...
r17206 if not mayexclude:
Manuel Jacob
discovery: change users of `outgoing.missingheads` to `outgoing.ancestorsof`...
r45704 og.ancestorsof = onlyheads or repo.heads()
Pierre-Yves David
phases: make outgoing object and discovery aware of exclusion...
r15838 elif onlyheads is None:
# use visible heads as it should be cached
Manuel Jacob
discovery: change users of `outgoing.missingheads` to `outgoing.ancestorsof`...
r45704 og.ancestorsof = repo.filtered(b"served").heads()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 og.excluded = [ctx.node() for ctx in repo.set(b'secret() or extinct()')]
Pierre-Yves David
phases: make outgoing object and discovery aware of exclusion...
r15838 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:
Pierre-Yves David
obsolete: do not exchange extinct changesets...
r17206 ctx = repo[node]
Patrick Mezard
discovery: add extinct changesets to outgoing.excluded...
r17248 if ctx.phase() >= phases.secret or ctx.extinct():
excluded.append(node)
else:
missing.append(node)
Pierre-Yves David
obsolete: do not exchange extinct changesets...
r17206 if len(missing) == len(allmissing):
Manuel Jacob
discovery: change users of `outgoing.missingheads` to `outgoing.ancestorsof`...
r45704 ancestorsof = onlyheads
Augie Fackler
formatting: blacken the codebase...
r43346 else: # update missing heads
phases: use revision number in new_heads...
r52473 to_rev = repo.changelog.index.rev
to_node = repo.changelog.node
excluded_revs = [to_rev(r) for r in excluded]
onlyheads_revs = [to_rev(r) for r in onlyheads]
new_heads = phases.new_heads(repo, onlyheads_revs, excluded_revs)
ancestorsof = [to_node(r) for r in new_heads]
Manuel Jacob
discovery: change users of `outgoing.missingheads` to `outgoing.ancestorsof`...
r45704 og.ancestorsof = ancestorsof
Sune Foldager
bundle: make bundles more portable (isue3441)...
r16736 if portable:
Manuel Jacob
discovery: change users of `outgoing.missingheads` to `outgoing.ancestorsof`...
r45704 # recompute common and ancestorsof as if -r<rev> had been given for
Sune Foldager
bundle: make bundles more portable (isue3441)...
r16736 # each head of missing, and --base <rev> for each head of the proper
# ancestors of missing
og._computecommonmissing()
cl = repo.changelog
Augie Fackler
cleanup: run pyupgrade on our source tree to clean up varying things...
r44937 missingrevs = {cl.rev(n) for n in og._missing}
Bryan O'Sullivan
revlog: ancestors(*revs) becomes ancestors(revs) (API)...
r16866 og._common = set(cl.ancestors(missingrevs)) - missingrevs
Sune Foldager
bundle: make bundles more portable (isue3441)...
r16736 commonheads = set(og.commonheads)
Manuel Jacob
discovery: change users of `outgoing.missingheads` to `outgoing.ancestorsof`...
r45704 og.ancestorsof = [h for h in og.ancestorsof if h not in commonheads]
Sune Foldager
bundle: make bundles more portable (isue3441)...
r16736
Pierre-Yves David
phases: make outgoing object and discovery aware of exclusion...
r15838 return og
Peter Arrenbrecht
discovery: resurrect findoutgoing as findcommonoutgoing for extension hooks...
r14213
Augie Fackler
formatting: blacken the codebase...
r43346
headssummary: directly feed the function with the 'pushop' object...
r32706 def _headssummary(pushop):
Pierre-Yves David
checkheads: extract branchmap preprocessing...
r17209 """compute a summary of branch and heads status before and after push
headsummary: expose the 'discardedheads' set in the headssummary...
r32708 return {'branch': ([remoteheads], [newheads],
[unsyncedheads], [discardedheads])} mapping
Pierre-Yves David
checkheads: simplify the structure build by preprocessing...
r17211
headsummary: expose the 'discardedheads' set in the headssummary...
r32708 - branch: the branch name,
Pierre-Yves David
checkheads: simplify the structure build by preprocessing...
r17211 - remoteheads: the list of remote heads known locally
headsummary: expose the 'discardedheads' set in the headssummary...
r32708 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 heads made obsolete by the push.
Pierre-Yves David
checkheads: extract branchmap preprocessing...
r17209 """
headssummary: directly feed the function with the 'pushop' object...
r32706 repo = pushop.repo.unfiltered()
remote = pushop.remote
outgoing = pushop.outgoing
Pierre-Yves David
checkheads: extract branchmap preprocessing...
r17209 cl = repo.changelog
Pierre-Yves David
checkheads: simplify the structure build by preprocessing...
r17211 headssum = {}
Pulkit Goyal
discovery: prevent recomputing info about server and outgoing changesets...
r42193 missingctx = set()
Pierre-Yves David
checkheads: extract branchmap preprocessing...
r17209 # A. Create set of branches involved in the push.
Pulkit Goyal
discovery: prevent recomputing info about server and outgoing changesets...
r42193 branches = set()
for n in outgoing.missing:
ctx = repo[n]
missingctx.add(ctx)
branches.add(ctx.branch())
Gregory Szorc
discovery: use command executor interface...
r37655
with remote.commandexecutor() as e:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 remotemap = e.callcommand(b'branchmap', {}).result()
Gregory Szorc
discovery: use command executor interface...
r37655
Augie Fackler
formatting: blacken the codebase...
r43346 knownnode = cl.hasnode # do not use nodemap until it is filtered
Pulkit Goyal
discovery: prevent deleting items from a dictionary...
r42195 # A. register remote heads of branches which are in outgoing set
Gregory Szorc
global: bulk replace simple pycompat.iteritems(x) with x.items()...
r49768 for branch, heads in remotemap.items():
Pulkit Goyal
discovery: prevent deleting items from a dictionary...
r42195 # don't add head info about branches which we don't have locally
if branch not in branches:
continue
Pierre-Yves David
checkheads: simplify the structure build by preprocessing...
r17211 known = []
unsynced = []
for h in heads:
Pierre-Yves David
discovery: stop using nodemap for membership testing...
r20225 if knownnode(h):
Pierre-Yves David
checkheads: simplify the structure build by preprocessing...
r17211 known.append(h)
else:
unsynced.append(h)
headssum[branch] = (known, list(known), unsynced)
Pulkit Goyal
discovery: prevent deleting items from a dictionary...
r42195
Pierre-Yves David
checkheads: simplify the structure build by preprocessing...
r17211 # B. add new branch data
Pulkit Goyal
discovery: drop some unused sets...
r42194 for branch in branches:
Pierre-Yves David
checkheads: simplify the structure build by preprocessing...
r17211 if branch not in headssum:
headssum[branch] = (None, [], [])
Pierre-Yves David
checkheads: extract branchmap preprocessing...
r17209
Pulkit Goyal
discovery: prevent deleting items from a dictionary...
r42195 # C. Update newmap with outgoing changes.
Pierre-Yves David
checkheads: extract branchmap preprocessing...
r17209 # This will possibly add new heads and remove existing ones.
Augie Fackler
formatting: blacken the codebase...
r43346 newmap = branchmap.remotebranchcache(
Joerg Sonnenberger
node: introduce nodeconstants class...
r47538 repo,
(
(branch, heads[1])
Gregory Szorc
global: bulk replace simple pycompat.iteritems(x) with x.items()...
r49768 for branch, heads in headssum.items()
Joerg Sonnenberger
node: introduce nodeconstants class...
r47538 if heads[0] is not None
),
Augie Fackler
formatting: blacken the codebase...
r43346 )
Pierre-Yves David
branchmap: pass revision insteads of changectx to the update function...
r18305 newmap.update(repo, (ctx.rev() for ctx in missingctx))
Gregory Szorc
global: bulk replace simple pycompat.iteritems(x) with x.items()...
r49768 for branch, newheads in newmap.items():
Pierre-Yves David
checkheads: simplify the structure build by preprocessing...
r17211 headssum[branch][1][:] = newheads
Gregory Szorc
global: bulk replace simple pycompat.iteritems(x) with x.items()...
r49768 for branch, items in headssum.items():
headssummary: ensure all returned lists are sorted...
r32672 for l in items:
if l is not None:
l.sort()
headsummary: expose the 'discardedheads' set in the headssummary...
r32708 headssum[branch] = items + ([],)
checkheads: perform obsolescence post processing directly in _headssummary...
r32707 # If there are no obsstore, no post processing are needed.
if repo.obsstore:
checkheads: use "revnum" in the "allfuturecommon" set...
r32791 torev = repo.changelog.rev
Manuel Jacob
discovery: change users of `outgoing.missingheads` to `outgoing.ancestorsof`...
r45704 futureheads = {torev(h) for h in outgoing.ancestorsof}
Augie Fackler
cleanup: run pyupgrade on our source tree to clean up varying things...
r44937 futureheads |= {torev(h) for h in outgoing.commonheads}
checkheads: use a "lazyancestors" object for allfuturecommon...
r32792 allfuturecommon = repo.changelog.ancestors(futureheads, inclusive=True)
Gregory Szorc
py3: finish porting iteritems() to pycompat and remove source transformer...
r43376 for branch, heads in sorted(pycompat.iteritems(headssum)):
headsummary: expose the 'discardedheads' set in the headssummary...
r32708 remoteheads, newheads, unsyncedheads, placeholder = heads
checkheads: perform obsolescence post processing directly in _headssummary...
r32707 result = _postprocessobsolete(pushop, allfuturecommon, newheads)
Augie Fackler
formatting: blacken the codebase...
r43346 headssum[branch] = (
remoteheads,
sorted(result[0]),
unsyncedheads,
sorted(result[1]),
)
Pierre-Yves David
checkheads: simplify the structure build by preprocessing...
r17211 return headssum
Pierre-Yves David
checkheads: extract branchmap preprocessing...
r17209
Augie Fackler
formatting: blacken the codebase...
r43346
Pierre-Yves David
checkheads: simplify the structure build by preprocessing...
r17211 def _oldheadssummary(repo, remoteheads, outgoing, inc=False):
Pierre-Yves David
checkheads: extract branchmap preprocessing...
r17209 """Compute branchmapsummary for repo without branchmap support"""
# 1-4b. old servers: Check for new topological heads.
# Construct {old,new}map with branch = None (topological branch).
Pierre-Yves David
branchmap: extract _updatebranchcache from repo
r18120 # (code based on update)
Augie Fackler
formatting: blacken the codebase...
r43346 knownnode = repo.changelog.hasnode # no nodemap until it is filtered
headssummary: ensure all returned lists are sorted...
r32672 oldheads = sorted(h for h in remoteheads if knownnode(h))
Pierre-Yves David
checkheads: extract branchmap preprocessing...
r17209 # all nodes in outgoing.missing are children of either:
# - an element of oldheads
# - another element of outgoing.missing
# - nullrev
# This explains why the new head are very simple to compute.
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 r = repo.set(b'heads(%ln + %ln)', oldheads, outgoing.missing)
headssummary: ensure all returned lists are sorted...
r32672 newheads = sorted(c.node() for c in r)
Pierre-Yves David
discovery: prevent crash on unknown remote heads with old repo (issue4337)...
r22178 # set some unsynced head to issue the "unsynced changes" warning
Jordi Gutiérrez Hermoso
style: kill ersatz if-else ternary operators...
r24306 if inc:
discovery: also use lists for the returns of '_oldheadssummary'...
r32671 unsynced = [None]
Jordi Gutiérrez Hermoso
style: kill ersatz if-else ternary operators...
r24306 else:
discovery: also use lists for the returns of '_oldheadssummary'...
r32671 unsynced = []
headsummary: expose the 'discardedheads' set in the headssummary...
r32708 return {None: (oldheads, newheads, unsynced, [])}
Pierre-Yves David
checkheads: extract branchmap preprocessing...
r17209
Augie Fackler
formatting: blacken the codebase...
r43346
Ryan McElroy
discovery: pass pushop to _nowarnheads...
r26936 def _nowarnheads(pushop):
Ryan McElroy
discovery: factor out calculation of heads to not warn about...
r26862 # Compute newly pushed bookmarks. We don't warn about bookmarked heads.
Ryan McElroy
discovery: pass pushop to _nowarnheads...
r26936 repo = pushop.repo.unfiltered()
remote = pushop.remote
Ryan McElroy
discovery: factor out calculation of heads to not warn about...
r26862 localbookmarks = repo._bookmarks
Gregory Szorc
discovery: use command executor interface...
r37655
with remote.commandexecutor() as e:
Augie Fackler
formatting: blacken the codebase...
r43346 remotebookmarks = e.callcommand(
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 b'listkeys',
{
b'namespace': b'bookmarks',
},
Augie Fackler
formatting: blacken the codebase...
r43346 ).result()
Gregory Szorc
discovery: use command executor interface...
r37655
Ryan McElroy
discovery: factor out calculation of heads to not warn about...
r26862 bookmarkedheads = set()
liscju
bookmarks: allow pushing active bookmark on new remote head (issue5236)...
r29229
# internal config: bookmarks.pushing
Augie Fackler
formatting: blacken the codebase...
r43346 newbookmarks = [
localbookmarks.expandname(b)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 for b in pushop.ui.configlist(b'bookmarks', b'pushing')
Augie Fackler
formatting: blacken the codebase...
r43346 ]
liscju
bookmarks: allow pushing active bookmark on new remote head (issue5236)...
r29229
Ryan McElroy
discovery: factor out calculation of heads to not warn about...
r26862 for bm in localbookmarks:
rnode = remotebookmarks.get(bm)
if rnode and rnode in repo:
Augie Fackler
bookmarks: remove changectx() method from bmstore (API)...
r43248 lctx, rctx = repo[localbookmarks[bm]], repo[rnode]
Ryan McElroy
discovery: factor out calculation of heads to not warn about...
r26862 if bookmarks.validdest(repo, rctx, lctx):
bookmarkedheads.add(lctx.node())
else:
if bm in newbookmarks and bm not in remotebookmarks:
Martin von Zweigbergk
discovery: look up bookmarks only among bookmarks...
r37469 bookmarkedheads.add(localbookmarks[bm])
Ryan McElroy
discovery: factor out calculation of heads to not warn about...
r26862
return bookmarkedheads
Augie Fackler
formatting: blacken the codebase...
r43346
Ryan McElroy
exchange: pass pushop to discovery.checkheads...
r26935 def checkheads(pushop):
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
Martin von Zweigbergk
errors: raise StateError when push fails because it creates new heads...
r46735 raise StateError error and display ui message as needed.
Pierre-Yves David
discovery: diet discovery.prepush from non-discovery code...
r15932 """
Ryan McElroy
exchange: pass pushop to discovery.checkheads...
r26935
repo = pushop.repo.unfiltered()
remote = pushop.remote
outgoing = pushop.outgoing
remoteheads = pushop.remoteheads
newbranch = pushop.newbranch
inc = bool(pushop.incoming)
Pierre-Yves David
checkheads: extract branchmap preprocessing...
r17209 # 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
Joerg Sonnenberger
node: replace nullid and friends with nodeconstants class...
r47771 if remoteheads == [repo.nullid]:
Pierre-Yves David
discovery: diet discovery.prepush from non-discovery code...
r15932 # remote is empty, nothing to check.
return
Dirkjan Ochtman
move discovery methods from localrepo into new discovery module
r11301
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if remote.capable(b'branchmap'):
headssummary: directly feed the function with the 'pushop' object...
r32706 headssum = _headssummary(pushop)
Pierre-Yves David
checkheads: extract branchmap preprocessing...
r17209 else:
Pierre-Yves David
checkheads: simplify the structure build by preprocessing...
r17211 headssum = _oldheadssummary(repo, remoteheads, outgoing, inc)
push: add a way to allow concurrent pushes on unrelated heads...
r32709 pushop.pushbranchmap = headssum
Augie Fackler
formatting: blacken the codebase...
r43346 newbranches = [
Gregory Szorc
global: bulk replace simple pycompat.iteritems(x) with x.items()...
r49768 branch for branch, heads in headssum.items() if heads[0] is None
Augie Fackler
formatting: blacken the codebase...
r43346 ]
Pierre-Yves David
checkheads: extract branchmap preprocessing...
r17209 # 1. Check for new branches on the remote.
if newbranches and not newbranch: # new branch requires --new-branch
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 branchnames = b', '.join(sorted(newbranches))
Pulkit Goyal
discovery: only calculate closed branches if required...
r42402 # Calculate how many of the new branches are closed branches
closedbranches = set()
for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
if isclosed:
closedbranches.add(tag)
Augie Fackler
formatting: blacken the codebase...
r43346 closedbranches = closedbranches & set(newbranches)
Taapas Agrawal
push: added clear warning message when pushing closed branches(issue6080)...
r42389 if closedbranches:
Martin von Zweigbergk
errors: remove trailing "!" in messages about creating new heads on push...
r46520 errmsg = _(b"push creates new remote branches: %s (%d closed)") % (
Augie Fackler
formatting: blacken the codebase...
r43346 branchnames,
len(closedbranches),
)
Taapas Agrawal
push: added clear warning message when pushing closed branches(issue6080)...
r42389 else:
Martin von Zweigbergk
errors: remove trailing "!" in messages about creating new heads on push...
r46520 errmsg = _(b"push creates new remote branches: %s") % branchnames
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 hint = _(b"use 'hg push --new-branch' to create new remote branches")
Martin von Zweigbergk
errors: raise StateError when push fails because it creates new heads...
r46735 raise error.StateError(errmsg, hint=hint)
Dirkjan Ochtman
move discovery methods from localrepo into new discovery module
r11301
Ryan McElroy
discovery: factor out calculation of heads to not warn about...
r26862 # 2. Find heads that we need not warn about
Ryan McElroy
discovery: pass pushop to _nowarnheads...
r26936 nowarnheads = _nowarnheads(pushop)
Pierre-Yves David
checkheads: extract bookmark computation from the branch loop...
r17212
# 3. Check for new heads.
Pierre-Yves David
discovery: diet discovery.prepush from non-discovery code...
r15932 # If there are more heads after the push than before, a suitable
# error message, depending on unsynced status, is displayed.
Pierre-Yves David
discovery: rename 'error' to 'errormsg'...
r26585 errormsg = None
Gregory Szorc
py3: finish porting iteritems() to pycompat and remove source transformer...
r43376 for branch, heads in sorted(pycompat.iteritems(headssum)):
headsummary: expose the 'discardedheads' set in the headssummary...
r32708 remoteheads, newheads, unsyncedheads, discardedheads = heads
Pierre-Yves David
checkheads: take future obsoleted heads into account...
r17214 # add unsynced data
Mads Kiilerich
discovery: cleanup of variable names and comments
r20381 if remoteheads is None:
FUJIWARA Katsunori
discovery: abort also when pushing multiple headed new branch...
r19840 oldhs = set()
else:
Mads Kiilerich
discovery: cleanup of variable names and comments
r20381 oldhs = set(remoteheads)
oldhs.update(unsyncedheads)
Augie Fackler
formatting: blacken the codebase...
r43346 dhs = None # delta heads, the new heads on branch
checkheads: simplify the code around obsolescence post-processing...
r32675 newhs = set(newheads)
checkheads: clarify that we no longer touch the head unknown locally...
r32673 newhs.update(unsyncedheads)
checkheads: drop now unused filtering of 'unsyncedheads'...
r32674 if unsyncedheads:
if None in unsyncedheads:
Pierre-Yves David
discovery: prevent crash on unknown remote heads with old repo (issue4337)...
r22178 # old remote, no heads data
heads = None
Mads Kiilerich
discovery: don't report all "unsynced" remote heads (issue4230)...
r21198 else:
Boris Feld
scmutil: extra utility to display a reasonable amount of nodes...
r35185 heads = scmutil.nodesummaries(repo, unsyncedheads)
Pierre-Yves David
discovery: prevent crash on unknown remote heads with old repo (issue4337)...
r22178 if heads is None:
Augie Fackler
formatting: blacken the codebase...
r43346 repo.ui.status(
Martin von Zweigbergk
cleanup: join string literals that are already on one line...
r43387 _(b"remote has heads that are not known locally\n")
Augie Fackler
formatting: blacken the codebase...
r43346 )
Pierre-Yves David
discovery: prevent crash on unknown remote heads with old repo (issue4337)...
r22178 elif branch is None:
Augie Fackler
formatting: blacken the codebase...
r43346 repo.ui.status(
Martin von Zweigbergk
cleanup: join string literals that are already on one line...
r43387 _(b"remote has heads that are not known locally: %s\n")
Augie Fackler
formatting: blacken the codebase...
r43346 % heads
)
Mads Kiilerich
discovery: improve "note: unsynced remote changes!" warning...
r20501 else:
Augie Fackler
formatting: blacken the codebase...
r43346 repo.ui.status(
_(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"remote has heads on branch '%s' that are "
b"not known locally: %s\n"
Augie Fackler
formatting: blacken the codebase...
r43346 )
% (branch, heads)
)
Mads Kiilerich
discovery: cleanup of variable names and comments
r20381 if remoteheads is None:
if len(newhs) > 1:
FUJIWARA Katsunori
discovery: abort also when pushing multiple headed new branch...
r19840 dhs = list(newhs)
Pierre-Yves David
discovery: rename 'error' to 'errormsg'...
r26585 if errormsg is None:
Augie Fackler
discovery: re-wrap expression to avoid a black bug...
r43319 errormsg = (
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b"push creates new branch '%s' with multiple heads")
Augie Fackler
formatting: blacken the codebase...
r43346 % branch
Augie Fackler
discovery: re-wrap expression to avoid a black bug...
r43319 )
Augie Fackler
formatting: blacken the codebase...
r43346 hint = _(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"merge or"
b" see 'hg help push' for details about"
b" pushing new heads"
Augie Fackler
formatting: blacken the codebase...
r43346 )
FUJIWARA Katsunori
discovery: abort also when pushing multiple headed new branch...
r19840 elif len(newhs) > len(oldhs):
Mads Kiilerich
discovery: cleanup of variable names and comments
r20381 # remove bookmarked or existing remote heads from the new heads list
Ryan McElroy
discovery: factor out calculation of heads to not warn about...
r26862 dhs = sorted(newhs - nowarnheads - oldhs)
Levi Bard
bookmarks: allow existing remote bookmarks to become heads when pushing
r16835 if dhs:
Pierre-Yves David
discovery: rename 'error' to 'errormsg'...
r26585 if errormsg is None:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if branch not in (b'default', None):
Augie Fackler
formatting: blacken the codebase...
r43346 errormsg = _(
Martin von Zweigbergk
errors: remove trailing "!" in messages about creating new heads on push...
r46520 b"push creates new remote head %s on branch '%s'"
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 ) % (
short(dhs[0]),
branch,
)
Stephen Lee
discovery: if a push would create a new head, mention the bookmark name if any
r21580 elif repo[dhs[0]].bookmarks():
Augie Fackler
formatting: blacken the codebase...
r43346 errormsg = _(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"push creates new remote head %s "
Martin von Zweigbergk
errors: remove trailing "!" in messages about creating new heads on push...
r46520 b"with bookmark '%s'"
Augie Fackler
formatting: blacken the codebase...
r43346 ) % (short(dhs[0]), repo[dhs[0]].bookmarks()[0])
Pierre-Yves David
discovery: diet discovery.prepush from non-discovery code...
r15932 else:
Martin von Zweigbergk
errors: remove trailing "!" in messages about creating new heads on push...
r46520 errormsg = _(b"push creates new remote head %s") % short(
Augie Fackler
formatting: blacken the codebase...
r43346 dhs[0]
)
Mads Kiilerich
discovery: cleanup of variable names and comments
r20381 if unsyncedheads:
Augie Fackler
formatting: blacken the codebase...
r43346 hint = _(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"pull and merge or"
b" see 'hg help push' for details about"
b" pushing new heads"
Augie Fackler
formatting: blacken the codebase...
r43346 )
Pierre-Yves David
discovery: diet discovery.prepush from non-discovery code...
r15932 else:
Augie Fackler
formatting: blacken the codebase...
r43346 hint = _(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"merge or"
b" see 'hg help push' for details about"
b" pushing new heads"
Augie Fackler
formatting: blacken the codebase...
r43346 )
Mads Kiilerich
discovery: make note messages for new heads more readable
r20051 if branch is None:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo.ui.note(_(b"new remote heads:\n"))
Mads Kiilerich
discovery: make note messages for new heads more readable
r20051 else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo.ui.note(_(b"new remote heads on branch '%s':\n") % branch)
Pierre-Yves David
discovery: diet discovery.prepush from non-discovery code...
r15932 for h in dhs:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo.ui.note(b" %s\n" % short(h))
Pierre-Yves David
discovery: rename 'error' to 'errormsg'...
r26585 if errormsg:
Martin von Zweigbergk
errors: raise StateError when push fails because it creates new heads...
r46735 raise error.StateError(errormsg, hint=hint)
Pierre-Yves David
checkheads: extract obsolete post processing in its own function...
r31586
Augie Fackler
formatting: blacken the codebase...
r43346
Pierre-Yves David
checkheads: extract obsolete post processing in its own function...
r31586 def _postprocessobsolete(pushop, futurecommon, candidate_newhs):
"""post process the list of new heads with obsolescence information
Pierre-Yves David
checkheads: upgrade the obsolescence postprocessing logic (issue4354)...
r32009 Exists as a sub-function to contain the complexity and allow extensions to
Pierre-Yves David
checkheads: extract obsolete post processing in its own function...
r31586 experiment with smarter logic.
Pierre-Yves David
checkheads: upgrade the obsolescence postprocessing logic (issue4354)...
r32009
Pierre-Yves David
checkheads: extract obsolete post processing in its own function...
r31586 Returns (newheads, discarded_heads) tuple
"""
Pierre-Yves David
checkheads: upgrade the obsolescence postprocessing logic (issue4354)...
r32009 # known issue
Pierre-Yves David
checkheads: extract obsolete post processing in its own function...
r31586 #
Pierre-Yves David
checkheads: upgrade the obsolescence postprocessing logic (issue4354)...
r32009 # * We "silently" skip processing on all changeset unknown locally
Pierre-Yves David
checkheads: extract obsolete post processing in its own function...
r31586 #
Pierre-Yves David
checkheads: upgrade the obsolescence postprocessing logic (issue4354)...
r32009 # * if <nh> is public on the remote, it won't be affected by obsolete
# marker and a new is created
# define various utilities and containers
Pierre-Yves David
checkheads: extract obsolete post processing in its own function...
r31586 repo = pushop.repo
Pierre-Yves David
checkheads: upgrade the obsolescence postprocessing logic (issue4354)...
r32009 unfi = repo.unfiltered()
index: use `index.get_rev` in `discovery._postprocessobsolete`...
r43960 torev = unfi.changelog.index.get_rev
Pierre-Yves David
checkheads: upgrade the obsolescence postprocessing logic (issue4354)...
r32009 public = phases.public
getphase = unfi._phasecache.phase
Augie Fackler
formatting: blacken the codebase...
r43346 ispublic = lambda r: getphase(unfi, r) == public
ispushed = lambda n: torev(n) in futurecommon
checkheads: pass "ispushed" function to the obsmarkers logic...
r32789 hasoutmarker = functools.partial(pushingmarkerfor, unfi.obsstore, ispushed)
Pierre-Yves David
checkheads: upgrade the obsolescence postprocessing logic (issue4354)...
r32009 successorsmarkers = unfi.obsstore.successors
Augie Fackler
formatting: blacken the codebase...
r43346 newhs = set() # final set of new heads
discarded = set() # new head of fully replaced branch
Pierre-Yves David
checkheads: upgrade the obsolescence postprocessing logic (issue4354)...
r32009
Augie Fackler
formatting: blacken the codebase...
r43346 localcandidate = set() # candidate heads known locally
unknownheads = set() # candidate heads unknown locally
Pierre-Yves David
checkheads: upgrade the obsolescence postprocessing logic (issue4354)...
r32009 for h in candidate_newhs:
if h in unfi:
localcandidate.add(h)
else:
if successorsmarkers.get(h) is not None:
Augie Fackler
formatting: blacken the codebase...
r43346 msg = (
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'checkheads: remote head unknown locally has'
b' local marker: %s\n'
Augie Fackler
formatting: blacken the codebase...
r43346 )
Pierre-Yves David
checkheads: upgrade the obsolescence postprocessing logic (issue4354)...
r32009 repo.ui.debug(msg % hex(h))
unknownheads.add(h)
# fast path the simple case
if len(localcandidate) == 1:
return unknownheads | set(candidate_newhs), set()
av6
discovery: port _postprocessobsolete() changes from evolve, add tests...
r49537 obsrevs = obsolete.getrevs(unfi, b'obsolete')
futurenonobsolete = frozenset(futurecommon) - obsrevs
Pierre-Yves David
checkheads: upgrade the obsolescence postprocessing logic (issue4354)...
r32009 # actually process branch replacement
while localcandidate:
nh = localcandidate.pop()
av6
discovery: port _postprocessobsolete() changes from evolve, add tests...
r49537 r = torev(nh)
discovery: avoid wrong detection of multiple branch heads (issue6256)...
r44949 current_branch = unfi[nh].branch()
Pierre-Yves David
checkheads: upgrade the obsolescence postprocessing logic (issue4354)...
r32009 # run this check early to skip the evaluation of the whole branch
av6
discovery: port _postprocessobsolete() changes from evolve, add tests...
r49537 if ispublic(r) or r not in obsrevs:
Pierre-Yves David
checkheads: upgrade the obsolescence postprocessing logic (issue4354)...
r32009 newhs.add(nh)
continue
# Get all revs/nodes on the branch exclusive to this head
# (already filtered heads are "ignored"))
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 branchrevs = unfi.revs(
b'only(%n, (%ln+%ln))', nh, localcandidate, newhs
)
discovery: avoid wrong detection of multiple branch heads (issue6256)...
r44949
branchnodes = []
for r in branchrevs:
c = unfi[r]
if c.branch() == current_branch:
branchnodes.append(c.node())
Pierre-Yves David
checkheads: upgrade the obsolescence postprocessing logic (issue4354)...
r32009
# The branch won't be hidden on the remote if
# * any part of it is public,
# * any part of it is considered part of the result by previous logic,
# * if we have no markers to push to obsolete it.
Augie Fackler
formatting: blacken the codebase...
r43346 if (
any(ispublic(r) for r in branchrevs)
av6
discovery: port _postprocessobsolete() changes from evolve, add tests...
r49537 or any(torev(n) in futurenonobsolete for n in branchnodes)
Augie Fackler
formatting: blacken the codebase...
r43346 or any(not hasoutmarker(n) for n in branchnodes)
):
Pierre-Yves David
checkheads: extract obsolete post processing in its own function...
r31586 newhs.add(nh)
else:
Pierre-Yves David
checkheads: upgrade the obsolescence postprocessing logic (issue4354)...
r32009 # note: there is a corner case if there is a merge in the branch.
# we might end up with -more- heads. However, these heads are not
# "added" by the push, but more by the "removal" on the remote so I
# think is a okay to ignore them,
discarded.add(nh)
newhs |= unknownheads
Pierre-Yves David
checkheads: extract obsolete post processing in its own function...
r31586 return newhs, discarded
Pierre-Yves David
checkheads: upgrade the obsolescence postprocessing logic (issue4354)...
r32009
Augie Fackler
formatting: blacken the codebase...
r43346
checkheads: pass "ispushed" function to the obsmarkers logic...
r32789 def pushingmarkerfor(obsstore, ispushed, node):
Pierre-Yves David
checkheads: upgrade the obsolescence postprocessing logic (issue4354)...
r32009 """true if some markers are to be pushed for node
We cannot just look in to the pushed obsmarkers from the pushop because
discovery might have filtered relevant markers. In addition listing all
markers relevant to all changesets in the pushed set would be too expensive
(O(len(repo)))
(note: There are cache opportunity in this function. but it would requires
a two dimensional stack.)
"""
successorsmarkers = obsstore.successors
stack = [node]
seen = set(stack)
while stack:
current = stack.pop()
checkheads: pass "ispushed" function to the obsmarkers logic...
r32789 if ispushed(current):
Pierre-Yves David
checkheads: upgrade the obsolescence postprocessing logic (issue4354)...
r32009 return True
markers = successorsmarkers.get(current, ())
# markers fields = ('prec', 'succs', 'flag', 'meta', 'date', 'parents')
for m in markers:
Augie Fackler
formatting: blacken the codebase...
r43346 nexts = m[1] # successors
if not nexts: # this is a prune marker
nexts = m[5] or () # parents
Pierre-Yves David
checkheads: upgrade the obsolescence postprocessing logic (issue4354)...
r32009 for n in nexts:
if n not in seen:
seen.add(n)
stack.append(n)
return False