Commit Graph

54 Commits

Author SHA1 Message Date
Gregory Szorc
0520797e9d 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.
2017-07-01 22:38:42 -07:00
Pierre-Yves David
04205af86b obsutil: move 'successorssets' to the new modules
We have a new 'obsutil' module now. We move this high level utility there to bring
'obsolete.py' back to a more reasonable size.
2017-06-27 01:03:01 +02:00
Pulkit Goyal
f8b6f67b7a update: show the commit to which we updated in case of multiple heads (BC)
Currently when we have multiple heads on the same branch, update tells us that
there some more heads for the current branch but does not tells us the head to
which the repository has been updated to. It makes more sense showing the
head we updated to and then telling there are some more heads.
2017-06-06 22:17:39 +05:30
Augie Fackler
39eba5889f localrepo: extract bookmarkheads method to bookmarks.py
This method is only used internally by destutil, and it's obscure
enough I'm willing to just move it without a deprecation warning,
especially since the new method has more constrained functionality.

Design-wise I'd also like to get active bookmark handling folded into
the bookmark store, so that we don't squirrel away an extra attribute
for the active bookmark on the repository object.
2017-05-18 16:43:56 -04:00
Yuya Nishihara
8e1d6228ac scmutil: proxy revrange() through repo to break import cycles
This was one of the hardest import cycles as scmutil is widely used and
revset functions are likely to depend on a variety of modules.

New repo.anyrevs() does not expand user aliases by default to copy the
behavior of the existing repo.revs(). I don't want to add new function to
localrepository, but this function is quite similar to repo.revs() so it
won't increase the complexity of the localrepository class so much.
2017-02-19 20:00:18 +09:00
Martin von Zweigbergk
7ddb655b81 destutil: drop now-unused "check" parameter from destupdate() 2017-02-13 11:32:09 -08:00
Martin von Zweigbergk
7e61f1a33b destutil: remove duplicate check and leave it to merge.update()
The check is done in merge.update() already and the next few patches
will add more checks there. Some of the additional checks will need
information about the merge that will not be available in destutil.

Since commands.postincoming() catches UpdateAbort(), we need to change
merge.update() to raise that more specific exception.

This goes directly again c6bcc960108f (destupdate: move the check
related to the "clean" logic in the function, 2015-10-05), but it will
simplify the next few patches, and we can always move it out again
(preferably move, not copy) after if we still think it's better that
way.
2017-02-09 09:52:32 -08:00
Martin von Zweigbergk
5afbd30073 destutil: remove dead code about non-linear updates
IIUC, the non-linear updates no longer happen by default since
5a430b57b16e (update: change default destination to tipmost descendant
(issue4673) (BC), 2016-02-02), and it was only if they happened by
default that we used to error out, so there is no longer a need to
handle this case.
2017-02-07 13:11:30 -08:00
Mads Kiilerich
38cb771268 spelling: fixes of non-dictionary words 2016-10-17 23:16:55 +02:00
timeless
263e302697 update: use single quotes in use warning 2016-09-02 21:49:33 +00:00
liscju
d8406bc0f4 update: fix bare --clean to work on new branch (issue5003) (BC)
Before this commit bare update --clean on newly created branch
updates to the parent commit, even if there are later commits
on the parent commit's branch. Update to the latest head on the
parent commit's branch instead.

This seems reasonable as clean should discard uncommited changes,
branch is one of them.
2016-04-05 07:30:01 +02:00
Pierre-Yves David
da0dc4d591 destutil: add the ability to specify a search space for rebase destination
In the 'hg pull --rebase', we don't want to pick a rebase destination unrelated
to the pull, we lay down basic infrastructure to allow such restriction on
stable (before 3.8 release) in this case. See issue 5214 for details.

Actual usage and test will be in the next patch.
2016-04-30 18:41:08 +02:00
Yuya Nishihara
51590b34c7 update: resurrect bare update from null parent to tip-most branch head
The situation is tricky if repository has no "default" branch, because "null"
revision belongs to non-existent "default" branch.

