##// END OF EJS Templates
show: implement "stack" view...
show: implement "stack" view People often want to know what they are working on *now*. As part of this, they also commonly want to know how that work is related to other changesets in the repo so they can perform common actions like rebase, histedit, and merge. `hg show work` made headway into this space. However, it is geared towards a complete repo view as opposed to just the current line of work. If you have a lot of in-flight work or the repo has many heads, the output can be overwhelming. The closest thing Mercurial has to "show me the current thing I'm working on" that doesn't require custom revsets is `hg qseries`. And this requires MQ, which completely changes workflows and repository behavior and has horrible performance on large repos. But as sub-optimal as MQ is, it does some things right, such as expose a model of the repo that is easy for people to reason about. This simplicity is why I think a lot of people prefer to use MQ, despite its shortcomings. One common development workflow is to author a series of linear changesets, using bookmarks, branches, anonymous heads, or even topics (3rd party extension). I'll call this a "stack." You periodically rewrite history in place (using `hg histedit`) and reparent the stack against newer changesets (using `hg rebase`). This workflow can be difficult because there is no obvious way to quickly see the current "stack" nor its relation to other changesets. Figuring out arguments to `hg rebase` can be difficult and may require highlighting and pasting multiple changeset nodes to construct a command. The goal of this commit is to make stack based workflows simpler by exposing a view of the current stack and its relationship to other releant changesets, notably the parent of the base changeset in the stack and newer heads that the stack could be rebased or merged into. Introduced is the `hg show stack` view. Essentially, it finds all mutable changesets from the working directory revision in both directions, stopping at a merge or branch point. This limits the revisions to a DAG linear range. The stack is rendered as a concise list of changesets. Alongside the stack is a visualization of the DAG, similar to `hg log -G`. Newer public heads from the branch point of the stack are rendered above the stack. The presence of these heads helps people understand the DAG model and the relationship between the stack and changes made since the branch point of that stack. If the "rebase" command is available, a `hg rebase` command is printed for each head so a user can perform a simple copy and paste to perform a rebase. This view is alpha quality. There are tons of TODOs documented inline. But I think it is good enough for a first iteration.

File last commit:

