Note:
This page is primarily intended for developers of Mercurial.
Default destination plan
A lot of Mercurial command as "default" behavior, some needs revisiting.
1. Default Update Destination
(we discuss the case without bookmark)
1.1. Current Behavior
Current default value for update is: max(branch(.))
1.1.1. Pure Consumer Case
If the user is just using hg pull and hg update this work fine.
#1 User is on branch foo,
#2 hg pull bring new changeset in branch foo,
#3 hg update bring the user on the latest (just pulled) changeset on foo.
hg update updated working copy content to latest version, mission accomplished.
1.1.2. Consumer Case: pulling multiple heads
#1 User is on branch foo,
#2 hg pull bring multiple heads in branch foo,
#3 hg update bring the user one of the head.
user got only half of the pulled changesets
used head is "arbitrary"
No warning about the user heads
(<!>, pulling multiple heads on a branch point at FeatureBranchesStruggle or advanced usecase/users)
1.1.3. Producer Case: simple
#1 User is on branch foo, with some own local changesets on branch foo
#2 hg pull bring new changeset in branch foo,
The pull commend mention that a new head is created.
#3 hg update refuse to update for "non-linear update"
This prompt the use toward doing a merge
The message is not quite explicit about that
Message is not issued if Y is created after the pull (quite common, if pulling with uncommitted change)
hg update --clean will happily move to D without any message
1.1.4. Producer Case: pulling multiple heads
#1 User is on branch foo, with some own local changesets on branch foo
#2 hg pull bring new changeset on the same topological branch and another new heads,
(could also be achieved with use have X, Y locally but went back on X for some reason before the pull)
The pull commend mention that a new head is created.
#3 hg update refuse to update for "non-linear update"
This prompt the use toward doing a merge
The message is not quite explicit about that a merge
Merging will not reduce the number of heads becase we are not a head
hg update --clean will happily move to D without any message, actually 'updating backward' our current working copy.
if Y existed before the pull, hg up would have brought us on Y.
1.2. Analysis
hg update moving to branch head: is a sensible default. Named branch denote a meaningful context/target/topic/product and hg update getting the most up-to-date content for that context.
complains about non-linear: one of the interresting side effect of the complains about non-linear update is that in the common very basic operation, it help the user to spot that three is multiple heads and that something is to be done. However, the message are very bad at pointing this and there is a significant number of cases were this won't point it out.
ignoring other lower heads: hg update while on max(branch(.)) will simply says "nothing to update" ignoring all the other unmerged heads on the branch.
behavior change with --clean: The behavior change (allowing non linear update) seems very debatable. While the initial motivation is probably that merging uncommitted change from on head to another was technically impossible in early ages, this fit badly in the logical framework for point (1) and (2). It also make the command less consistent.
1.3. Behavior Change Proposal
There is multiple tier of change we use to improve the situation:
1. {x} Improving not a linear update message to mention heads and merge (waiting to be implemented).
2. Adding warning message to update that end on a head when there is other heads on the branch.
3. Having update destination become max(branch(.) and .::) as warning added in (2) provide the same usefulness as the non-linear abort.
4. Abort is there there is more than one possible destination heads (probably too radical)[REJECTED]
2. Default Rebase Destination
(we discuss the case without bookmark)
2.1. Current Behavior
Current default value for update is: max(branch(.))
2.1.1. Optimal case: pull things and rebase
#1 User is on branch foo, with some own local changesets on branch foo
#2 hg pull bring new changeset in branch foo,
The pull commend mention that a new head is created.
#3 hg rebase move current local branch on newly pulled changesets
local changed, rebased on remote change: mission accomplished.
This is the hg pull --rebase case.
2.1.2. Optimal case: pull things, commit and rebase
#1 User is on branch foo, with some own local changesets on branch foo
#2 hg pull bring new changeset in branch foo,
The pull commend mention that a new head is created.
#3 user commit his changes
#4 hg rebase says "nothing to rebase"
(Latest commit in the branch in working directory parent and default target.)
There is another obvious candidate for rebase.
2.1.3. Optimal case: pulling multiple heads and rebase
#1 User is on branch foo, with some own local changesets on branch foo
#2 hg pull bring multiple heads in branch foo,
The pull commend mention that a new head is created.
#3 hg rebase silently pick a branch as destination.
- Last pulled commit was 'F' (because reasons…),
case was ambiguous, it should have aborted like merge.
2.2. Analysis
Rebase default destination is likely as it is to prevent possible issue with rebasing "public" changeset (from the pre-phases era). As it is:
hg pull && hg rebase will likely do the right and safe thing (local producer case).
- anything will probably refuse to work
However we now have phase, that prevent user to rebase bad things
The current destination has some obvious issues:
- Fails to spot the other single head we just pull before comitting,
- silently pick an "arbitrary" head when multiple are available.
3. Merge behavior
- {x} We want merge to print a warning, when not reducing the number of heads.
3.1. Changes Proposal
Rebase semantic is very similar to merge semantic. We could and should share the same logic for default destination:
If there is just one head → nothing to merge/rebase
If there is one other head, merge/rebase with it.
If there is more than one other heads, refuse to pick and ask for explicit
- target.
4. Progress
((./) done, in progress, Need to be done)
extra default destinations into their own functions,
make the report/failure logic optional,
expose default destination as revsets,
rework default update destination,
rework default rebase destination,
rework default merge destination,