Before 9d20b43f7098, bare update from null would bring us to the tip-most
non-closed branch head. 9d20b43f7098 removed the special handling of missing
"default" branch since we wanted to stick to the uncommitted branch in that
case. But, if the parent is "null" revision, and if the missing branch is
"default", it shouldn't be an uncommitted branch. In this case, bare update
should bring us to the tip-most head as before.

This should fix the test breakage introduced by 9d20b43f7098.
2016-04-15 20:37:11 +09:00
liscju
4b86252e85 update: fix bare update to work on new branch
So far bare update on new branch results in
'abort: branch new-branch not found'. This commit fixes
this by updating to the parent of wctx.

The effect of updating to the parent of wctx is to move to the paren't
branch - this means that it is no longer necessary to prevent you from
updating if you would lose your newly created branch.
2016-04-05 06:53:33 +02:00
FUJIWARA Katsunori
f736378bd5 destutil: show message and hint at updating to the closed head as warning 2016-03-29 23:59:32 +09:00
FUJIWARA Katsunori
aeacfdc6d7 destutil: make messages at updating to the closed head usual form
This patch makes messages at updating to the closed head usual form
for Mercurial as below:

    one line description of the problem with no period
    (a suggestion about how to move forward or get more info)
2016-03-29 23:59:32 +09:00
FUJIWARA Katsunori
9edf9953ec destutil: choose non-closed branch head at first (BC)
Before this patch, destupdate() returns the tipmost (descendant)
branch head regardless of closed or not. But updating to closed branch
head isn't reasonable for ordinary workflow, because:

  - "hg heads" doesn't show closed heads (= updated parent itself) by
    default

  - subsequent committing on it re-opens closed branch

    even if inactivation of closed head is needed, update destination
    isn't it, because it should be merged into to another branch in
    such case.

This patch chooses non-closed descendant branch head as default update
destination at first. If all descendant branch heads are closed,
destupdate() returns the tipmost closed branch head.

For simplicity, this patch chooses adding _destupdatebranchfallback()
instead largely changing _destupdatebranch().