r33194:c5a07a3a default
r33194:c5a07a3a default
Show More
destutil.py
414 lines | 15.4 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,
obsutil: move 'successorssets' to the new modules...
r33143 obsutil,
Yuya Nishihara
scmutil: proxy revrange() through repo to break import cycles...
r31025 scmutil,
Pierre-Yves David
update: move default destination computation to a function...
r26569 )
Martin von Zweigbergk
destutil: drop now-unused "check" parameter from destupdate()
r30962 def _destupdateobs(repo, clean):
Pierre-Yves David
destupdate: extract logic based on obsolescence marker in its own function...
r26723 """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
obsutil: move 'successorssets' to the new modules...
r33143 successors = obsutil.successorssets(repo, p1.node())
Pierre-Yves David
update: move default destination computation to a function...
r26569
# 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
Martin von Zweigbergk
destutil: drop now-unused "check" parameter from destupdate()
r30962 def _destupdatebook(repo, clean):
Pierre-Yves David
destupdate: extract logic based on bookmarks in its own function...
r26724 """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
Martin von Zweigbergk
destutil: drop now-unused "check" parameter from destupdate()
r30962 def _destupdatebranch(repo, clean):
FUJIWARA Katsunori
destutil: choose non-closed branch head at first (BC)...
r28385 """decide on an update destination from current branch
This ignores closed branch heads.
"""
Pierre-Yves David
destupdate: extract logic based on branch in its own function...
r26725 wc = repo[None]
movemark = node = None
FUJIWARA Katsunori
destutil: replace wc.branch() invocations by cached value for efficiency
r28235 currentbranch = wc.branch()
liscju
update: fix bare --clean to work on new branch (issue5003) (BC)...
r29284
if clean:
currentbranch = repo['.'].branch()
FUJIWARA Katsunori
destutil: use cached branch information instead of query for efficiency...
r28236 if currentbranch in repo.branchmap():
FUJIWARA Katsunori
destutil: choose non-closed branch head at first (BC)...
r28385 heads = repo.branchheads(currentbranch)
FUJIWARA Katsunori
destutil: use cached branch information instead of query for efficiency...
r28236 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()
Yuya Nishihara
update: resurrect bare update from null parent to tip-most branch head...
r28924 elif currentbranch == 'default' and not wc.p1():
# "null" parent belongs to "default" branch, but it doesn't exist, so
# update to the tipmost non-closed branch head
node = repo.revs('max(head() and not closed())').first()
FUJIWARA Katsunori
destutil: use cached branch information instead of query for efficiency...
r28236 else:
liscju
update: fix bare update to work on new branch...
r28903 node = repo['.'].node()
Pierre-Yves David
destupdate: extract logic based on branch in its own function...
r26725 return node, movemark, None
Martin von Zweigbergk
destutil: drop now-unused "check" parameter from destupdate()
r30962 def _destupdatebranchfallback(repo, clean):
FUJIWARA Katsunori
destutil: choose non-closed branch head at first (BC)...
r28385 """decide on an update destination from closed heads in current branch"""
wc = repo[None]
currentbranch = wc.branch()
movemark = None
if currentbranch in repo.branchmap():
# here, all descendant branch heads are closed
heads = repo.branchheads(currentbranch, closed=True)
assert heads, "any branch has at least one head"
node = repo.revs('max(.::(%ln))', heads).first()
assert node is not None, ("any revision has at least "
"one descendant branch head")
if bookmarks.isactivewdirparent(repo):
movemark = repo['.'].node()
else:
# here, no "default" branch, and all branches are closed
node = repo.lookup('tip')
assert node is not None, "'tip' exists even in empty repository"
return node, movemark, None
Mads Kiilerich
spelling: fixes of non-dictionary words
r30332 # order in which each step should be evaluated
Pierre-Yves David
destupdate: have a generic and extensible way to run each step...
r26726 # steps are run until one finds a destination
FUJIWARA Katsunori
destutil: choose non-closed branch head at first (BC)...
r28385 destupdatesteps = ['evolution', 'bookmark', 'branch', 'branchfallback']
Pierre-Yves David
destupdate: have a generic and extensible way to run each step...
r26726 # mapping to ease extension overriding steps.
destupdatestepmap = {'evolution': _destupdateobs,
'bookmark': _destupdatebook,
'branch': _destupdatebranch,
FUJIWARA Katsunori
destutil: choose non-closed branch head at first (BC)...
r28385 'branchfallback': _destupdatebranchfallback,
Pierre-Yves David
destupdate: have a generic and extensible way to run each step...
r26726 }
Martin von Zweigbergk
destutil: drop now-unused "check" parameter from destupdate()
r30962 def destupdate(repo, clean=False):
Pierre-Yves David
destupdate: extract logic based on obsolescence marker in its own function...
r26723 """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:
Martin von Zweigbergk
destutil: drop now-unused "check" parameter from destupdate()
r30962 node, movemark, activemark = destupdatestepmap[step](repo, clean)
Pierre-Yves David
destupdate: have a generic and extensible way to run each step...
r26726 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: 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: add the ability to specify a search space for rebase destination...
r29043 def _destmergebook(repo, action='merge', sourceset=None, destspace=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
Augie Fackler
localrepo: extract bookmarkheads method to bookmarks.py...
r32381 bmheads = bookmarks.headsforactive(repo)
Pierre-Yves David
destmerge: extract logic based on bookmark into its own function...
r26727 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: add the ability to specify a search space for rebase destination...
r29043 def _destmergebranch(repo, action='merge', sourceset=None, onheadcheck=True,
destspace=None):
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: add the ability to specify a search space for rebase destination...
r29043
if destspace is not None:
# restrict search space
# used in the 'hg pull --rebase' case, see issue 5214.
nbhs = list(repo.revs('%ld and %ld', destspace, nbhs))
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: add the ability to specify a search space for rebase destination...
r29043 def destmerge(repo, action='merge', sourceset=None, onheadcheck=True,
destspace=None):
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: add the ability to specify a search space for rebase destination...
r29043 # destspace is here to work around issues with `hg pull --rebase` see
# issue5214 for details
Pierre-Yves David
destutil: move default merge destination into a function...
r26714 if repo._activebookmark:
Pierre-Yves David
destutil: add the ability to specify a search space for rebase destination...
r29043 node = _destmergebook(repo, action=action, sourceset=sourceset,
destspace=destspace)
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,
Pierre-Yves David
destutil: add the ability to specify a search space for rebase destination...
r29043 onheadcheck=onheadcheck, destspace=destspace)
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`."""
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
Gregory Szorc
show: implement "stack" view...
r33194 def stackbase(ui, repo):
# The histedit default base stops at public changesets, branchpoints,
# and merges, which is exactly what we want for a stack.
revs = scmutil.revrange(repo, [histeditdefaultrevset])
return revs.last() if revs else None
Pierre-Yves David
update: warn about other topological heads on bare update...
r28029 def _statusotherbook(ui, repo):
Augie Fackler
localrepo: extract bookmarkheads method to bookmarks.py...
r32381 bmheads = bookmarks.headsforactive(repo)
Pierre-Yves David
update: warn about other topological heads on bare update...
r28029 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()
FUJIWARA Katsunori
destutil: show message about other branch heads, even if on a closed head...
r28266 allheads = repo.branchheads(currentbranch, closed=True)
Pierre-Yves David
update: warn about other topological heads on bare update...
r28029 heads = repo.branchheads(currentbranch)
FUJIWARA Katsunori
destutil: show message about other branch heads, even if on a closed head...
r28266 if repo.revs('%ln and parents()', allheads):
# we are on a head, even though it might be closed
FUJIWARA Katsunori
destutil: choose non-closed branch head at first (BC)...
r28385 #
# on closed otherheads
# ========= ==========
# o 0 all heads for current branch are closed
# N only descendant branch heads are closed
# x 0 there is only one non-closed branch head
# N there are some non-closed branch heads
# ========= ==========
FUJIWARA Katsunori
destutil: add new local variable to increase readability...
r28233 otherheads = repo.revs('%ln - parents()', heads)
FUJIWARA Katsunori
destutil: choose non-closed branch head at first (BC)...
r28385 if repo['.'].closesbranch():
FUJIWARA Katsunori
destutil: show message and hint at updating to the closed head as warning
r28684 ui.warn(_('no open descendant heads on branch "%s", '
FUJIWARA Katsunori
destutil: make messages at updating to the closed head usual form...
r28683 'updating to a closed head\n') %
(currentbranch))
FUJIWARA Katsunori
destutil: choose non-closed branch head at first (BC)...
r28385 if otherheads:
timeless
update: use single quotes in use warning
r29964 ui.warn(_("(committing will reopen the head, "
"use 'hg heads .' to see %i other heads)\n") %
FUJIWARA Katsunori
destutil: make messages at updating to the closed head usual form...
r28683 (len(otherheads)))
FUJIWARA Katsunori
destutil: choose non-closed branch head at first (BC)...
r28385 else:
FUJIWARA Katsunori
destutil: show message and hint at updating to the closed head as warning
r28684 ui.warn(_('(committing will reopen branch "%s")\n') %
FUJIWARA Katsunori
destutil: make messages at updating to the closed head usual form...
r28683 (currentbranch))
FUJIWARA Katsunori
destutil: choose non-closed branch head at first (BC)...
r28385 elif otherheads:
Pulkit Goyal
update: show the commit to which we updated in case of multiple heads (BC)...
r32698 curhead = repo['.']
ui.status(_('updated to "%s: %s"\n') % (curhead,
curhead.description().split('\n')[0]))
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)