7738
Comment:
|
10550
bug are bugs, we have a bug reports, no need to includes it in the pain point list.
|
Deletions are marked like this. | Additions are marked like this. |
Line 11: | Line 11: |
/!\ This sub-section need rework/splitting/movement/unicorn before being useful |
|
Line 21: | Line 24: |
/!\ This section need rework/splitting/movement/unicorn before being useful |
|
Line 37: | Line 43: |
/!\ This section need rework/splitting/movement/unicorn before being useful |
|
Line 39: | Line 48: |
== Commands == /!\ This section wants to be: * Summary of existing commands and alias * One section per command//action * Quick reminder of the command//action role and spirit * Discuss for name change * Discuss flag names == hg fold == /!\ This sub-section need rework/splitting/movement/unicorn before being useful Currently fold can work in two modes: folding between a target revision and ".", or given an explicit set of revisions, fold this set into a single revision. The current UI for this is weird: for the first mode you specify revisions without --rev and the second mode you specify them with --rev. This UI is inconsistent with the rest of Mercurial. We have several examples of commands that take revisions with or without a --rev argument, and in all these cases, the behaviour is the same, and the --rev specifier is just optional: * strip * update * export Jordi has proposed patch to address this that treats revisions with and without --rev the same way and obtains both kinds of behaviours depending on whether a single or multiple revisions are specified. However, this has other problems. With certain revsets, it may not be easy to know in advance how many revisions are actually in the revset, so it would be surprising to get different behaviour depending on the number of revisions. How to solve this? == Behavior == |
|
Line 40: | Line 76: |
/!\ This sub section need rework/splitting/movement/unicorn before being useful /!\ no decision are will be made on this any time soon, concider using your brain power elsewhere. |
|
Line 47: | Line 88: |
Line 61: | Line 103: |
== hg fold == Currently fold can work in two modes: folding between a target revision and ".", or given an explicit set of revisions, fold this set into a single revision. The current UI for this is weird: for the first mode you specify revisions without --rev and the second mode you specify them with --rev. This UI is inconsistent with the rest of Mercurial. We have several examples of commands that take revisions with or without a --rev argument, and in all these cases, the behaviour is the same, and the --rev specifier is just optional: |
|
Line 64: | Line 104: |
* strip * update * export Jordi has proposed patch to address this that treats revisions with and without --rev the same way and obtains both kinds of behaviours depending on whether a single or multiple revisions are specified. However, this has other problems. With certain revsets, it may not be easy to know in advance how many revisions are actually in the revset, so it would be surprising to get different behaviour depending on the number of revisions. How to solve this? |
|
Line 76: | Line 109: |
Users will often accidentally amend a commit. Recovering from this right now involves looking at .hg/strip-backups, using incoming to find the bundle, hg unbundle, hg update, hg strip -k to delete the temp amend commit, hg bookmark to fix bookmarks, and hg strip again to delete the bad commit. In git it's just: `git reset HEAD@{1}`. We should be able to do something similar with evolve. Either a similar reset command, or perhaps an `hg uncommit -r 'precursor(., 1)'` | Users will often accidentally amend a commit. We need a good story to undo them. This mean changing the commit content, but not touching the working directory. The `hg uncommit` command is already responsible for this action. Growing a was to easily call uncommit on the precursor intead of the parent would fit that need: * `hg uncommit -r 'precursor(., 1)'` * `hg uncommit --precursor` * `hg uncommit -P` (Git have a `git reset HEAD@{1}` notation for this. However, introducing a `git-reset` like command in Mercurial is a non-goal) |
Line 80: | Line 123: |
=== Evolve Steps can be Opaque === | === Evolve can "stabilise" to unstable destination === |
Line 82: | Line 125: |
This is an attempt at creating a situation where the single-step '`hg evolve`' behavior might be useful: amending two commits without calling '`hg evolve`' inbetween. Start with a linear graph: | ==== Situation ==== |
Line 84: | Line 127: |
{{{ @ 5 cc | o 4 c | o 3 bb | o 2 b | o 1 aa | o 0 a |
Start with a linear graph: {{{#!dot digraph G { rankdir=LR node [shape=box] a -> aa -> b -> bb -> c -> cc -> wc } |
Line 97: | Line 136: |
Line 100: | Line 140: |
{{{ @ 9 bb' | | o 7 aa' | | | | o 5 cc | | | | | o 4 c | | | +---x 3 bb | | o | 2 b | | x | 1 aa |/ o 0 a |
{{{#!dot digraph G { rankdir=LR node [shape=box] { node [color=red] aa bb } { node [color=orange] b c cc } aa2 [label="aa'"] bb2 [label="bb'"] a -> aa -> b -> bb -> c -> cc a -> aa2 b -> bb2 } |
Line 118: | Line 154: |
Getting this repo back into an untroubled state takes 6 calls to '`hg evolve`', the last 4 of which need `--any`. | The red changesets are marked as obsolete, and the orange changesets are thus troubled. Starting from bb, getting this repo back into an untroubled state takes 6 calls to '`hg evolve`', the last 4 of which need `--any`. |
Line 120: | Line 156: |
When running the commands, it might not be clear to the user when to run '`hg evolve`' and when to prefer '`hg evolve --any`'. Running '`hg update`' might also affect the results? | ==== Explanation of the current behavior ==== |
Line 122: | Line 158: |
In other words: the steps needed to bring a repository back to an untroubled state feels completely opaque. This is an argument for having '`hg evolve`' evolve all troubled changesets, in a similar way to how '`hg rebase`' only lets you finish the rebase completely or abort it entirely. | This happens because evolve first started to rebase c and cc on B''. After that it asked to --any to start evolving B, BB' and C' and CC' over aa'. ==== Possible improvement ==== The shortest path to stabilization would have been to take care of B and BB' first then directly evolve C and C'' on the result. The fact that `hg evolve` think evolve B is unrelated to BB' (then requires --any) sounds wrong too. Both point can be fixed if we make evolving ancestors "relevant to the context" (not requires any). (This case is not a valid case in favor of hg evolve --all) === The obsolete history is not very usable === In order for evolve to achieve its full potential the hidden history that that evolve creates must be not only useful for enabling amending shared revisions but also _usable_ by the user to get back to old versions of a given revision (e.g. in case that the user is not happy with a later version of that revision). Currently the obsolete history created by evolve is not very usable because the number of hidden, obsolete revisions created by evolve is greater than it should. In particular: - Evolve creates "temporary amend commits" which basically doubles the number of hidden revisions that evolve creates. - Each history modification step creates its own set of obsolete revisions. There is no way to perform several history editing operations and combining those into a single operation. An alternative to this would be for evolve to provide tools to filter or show the obsolete history somehow. === Automatically evolve obsolete revisions when possible === The multi-step nature of evolve operations is a bit painful sometimes, particularly in cases where the necessary evolve --all step would be trivial. For example, at some point it might be nice to automatically detect meta-data only amend operations, and in that case automatically evolve the resulting unstable revisions (whose evolution should be trivial). Alternatively, there could be an --evolve flag for amend or some other way to trigger an automatic evolve when possible. == F.A.Q. == === Why do we have a temporary commit after amend? === It is an implementation details that will eventually be removed |
This page is primarily intended for Mercurial developers
There are a number of things that have to be discussed about how the Evolve UI works.
Glossary
Which language should we use for Evolve? Remember that once this goes into core, this language gets frozen forever.
1. Command names
This sub-section need rework/splitting/movement/unicorn before being useful
evolve: Automatically solve troubled commits. Get rid of stabilize and solve aliases?
previous and next: Move up and down the DAG. No more gup and gdown aliases?
- I'm in favor of removing gup and gdown. I never liked gup because it has "up" in its name and could be confused for "update." -- indygreg
touch: Create a new identical commit but identical to obsolete commit. Rename to restore and limit source to obsolete commits?
- +1 for restore. "touch" never made much sense to me. "touch" is also overloaded in UNIX speak to draw up associations with files. --indygreg
prune: Mark a commit as obsolete, optionally as replacing one. Remove kill and obsolete aliases.
fold: Fold various commits into one. Add a squash alias? Ok since git doesn't have a squash command.
reorder: Proposed command that permutes commits. With this proposed command, the Evolve UI completely replaces all uses of the histedit UI.
2. Concepts
This section need rework/splitting/movement/unicorn before being useful
Successor/precursor: An obsolescence marker can indicate the commit that replaces the obsolete commit. The replacement is a successor, and the obsoleted commit is a precursor. These names are a bit ambiguous, because they sort of are synonyms for descendants and ancestors. Possible alternative language: replacement commit and original commit, with corresponding revset functions.
Troubled commits: Commits that hg evolve will have to fix. There are three kinds of troubled commits:
Unstable commits: non-obsolete commits based on obsolete commits.
If the obsolete commits have a replacement, hg evolve rebases unstable commits to the replacemnt. If there is no replacement, hg evolve rebases unstable commits to the root of their obsolete ancestors.
Bumped commits: replacement commits whose original commit got turned into the public phase by a pull. Better terminology: invalidated replacements?
- Since it is no longer valid to edit a now-public commit, the best that can be done for invalidated replacements is to create a diff between the replacement and the original and add that as a new commit.
Divergent commits: Two conflicting replacement commits for the same original commit.
What should hg evolve do here?
3. Terminology Opinions
This section need rework/splitting/movement/unicorn before being useful
Ideally we're searching for a grammar where everything is related. If we have words that are closely associated in the English language, users will associate them with related version control tasks. It reduces the potential for confusion and increases the probability for knowledge recall. With that in mind, I'm not sure words like "evolve" and "troubled" go together well. You wouldn't think "this thing is troubled, therefore I'm going to evolve it." I would think "stablize" or "solve" would be much better verbs to complement "troubled." "This thing is troubled, therefore I'm going to stablize it" makes more sense, IMO. But I think there's still room for improvement in the grammar. --indygreg
Commands
This section wants to be:
- Summary of existing commands and alias
- One section per command//action
- Quick reminder of the command//action role and spirit
- Discuss for name change
- Discuss flag names
hg fold
This sub-section need rework/splitting/movement/unicorn before being useful
Currently fold can work in two modes: folding between a target revision and ".", or given an explicit set of revisions, fold this set into a single revision. The current UI for this is weird: for the first mode you specify revisions without --rev and the second mode you specify them with --rev. This UI is inconsistent with the rest of Mercurial. We have several examples of commands that take revisions with or without a --rev argument, and in all these cases, the behaviour is the same, and the --rev specifier is just optional:
- strip
- update
- export
Jordi has proposed patch to address this that treats revisions with and without --rev the same way and obtains both kinds of behaviours depending on whether a single or multiple revisions are specified. However, this has other problems. With certain revsets, it may not be easy to know in advance how many revisions are actually in the revset, so it would be surprising to get different behaviour depending on the number of revisions.
How to solve this?
Behavior
Automatic "hg evolve" call
This sub section need rework/splitting/movement/unicorn before being useful
no decision are will be made on this any time soon, concider using your brain power elsewhere.
Many evolve commands produce unstable changesets. Should they immediately call hg evolve by default?
1. pros
- Most (?) of the time, hg evolve will work without problems.
- Nicer for the user for the magic to happen automatically by default
2. cons
- Makes the user immediately handle instability
This is a very serious downside. Currently, there is no way at all to cancel a merge conflict. Once you are in this state, you are stuck and have to do a serious biopsy. Agreed, we should absolutely not do this by default, nor have a config option. I'm ok with an hg commit --amend flag that does this for you automatically though. -- sid0
- If you need to amend multiple changeset, you'd be stuck having to do multiple back-and-forth updates.
This is also concerning. This is O(N^2) work rather than O(N) that incremental hg evolve runs allow. -- sid0
- Letting the user decide when to deal with rebases and merge conflicts might be nicer.
Perhaps ui.autoevolve option? On by default? Off by default?
I think auto evolve makes sense in some cases. For example, say you amend a commit with descendants and only change the commit message. Why wouldn't you want auto evolve in that scenario? -- indygreg
I think the "there are now troubled commits message" should be actionable. Currently it just prints the count of troubled commits. I'd really like to see a "run hg evolve to stablize" message. If we don't auto evolve, at least we can tell the user what they should probably be doing next. -- indygreg
Use Cases
1. Undoing an amend
Users will often accidentally amend a commit. We need a good story to undo them.
This mean changing the commit content, but not touching the working directory. The hg uncommit command is already responsible for this action.
Growing a was to easily call uncommit on the precursor intead of the parent would fit that need:
hg uncommit -r 'precursor(., 1)'
hg uncommit --precursor
hg uncommit -P
(Git have a git reset HEAD@{1} notation for this. However, introducing a git-reset like command in Mercurial is a non-goal)
Pain Points
1. Evolve can "stabilise" to unstable destination
1.1. Situation
Start with a linear graph:
and amend 1 and 3 to create aa' and bb'. This gives us this graph:
The red changesets are marked as obsolete, and the orange changesets are thus troubled. Starting from bb, getting this repo back into an untroubled state takes 6 calls to 'hg evolve', the last 4 of which need --any.
1.2. Explanation of the current behavior
This happens because evolve first started to rebase c and cc on B. After that it asked to --any to start evolving B, BB' and C' and CC' over aa'.
The shortest path to stabilization would have been to take care of B and BB' first then directly evolve C and C1.3. Possible improvement
The fact that hg evolve think evolve B is unrelated to BB' (then requires --any) sounds wrong too.
Both point can be fixed if we make evolving ancestors "relevant to the context" (not requires any).
(This case is not a valid case in favor of hg evolve --all)
2. The obsolete history is not very usable
In order for evolve to achieve its full potential the hidden history that that evolve creates must be not only useful for enabling amending shared revisions but also _usable_ by the user to get back to old versions of a given revision (e.g. in case that the user is not happy with a later version of that revision).
Currently the obsolete history created by evolve is not very usable because the number of hidden, obsolete revisions created by evolve is greater than it should. In particular:
- Evolve creates "temporary amend commits" which basically doubles the number of hidden revisions that evolve creates. - Each history modification step creates its own set of obsolete revisions. There is no way to perform several history editing operations and combining those into a single operation. An alternative to this would be for evolve to provide tools to filter or show the obsolete history somehow.
3. Automatically evolve obsolete revisions when possible
The multi-step nature of evolve operations is a bit painful sometimes, particularly in cases where the necessary evolve --all step would be trivial. For example, at some point it might be nice to automatically detect meta-data only amend operations, and in that case automatically evolve the resulting unstable revisions (whose evolution should be trivial). Alternatively, there could be an --evolve flag for amend or some other way to trigger an automatic evolve when possible.
F.A.Q.
1. Why do we have a temporary commit after amend?
It is an implementation details that will eventually be removed