This patch changes not only normal lookup code path, but also the "no
default branch" code path, for consistency.
2016-03-07 03:14:19 +09:00
FUJIWARA Katsunori
c83f9e65b1 destutil: show message about other branch heads, even if on a closed head
Before this patch, bare "hg update" displays message below, if there
is at least one non-closed branch head other than current parent:

   1. 'XX other heads for branch "BRANCH"' message, if current parent is
      on a non-closed branch head

      This suggests user to invoke "hg heads" or so for merging them.

   2. no message, if current parent is on a closed branch head

      At this patch, bare "hg update" might choose closed branch head
      as update destination, and it causes this situation easily.

   3. no message, otherwise (= current parent isn't on any branch head)

'XX other heads for branch "BRANCH"' should be displayed also in #2
case above, because user might overlook other non-closed branch heads.

This patch gets a list of all branch heads regardless of closed-ness
of it, and uses it (= 'allheads') to distinguish #1/#2 from #3 above.
2016-02-24 23:00:33 +09:00
FUJIWARA Katsunori
80db9e6cdf destutil: use cached branch information instead of query for efficiency
Before this patch, calculation of "the tipmost branch head on current
branch" uses revset query "max(.::(head() and branch(BRANCH)))", but
this isn't efficiency, because:

  - head() predicate lists up heads on all branches, but
  - branch() predicate eliminates heads on other branches

In addition to it, without "literal:" prefix for branch name,
branch(BRANCH) tries to (1) look up BRANCH in "repo.branchmap()" and
(2) look up BRANCH as symbol name again, if there is no branch
matching against BRANCH. The latter looking up is obviously redundant.

This patch uses repo.branchheads(closed=True) to get all branch heads
on specified branch instead of "head() and branch(BRANCH)" revset
query part.

This patch also makes catching RepoLookupError meaningless, because it
is only raised by revset predicate "branch()". But "currentbranch in
repo.branchmap()" can detect whether currentbranch actually exists or
not.

Therefore, this patch replaces try/except for RepoLookupError by
if/else for "currentbranch in repo.branchmap()".
2016-02-24 23:00:33 +09:00
FUJIWARA Katsunori
a461b855a0 destutil: replace wc.branch() invocations by cached value for efficiency 2016-02-24 23:00:33 +09:00
FUJIWARA Katsunori
d37b98a31a destutil: remove redundant examination
Before this patch, "len(heads) != len(otherheads)" is examined to
detect whether message should be displayed or not.

But if "repo.revs('%ln and parents()', heads)", heads should contain
"parents()" and otherheads is always less than heads.
2016-02-24 23:00:32 +09:00
FUJIWARA Katsunori
91c132782d destutil: add new local variable to increase readability
Before this patch, local variable 'heads' is used not only for "all
branch heads" but also for "branch heads other than current parent".

This patch newly adds local variable 'otherheads' for the latter
purpose, to increase readability.
2016-02-24 23:00:32 +09:00
Pierre-Yves David
b305efc185 rebase: choose default destination the same way as 'hg merge' (BC)
This changeset finally make 'hg rebase' choose its default destination using the
same logic as 'hg merge'. The previous default was "tipmost changeset on the
current branch", the new default is "the other head if there is only one".  This
change has multiple consequences:

- Multiple tests which were not rebasing anything (rebasing from tipmost head)
  are now rebasing on the other "lower" branch. This is the expected new
  behavior.

- A test is now explicitly aborting when there is too many heads on the branch.
  This is the expected behavior.

- We gained a better detection of the "nothing to rebase" case while performing
  'hg pull --rebase' so the message have been updated. Making clearer than an
  update was performed and why. This is beneficial side-effect.

- Rebasing from an active bookmark will behave the same as 'hg merge' from a
  bookmark.
2016-02-14 13:25:59 +00:00
Pierre-Yves David
8f36438164 destutil: ensure we offer 'hg update' hint when not at head in all cases
In the merge case, we abort if the working copy is not at head, offering to
run 'hg update' in the hint instead. In the rebase case, we do not abort in that
case. Yet if no rebase destination are found, it still make sense to hint the
user about running 'hg update'. So we re-introduce a conditional using this
branch in the 'onheadcheck == False' case.

This will get used on rebase use this function.
2016-02-09 23:35:21 +00:00
Pierre-Yves David
4975fa6f10 destutil: add more precise error classes for destmerge
Having exception classes more precise than 'Abort' will allow us to properly
catch "nothing to rebase" situations when we will be using 'destmerge' in
rebase.
2016-02-09 23:30:41 +00:00
Pierre-Yves David
ac286ef82e destutil: allow to disable the "on head check" in destmerge
'hg merge' refuses to pick a default destination if the working copy is not on
a head. This is a very sensible default for 'hg merge' but 'hg rebase' should
work in this situation. So we introduce a way to disable this check. It will
soon be used by rebase.
2016-02-08 22:58:15 +00:00
Pierre-Yves David
38693c451d destutil: allow to specify an explicit source for the merge
We can now specify from where the merge is performed. The experimental revset
is updated to take revisions as argument, allowing to test the feature.

This will become very useful for pick the 'rebase' default destination. For this
reason, we also exclude all descendants from the rebased set from the candidate
destinations. This descendants exclusion was not necessary for merge as default
destination would not be picked from anything else than a head.

I'm not super excited with the current error messages, but I would prefer to
delay an overall messages rework once 'hg rebase' is done getting a default
destination aligned with 'hg merge'.
2016-02-08 19:32:29 +01:00
Pierre-Yves David
5b76b583b1 destutil: remove current head from list of candidates early
While 'hg merge' will refuse to pick a default destination if the working copy
is not on a head, this will be a common and valid case for rebase. In this
case, we will need to exclude from the candidate destination all descendants
from the rebased set.

We make a step forward in that direction by removing parents of the working
copy from the candidate destinations instead of manually filtering the working
copy parent at the end of the process. This will make the extra step of
filtering descendant much simpler in a future changeset.
2016-02-08 18:12:06 +01:00
Pierre-Yves David
e071a4f70d destutil: add an 'action' layer to the destmerge message dictionary
We'll introduce messages for 'rebase' soon, so we introduce a way to select
a message based on the action being performed.
2016-02-08 17:53:44 +01:00
Pierre-Yves David
530d9d0362 destutil: document various failure cases
We document what various conditional branch mean and clarify that they are
exclusive (since they all end up in with exception raised).
2016-02-08 17:34:32 +01:00
Pierre-Yves David
58a2a17b1f destutil: consistently retrieve 'p1' and 'branch'
We already read p1 from the dirstate so let's read the branch from it too.
2016-02-08 14:56:28 +01:00
Pierre-Yves David
5f9bab17c1 merge: give priority to "not at head" failures for bare 'hg merge'
We refuse to pick a destination for a bare 'hg merge' if the working copy is not
at head. This is meant to prevent strange merge from user who forget to update.
(Moreover, such merge does not reduce actually the number of heads)

However, we were doing that as the last possible failure type. So user were
recommended to merge with an explicit head (from this bad location) if the
branch had too many heads.

We now make "not on branch heads" class of failure the first things to check
and fail on. The one test that change was actually trying to check for these
failure (and did not). The new test output is correct.
2016-02-08 14:55:58 +01:00
Pierre-Yves David
45bbc38fe5 destutil: extract all 'mergedest' abort messages into a dictionary
We plan to be able to reuse this function for rebase. The error
message explicitly refers to "merge" in multiple places. So we'll need
to be able to use different messages. The first step of that is to
extract all messages in a dedicated dictionary and use them
indirectly.

As a side effect it clarifies the actual function and opens the way to
various cleanups and fixes in future changesets.
2016-02-09 21:14:37 +00:00
Pierre-Yves David
2dcf98d614 update: change default destination to tipmost descendant (issue4673) (BC)
Bare 'hg update' now brings you to the tipmost descendant (on the same branch).
Leaving the user on the same topological branch. The previous behavior, updating
to the tipmost changeset on the same branch could lead to jump from a
topological branch to another. This was confusing and impractical. As the only
conceivable reason for the old behavior have been address by the recently
introduce message about other heads, we can "safely" change this behavior

All test changes have been reviewed and seen a valid consequences.
2016-02-02 15:24:11 +00:00
Pierre-Yves David
2e0675043e update: warn about other topological heads on bare update
A concern around the user experience of Mercurial is user getting stuck on there
own topological branch forever. For example, someone pulling another topological
branch, missing that message in pull asking them to merge and getting stuck on
there own local branch.

The current way to "address" this concern was for bare 'hg update' to target the
tipmost (also latest pulled) changesets and complain when the update was not
linear. That way, failure to merge newly pulled changesets would result in some
kind of failure.

Yet the failure was quite obscure, not working in all cases (eg: commit right
after pull) and the behavior was very impractical in the common case
(eg: issue4673).

To be able to change that behavior, we need to provide other ways to alert a
user stucks on one of many topological head. We do so with an extra message after
bare update:

  1 other heads for branch "default"

Bookmark get its own special version:

  1 other divergent bookmarks for "foobar"

There is significant room to improve the message itself, and we should augment
it with hint about how to see theses other heads or handle the situation (see
in-line comment). But having "a" message is already a significant improvement
compared to the existing situation. Once we have it we can iterate on a better
version of it. As having such message is an important step toward changing the
default destination for update and other nicety, I would like to move forward
quickly on getting such message.

This was discussed during London - October 2015 Sprint.
2016-02-02 14:49:02 +00:00
Gregory Szorc
07328dec9f destutil: use scmutil.revrange for desthistedit (issue5001)
This allows user aliases to be expanded. It also prevents the
user-provided revset from being treated as a revset expression.
2015-12-24 10:16:30 -08:00
Gregory Szorc
71b5e83cd8 destutil: use absolute_import 2015-12-12 13:32:25 -05:00
Gregory Szorc
0c976d1ad3 histedit: pick an appropriate base changeset by default (BC)
Previously, `hg histedit` required a revision argument specifying which
revision to use as the base for the current histedit operation. There
was an undocumented and experimental "histedit.defaultrev" option that
supported defining a single revision to be used if no argument is
passed.

Mercurial knows what changesets can be edited. And in most scenarios,
people want to edit this history of everything on the current head that
is rewritable. Making histedit do this by default and not require
an explicit argument or additional configuration is a major usability
win and will enable more people to use histedit.

This patch changes the behavior of the experimental and undocumented
"histedit.defaultrev" config option to select an appropriate base
revision by default. Comprehensive tests exercising the edge cases
in the new, somewhat complicated default revset have been added.
Surprisingly, no tests broke. I guess we were never testing the
behavior with no ANCESTOR argument (it used to fail with
"abort: histedit requires exactly one ancestor revision"). The new
behavior is much more user friendly.

The functionality for choosing the default base revision has been
moved to destutil.py, where it can easily be modified by extensions.
2015-10-24 19:56:39 +01:00
Pierre-Yves David
234c3afb90 destmerge: extract logic based on branch heads in its own function
One of the main goal of having consolidated destination function is to allow
extension to play with this logic. We extract sub logic to make is wrapping more
practical.
2015-10-15 03:15:54 +01:00
Pierre-Yves David
065efbf449 destmerge: extract logic based on bookmark into its own function
One of the main goal of having consolidated destination function is to allow
extension to play with this logic. We extract sub logic to make is wrapping more
practical.
2015-10-15 03:13:14 +01:00
Pierre-Yves David
b6c0464fcc destupdate: have a generic and extensible way to run each step
We want extension to be able to easily override or add new way to select the
default update destination. We use the same list + dict approach as in other
parts of the code.
2015-10-15 03:00:09 +01:00
Pierre-Yves David
6fa23d38a1 destupdate: extract logic based on branch in its own function
One of the main goal of having consolidated destination function is to allow
extension to play with this logic. We extract sub logic to make is wrapping more
practical.
2015-10-15 02:33:09 +01:00
Pierre-Yves David
07af7a7ec4 destupdate: extract logic based on bookmarks in its own function
One of the main goal of having consolidated destination function is to allow
extension to play with this logic. We extract sub logic to make is wrapping more
practical.
2015-10-15 02:27:30 +01:00
Pierre-Yves David
6594fee40e destupdate: extract logic based on obsolescence marker in its own function
One of the main goal of having consolidated destination function is to allow
extension to play with this logic. We extract sub logic to make is wrapping more
practical.
2015-10-15 02:15:43 +01:00
Pierre-Yves David
1331d59a5c destupdate: move obsolete handling first
This block was overwriting any result from the previous block anyway. So we move
it first to prove it is possible and we'll extract it in its own function in the
next patch.
2015-10-15 02:12:55 +01:00
Pierre-Yves David
b9d3d2a9c2 destupdate: indent bookmark and branch logic
We'll move the obsolete related logic first (as it is overwriting any other
anyway) to make the next patch clearer we add indentation in this one.
2015-10-15 02:12:15 +01:00
Pierre-Yves David
1ef8c926f9 destupdate: extract validation logic
One of the main goal of having consolidated destination function is to allow
extension to play with this logic. We extract sub logic to make is wrapping more
practical.
2015-10-15 14:10:57 +01:00
Pierre-Yves David
614a2e0418 destutil: move default merge destination into a function
Function in destutil are much simpler to wrap and more flexible than revset.
This also help consistency as 'destupdate' live here and cannot become a pure
revset anyway.
2015-10-15 01:11:00 +01:00
Pierre-Yves David
e4483e415c update: introduce a 'UpdateAbort' exception
The 'postincoming' function used by 'hg pull --update' and 'hg unbundle' is
catching 'Abort' exceptions to intercept failed update. This feel a bit too
wide to me, so I'm introducing a more precise exception to specify update
destination issues.
2015-10-05 04:26:26 -07:00
Pierre-Yves David
d22b16ba8c destupdate: also include bookmark related logic
For the same reason, we move the bookmark related update logic into the
'destupdate' function. This requires to extend the returns of the function to
include the bookmark that needs to move (more or less) and the bookmark to
activate at the end of the function. See function documentation for details on
this returns.
2015-09-29 01:03:26 -07:00