##// END OF EJS Templates
repoview: discard filtered changelog if index isn't shared with unfiltered...
repoview: discard filtered changelog if index isn't shared with unfiltered Before this patch, revisions rollbacked at failure of previous transaction might be visible at subsequent operations unintentionally, if repoview object is reused even after failure of transaction: e.g. command server and HTTP server are typical cases. 'repoview' uses the tuple of values below of unfiltered changelog as "the key" to examine validity of filtered changelog cache. - length - tip node - filtered revisions (as hashed value) - '_delayed' field 'repoview' compares between "the key" of unfiltered changelog at previous caching and now, and reuses filtered changelog cache if no change is detected. But this comparison indicates only that there is no change between unfiltered 'repo.changelog' at last caching and now, but not that filtered changelog cache is valid for current unfiltered one. 'repoview' uses "shallow copy" of unfiltered changelog to create filtered changelog cache. In this case, 'index' buffer of unfiltered changelog is also referred by filtered changelog. At failure of transaction, unfiltered changelog itself is invalidated (= un-referred) on the 'repo' side (see 0a7610758c42 also). But 'index' of it still contains revisions to be rollbacked at this failure, and is referred by filtered changelog. Therefore, even if there is no change between unfiltered 'repo.changelog' at last caching and now, steps below makes rollbacked revisions visible via filtered changelog unintentionally. 1. instantiate unfiltered changelog as 'repo.changelog' (call it CL1) 2. make filtered (= shallow copy of) CL1 (call it FCL1) 3. cache FCL1 with "the key" of CL1 4. revisions are appended to 'index', which is shared by CL1 and FCL1 5. invalidate 'repo.changelog' (= CL1) at failure of transaction 6. instantiate 'repo.changelog' again at next operation (call it CL2) CL2 doesn't have revisions added at (4), because it is instantiated from '00changelog.i', which isn't changed while failed transaction. 7. compare between "the key" of CL1 and CL2 8. FCL1 cached at (3) is reused, because comparison at (7) doesn't detect change between CL1 at (1) and CL2 9. revisions rollbacked at (5) are visible via FCL1 unintentionally, because FCL1 still refers 'index' changed at (4) The root cause of this issue is that there is no examination about validity of filtered changelog cache against current unfiltered one. This patch discards filtered changelog cache, if its 'index' object isn't shared with unfiltered one. BTW, at the time of this patch, redundant truncation of '00changelog.i' at failure of transaction (see 0a7610758c42 for detail) often prevents "hg serve" from making already rollbacked revisions visible, because updating timestamps of '00changelog.i' by truncation makes "hg serve" discard old repoview object with invalid filtered changelog cache. This is reason why this issue is overlooked before this patch, even though test-bundle2-exchange.t has tests in similar situation: failure of "hg push" via HTTP by pretxnclose hook on server side doesn't prevent subsequent commands from looking up outgoing revisions correctly. But timestamp on the filesystem doesn't have enough resolution for recent computation power, and it can't be assumed that this avoidance always works as expected. Therefore, without this patch, this issue might appear occasionally.

File last commit:

r28236:e333cea7 default
r28265:33292621 default
Show More
destutil.py
377 lines | 13.8 KiB | text/x-python | PythonLexer
Pierre-Yves David
update: move default destination computation to a function...
r26569 # destutil.py - Mercurial utility function for command destination
#
# Copyright Matt Mackall <mpm@selenic.com> and other
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
Gregory Szorc
destutil: use absolute_import
r27333 from __future__ import absolute_import
Pierre-Yves David
update: move default destination computation to a function...
r26569 from .i18n import _
from . import (
Pierre-Yves David
destupdate: also include bookmark related logic...
r26641 bookmarks,
Pierre-Yves David
update: move default destination computation to a function...
r26569 error,
obsolete,
)
Pierre-Yves David
destupdate: extract validation logic...
r26720 def _destupdatevalidate(repo, rev, clean, check):
"""validate that the destination comply to various rules
This exists as its own function to help wrapping from extensions."""
wc = repo[None]
p1 = wc.p1()
if not clean:
# Check that the update is linear.
#
# Mercurial do not allow update-merge for non linear pattern
# (that would be technically possible but was considered too confusing
# for user a long time ago)
#
# See mercurial.merge.update for details
if p1.rev() not in repo.changelog.ancestors([rev], inclusive=True):
dirty = wc.dirty(missing=True)
foreground = obsolete.foreground(repo, [p1.node()])
if not repo[rev].node() in foreground:
if dirty:
msg = _("uncommitted changes")
hint = _("commit and merge, or update --clean to"
" discard changes")
raise error.UpdateAbort(msg, hint=hint)
elif not check: # destination is not a descendant.
msg = _("not a linear update")
hint = _("merge or update --check to force update")
raise error.UpdateAbort(msg, hint=hint)
Pierre-Yves David
destupdate: extract logic based on obsolescence marker in its own function...
r26723 def _destupdateobs(repo, clean, check):
"""decide of an update destination from obsolescence markers"""
Pierre-Yves David
update: move default destination computation to a function...
r26569 node = None
wc = repo[None]
p1 = wc.p1()
Pierre-Yves David
destupdate: extract logic based on obsolescence marker in its own function...
r26723 movemark = None
Pierre-Yves David
update: move default destination computation to a function...
r26569
if p1.obsolete() and not p1.children():
# allow updating to successors
successors = obsolete.successorssets(repo, p1.node())
# behavior of certain cases is as follows,
#
# divergent changesets: update to highest rev, similar to what
# is currently done when there are more than one head
# (i.e. 'tip')
#
# replaced changesets: same as divergent except we know there
# is no conflict
#
# pruned changeset: no update is done; though, we could
# consider updating to the first non-obsolete parent,
# similar to what is current done for 'hg prune'
if successors:
# flatten the list here handles both divergent (len > 1)
# and the usual case (len = 1)
successors = [n for sub in successors for n in sub]
# get the max revision for the given successors set,
# i.e. the 'tip' of a set
node = repo.revs('max(%ln)', successors).first()
Pierre-Yves David
destupdate: move obsolete handling first...
r26722 if bookmarks.isactivewdirparent(repo):
movemark = repo['.'].node()
Pierre-Yves David
destupdate: extract logic based on obsolescence marker in its own function...
r26723 return node, movemark, None
Pierre-Yves David
destupdate: extract logic based on bookmarks in its own function...
r26724 def _destupdatebook(repo, clean, check):
"""decide on an update destination from active bookmark"""
# we also move the active bookmark, if any
activemark = None
node, movemark = bookmarks.calculateupdate(repo.ui, repo, None)
if node is not None:
activemark = node
return node, movemark, activemark
Pierre-Yves David
destupdate: extract logic based on branch in its own function...
r26725 def _destupdatebranch(repo, clean, check):
"""decide on an update destination from current branch"""
wc = repo[None]
movemark = node = None
FUJIWARA Katsunori
destutil: replace wc.branch() invocations by cached value for efficiency
r28235 currentbranch = wc.branch()
FUJIWARA Katsunori
destutil: use cached branch information instead of query for efficiency...
r28236 if currentbranch in repo.branchmap():
heads = repo.branchheads(currentbranch, closed=True)
if heads:
node = repo.revs('max(.::(%ln))', heads).first()
Pierre-Yves David
destupdate: extract logic based on branch in its own function...
r26725 if bookmarks.isactivewdirparent(repo):
movemark = repo['.'].node()
FUJIWARA Katsunori
destutil: use cached branch information instead of query for efficiency...
r28236 else:
FUJIWARA Katsunori
destutil: replace wc.branch() invocations by cached value for efficiency
r28235 if currentbranch == 'default': # no default branch!
Pierre-Yves David
destupdate: extract logic based on branch in its own function...
r26725 node = repo.lookup('tip') # update to tip
else:
FUJIWARA Katsunori
destutil: replace wc.branch() invocations by cached value for efficiency
r28235 raise error.Abort(_("branch %s not found") % currentbranch)
Pierre-Yves David
destupdate: extract logic based on branch in its own function...
r26725 return node, movemark, None
Pierre-Yves David
destupdate: have a generic and extensible way to run each step...
r26726 # order in which each step should be evalutated
# steps are run until one finds a destination
destupdatesteps = ['evolution', 'bookmark', 'branch']
# mapping to ease extension overriding steps.
destupdatestepmap = {'evolution': _destupdateobs,
'bookmark': _destupdatebook,
'branch': _destupdatebranch,
}
Pierre-Yves David
destupdate: extract logic based on obsolescence marker in its own function...
r26723 def destupdate(repo, clean=False, check=False):
"""destination for bare update operation
return (rev, movemark, activemark)
- rev: the revision to update to,
- movemark: node to move the active bookmark from
(cf bookmark.calculate update),
- activemark: a bookmark to activate at the end of the update.
"""
Pierre-Yves David
destupdate: have a generic and extensible way to run each step...
r26726 node = movemark = activemark = None
Pierre-Yves David
destupdate: extract logic based on obsolescence marker in its own function...
r26723
Pierre-Yves David
destupdate: have a generic and extensible way to run each step...
r26726 for step in destupdatesteps:
node, movemark, activemark = destupdatestepmap[step](repo, clean, check)
if node is not None:
break
Pierre-Yves David
destupdate: move the check related to the "clean" logic in the function...
r26628 rev = repo[node].rev()
Pierre-Yves David
destupdate: extract validation logic...
r26720 _destupdatevalidate(repo, rev, clean, check)
Pierre-Yves David
destupdate: move the check related to the "clean" logic in the function...
r26628
Pierre-Yves David
destupdate: also include bookmark related logic...
r26641 return rev, movemark, activemark
Pierre-Yves David
destutil: move default merge destination into a function...
r26714
Pierre-Yves David
destutil: extract all 'mergedest' abort messages into a dictionary...
r28102 msgdestmerge = {
# too many matching divergent bookmark
'toomanybookmarks':
Pierre-Yves David
destutil: add an 'action' layer to the destmerge message dictionary...
r28137 {'merge':
(_("multiple matching bookmarks to merge -"
" please merge with an explicit rev or bookmark"),
_("run 'hg heads' to see all heads")),
Pierre-Yves David
rebase: choose default destination the same way as 'hg merge' (BC)...
r28189 'rebase':
(_("multiple matching bookmarks to rebase -"
" please rebase to an explicit rev or bookmark"),
_("run 'hg heads' to see all heads")),
Pierre-Yves David
destutil: add an 'action' layer to the destmerge message dictionary...
r28137 },
Pierre-Yves David
destutil: extract all 'mergedest' abort messages into a dictionary...
r28102 # no other matching divergent bookmark
'nootherbookmarks':
Pierre-Yves David
destutil: add an 'action' layer to the destmerge message dictionary...
r28137 {'merge':
(_("no matching bookmark to merge - "
"please merge with an explicit rev or bookmark"),
_("run 'hg heads' to see all heads")),
Pierre-Yves David
rebase: choose default destination the same way as 'hg merge' (BC)...
r28189 'rebase':
(_("no matching bookmark to rebase - "
"please rebase to an explicit rev or bookmark"),
_("run 'hg heads' to see all heads")),
Pierre-Yves David
destutil: add an 'action' layer to the destmerge message dictionary...
r28137 },
Pierre-Yves David
destutil: extract all 'mergedest' abort messages into a dictionary...
r28102 # branch have too many unbookmarked heads, no obvious destination
'toomanyheads':
Pierre-Yves David
destutil: add an 'action' layer to the destmerge message dictionary...
r28137 {'merge':
(_("branch '%s' has %d heads - please merge with an explicit rev"),
_("run 'hg heads .' to see heads")),
Pierre-Yves David
rebase: choose default destination the same way as 'hg merge' (BC)...
r28189 'rebase':
(_("branch '%s' has %d heads - please rebase to an explicit rev"),
_("run 'hg heads .' to see heads")),
Pierre-Yves David
destutil: add an 'action' layer to the destmerge message dictionary...
r28137 },
Pierre-Yves David
destutil: extract all 'mergedest' abort messages into a dictionary...
r28102 # branch have no other unbookmarked heads
'bookmarkedheads':
Pierre-Yves David
destutil: add an 'action' layer to the destmerge message dictionary...
r28137 {'merge':
(_("heads are bookmarked - please merge with an explicit rev"),
_("run 'hg heads' to see all heads")),
Pierre-Yves David
rebase: choose default destination the same way as 'hg merge' (BC)...
r28189 'rebase':
(_("heads are bookmarked - please rebase to an explicit rev"),
_("run 'hg heads' to see all heads")),
Pierre-Yves David
destutil: add an 'action' layer to the destmerge message dictionary...
r28137 },
Pierre-Yves David
destutil: extract all 'mergedest' abort messages into a dictionary...
r28102 # branch have just a single heads, but there is other branches
'nootherbranchheads':
Pierre-Yves David
destutil: add an 'action' layer to the destmerge message dictionary...
r28137 {'merge':
(_("branch '%s' has one head - please merge with an explicit rev"),
_("run 'hg heads' to see all heads")),
Pierre-Yves David
rebase: choose default destination the same way as 'hg merge' (BC)...
r28189 'rebase':
(_("branch '%s' has one head - please rebase to an explicit rev"),
_("run 'hg heads' to see all heads")),
Pierre-Yves David
destutil: add an 'action' layer to the destmerge message dictionary...
r28137 },
Pierre-Yves David
destutil: extract all 'mergedest' abort messages into a dictionary...
r28102 # repository have a single head
'nootherheads':
Pierre-Yves David
rebase: choose default destination the same way as 'hg merge' (BC)...
r28189 {'merge':
(_('nothing to merge'),
None),
'rebase':
(_('nothing to rebase'),
None),
Pierre-Yves David
destutil: add an 'action' layer to the destmerge message dictionary...
r28137 },
Pierre-Yves David
destutil: extract all 'mergedest' abort messages into a dictionary...
r28102 # repository have a single head and we are not on it
'nootherheadsbehind':
Pierre-Yves David
destutil: add an 'action' layer to the destmerge message dictionary...
r28137 {'merge':
(_('nothing to merge'),
_("use 'hg update' instead")),
Pierre-Yves David
rebase: choose default destination the same way as 'hg merge' (BC)...
r28189 'rebase':
(_('nothing to rebase'),
_("use 'hg update' instead")),
Pierre-Yves David
destutil: add an 'action' layer to the destmerge message dictionary...
r28137 },
Pierre-Yves David
destutil: extract all 'mergedest' abort messages into a dictionary...
r28102 # We are not on a head
'notatheads':
Pierre-Yves David
destutil: add an 'action' layer to the destmerge message dictionary...
r28137 {'merge':
(_('working directory not at a head revision'),
Pierre-Yves David
rebase: choose default destination the same way as 'hg merge' (BC)...
r28189 _("use 'hg update' or merge with an explicit revision")),
'rebase':
(_('working directory not at a head revision'),
_("use 'hg update' or rebase to an explicit revision"))
Pierre-Yves David
destutil: add an 'action' layer to the destmerge message dictionary...
r28137 },
Pierre-Yves David
destutil: allow to specify an explicit source for the merge...
r28139 'emptysourceset':
{'merge':
(_('source set is empty'),
Pierre-Yves David
rebase: choose default destination the same way as 'hg merge' (BC)...
r28189 None),
'rebase':
(_('source set is empty'),
None),
Pierre-Yves David
destutil: allow to specify an explicit source for the merge...
r28139 },
'multiplebranchessourceset':
{'merge':
(_('source set is rooted in multiple branches'),
Pierre-Yves David
rebase: choose default destination the same way as 'hg merge' (BC)...
r28189 None),
'rebase':
(_('rebaseset is rooted in multiple named branches'),
_('specify an explicit destination with --dest')),
Pierre-Yves David
destutil: allow to specify an explicit source for the merge...
r28139 },
Pierre-Yves David
destutil: add an 'action' layer to the destmerge message dictionary...
r28137 }
Pierre-Yves David
destutil: extract all 'mergedest' abort messages into a dictionary...
r28102
Pierre-Yves David
destutil: allow to specify an explicit source for the merge...
r28139 def _destmergebook(repo, action='merge', sourceset=None):
Pierre-Yves David
destmerge: extract logic based on bookmark into its own function...
r26727 """find merge destination in the active bookmark case"""
node = None
bmheads = repo.bookmarkheads(repo._activebookmark)
curhead = repo[repo._activebookmark].node()
if len(bmheads) == 2:
if curhead == bmheads[0]:
node = bmheads[1]
else:
node = bmheads[0]
elif len(bmheads) > 2:
Pierre-Yves David
destutil: add an 'action' layer to the destmerge message dictionary...
r28137 msg, hint = msgdestmerge['toomanybookmarks'][action]
Pierre-Yves David
destutil: add more precise error classes for destmerge...
r28141 raise error.ManyMergeDestAbort(msg, hint=hint)
Pierre-Yves David
destmerge: extract logic based on bookmark into its own function...
r26727 elif len(bmheads) <= 1:
Pierre-Yves David
destutil: add an 'action' layer to the destmerge message dictionary...
r28137 msg, hint = msgdestmerge['nootherbookmarks'][action]
Pierre-Yves David
destutil: add more precise error classes for destmerge...
r28141 raise error.NoMergeDestAbort(msg, hint=hint)
Pierre-Yves David
destmerge: extract logic based on bookmark into its own function...
r26727 assert node is not None
return node
Pierre-Yves David
destutil: allow to disable the "on head check" in destmerge...
r28140 def _destmergebranch(repo, action='merge', sourceset=None, onheadcheck=True):
Pierre-Yves David
destmerge: extract logic based on branch heads in its own function...
r26728 """find merge destination based on branch heads"""
node = None
Pierre-Yves David
destutil: allow to specify an explicit source for the merge...
r28139
if sourceset is None:
sourceset = [repo[repo.dirstate.p1()].rev()]
branch = repo.dirstate.branch()
elif not sourceset:
msg, hint = msgdestmerge['emptysourceset'][action]
Pierre-Yves David
destutil: add more precise error classes for destmerge...
r28141 raise error.NoMergeDestAbort(msg, hint=hint)
Pierre-Yves David
destutil: allow to specify an explicit source for the merge...
r28139 else:
branch = None
for ctx in repo.set('roots(%ld::%ld)', sourceset, sourceset):
if branch is not None and ctx.branch() != branch:
msg, hint = msgdestmerge['multiplebranchessourceset'][action]
Pierre-Yves David
destutil: add more precise error classes for destmerge...
r28141 raise error.ManyMergeDestAbort(msg, hint=hint)
Pierre-Yves David
destutil: allow to specify an explicit source for the merge...
r28139 branch = ctx.branch()
Pierre-Yves David
destmerge: extract logic based on branch heads in its own function...
r26728 bheads = repo.branchheads(branch)
Pierre-Yves David
destutil: ensure we offer 'hg update' hint when not at head in all cases...
r28161 onhead = repo.revs('%ld and %ln', sourceset, bheads)
if onheadcheck and not onhead:
Pierre-Yves David
destutil: allow to specify an explicit source for the merge...
r28139 # Case A: working copy if not on a head. (merge only)
Pierre-Yves David
destutil: document various failure cases...
r28105 #
# This is probably a user mistake We bailout pointing at 'hg update'
Pierre-Yves David
merge: give priority to "not at head" failures for bare 'hg merge'...
r28103 if len(repo.heads()) <= 1:
Pierre-Yves David
destutil: add an 'action' layer to the destmerge message dictionary...
r28137 msg, hint = msgdestmerge['nootherheadsbehind'][action]
Pierre-Yves David
merge: give priority to "not at head" failures for bare 'hg merge'...
r28103 else:
Pierre-Yves David
destutil: add an 'action' layer to the destmerge message dictionary...
r28137 msg, hint = msgdestmerge['notatheads'][action]
Pierre-Yves David
merge: give priority to "not at head" failures for bare 'hg merge'...
r28103 raise error.Abort(msg, hint=hint)
Pierre-Yves David
destutil: allow to specify an explicit source for the merge...
r28139 # remove heads descendants of source from the set
bheads = list(repo.revs('%ln - (%ld::)', bheads, sourceset))
Pierre-Yves David
destutil: remove current head from list of candidates early...
r28138 # filters out bookmarked heads
Pierre-Yves David
destutil: allow to specify an explicit source for the merge...
r28139 nbhs = list(repo.revs('%ld - bookmark()', bheads))
Pierre-Yves David
destutil: remove current head from list of candidates early...
r28138 if len(nbhs) > 1:
# Case B: There is more than 1 other anonymous heads
Pierre-Yves David
destutil: document various failure cases...
r28105 #
# This means that there will be more than 1 candidate. This is
# ambiguous. We abort asking the user to pick as explicit destination
# instead.
Pierre-Yves David
destutil: add an 'action' layer to the destmerge message dictionary...
r28137 msg, hint = msgdestmerge['toomanyheads'][action]
Pierre-Yves David
destutil: remove current head from list of candidates early...
r28138 msg %= (branch, len(bheads) + 1)
Pierre-Yves David
destutil: add more precise error classes for destmerge...
r28141 raise error.ManyMergeDestAbort(msg, hint=hint)
Pierre-Yves David
destutil: remove current head from list of candidates early...
r28138 elif not nbhs:
# Case B: There is no other anonymous heads
Pierre-Yves David
destutil: document various failure cases...
r28105 #
# This means that there is no natural candidate to merge with.
# We abort, with various messages for various cases.
Pierre-Yves David
destutil: remove current head from list of candidates early...
r28138 if bheads:
Pierre-Yves David
destutil: add an 'action' layer to the destmerge message dictionary...
r28137 msg, hint = msgdestmerge['bookmarkedheads'][action]
Pierre-Yves David
destutil: extract all 'mergedest' abort messages into a dictionary...
r28102 elif len(repo.heads()) > 1:
Pierre-Yves David
destutil: add an 'action' layer to the destmerge message dictionary...
r28137 msg, hint = msgdestmerge['nootherbranchheads'][action]
Pierre-Yves David
destutil: extract all 'mergedest' abort messages into a dictionary...
r28102 msg %= branch
Pierre-Yves David
destutil: ensure we offer 'hg update' hint when not at head in all cases...
r28161 elif not onhead:
# if 'onheadcheck == False' (rebase case),
# this was not caught in Case A.
msg, hint = msgdestmerge['nootherheadsbehind'][action]
Pierre-Yves David
destutil: extract all 'mergedest' abort messages into a dictionary...
r28102 else:
Pierre-Yves David
destutil: add an 'action' layer to the destmerge message dictionary...
r28137 msg, hint = msgdestmerge['nootherheads'][action]
Pierre-Yves David
destutil: add more precise error classes for destmerge...
r28141 raise error.NoMergeDestAbort(msg, hint=hint)
Pierre-Yves David
destmerge: extract logic based on branch heads in its own function...
r26728 else:
node = nbhs[0]
assert node is not None
return node
Pierre-Yves David
destutil: allow to disable the "on head check" in destmerge...
r28140 def destmerge(repo, action='merge', sourceset=None, onheadcheck=True):
Pierre-Yves David
destutil: add an 'action' layer to the destmerge message dictionary...
r28137 """return the default destination for a merge
(or raise exception about why it can't pick one)
:action: the action being performed, controls emitted error message
"""
Pierre-Yves David
destutil: move default merge destination into a function...
r26714 if repo._activebookmark:
Pierre-Yves David
destutil: allow to specify an explicit source for the merge...
r28139 node = _destmergebook(repo, action=action, sourceset=sourceset)
Pierre-Yves David
destutil: move default merge destination into a function...
r26714 else:
Pierre-Yves David
destutil: allow to disable the "on head check" in destmerge...
r28140 node = _destmergebranch(repo, action=action, sourceset=sourceset,
onheadcheck=onheadcheck)
Pierre-Yves David
destutil: move default merge destination into a function...
r26714 return repo[node].rev()
Gregory Szorc
histedit: pick an appropriate base changeset by default (BC)...
r27262
histeditdefaultrevset = 'reverse(only(.) and not public() and not ::merge())'
def desthistedit(ui, repo):
"""Default base revision to edit for `hg histedit`."""
Gregory Szorc
destutil: use scmutil.revrange for desthistedit (issue5001)...
r27559 # Avoid cycle: scmutil -> revset -> destutil
from . import scmutil
Gregory Szorc
histedit: pick an appropriate base changeset by default (BC)...
r27262 default = ui.config('histedit', 'defaultrev', histeditdefaultrevset)
if default:
Gregory Szorc
destutil: use scmutil.revrange for desthistedit (issue5001)...
r27559 revs = scmutil.revrange(repo, [default])
Gregory Szorc
histedit: pick an appropriate base changeset by default (BC)...
r27262 if revs:
# The revset supplied by the user may not be in ascending order nor
# take the first revision. So do this manually.
revs.sort()
return revs.first()
return None
Pierre-Yves David
update: warn about other topological heads on bare update...
r28029
def _statusotherbook(ui, repo):
bmheads = repo.bookmarkheads(repo._activebookmark)
curhead = repo[repo._activebookmark].node()
if repo.revs('%n and parents()', curhead):
# we are on the active bookmark
bmheads = [b for b in bmheads if curhead != b]
if bmheads:
msg = _('%i other divergent bookmarks for "%s"\n')
ui.status(msg % (len(bmheads), repo._activebookmark))
def _statusotherbranchheads(ui, repo):
currentbranch = repo.dirstate.branch()
heads = repo.branchheads(currentbranch)
if repo.revs('%ln and parents()', heads):
# we are on a head
FUJIWARA Katsunori
destutil: add new local variable to increase readability...
r28233 otherheads = repo.revs('%ln - parents()', heads)
FUJIWARA Katsunori
destutil: remove redundant examination...
r28234 if otherheads:
Pierre-Yves David
update: warn about other topological heads on bare update...
r28029 ui.status(_('%i other heads for branch "%s"\n') %
FUJIWARA Katsunori
destutil: add new local variable to increase readability...
r28233 (len(otherheads), currentbranch))
Pierre-Yves David
update: warn about other topological heads on bare update...
r28029
def statusotherdests(ui, repo):
"""Print message about other head"""
# XXX we should probably include a hint:
# - about what to do
# - how to see such heads
if repo._activebookmark:
_statusotherbook(ui, repo)
else:
_statusotherbranchheads(ui, repo)