RFC: Phase UI (revset, phase command and others)

Gilles Moris gilles.moris at free.fr
Tue Dec 27 16:22:12 CST 2011


On Tuesday 27 December 2011 12:11:12 am Pierre-Yves David wrote:
> This email talks about phase and assumes reader are familiar with this new
> concept.  You can find more informations about this new concept in the wiki
> page, previous discussion and module documentation related to phase.
>
> wikipage: http://mercurial.selenic.com/wiki/StatesPlan
> module:   http://selenic.com/hg/file/3bcfea777efc/mercurial/phases.py
>
> This email aims to sum up the current decision about phases impact on the
> ui and to suggest solutions for area yet undecided.
>
>
> Phase name
> ============
>
> The current naming scheme is:
>
>            immutable shared
>    public:     X        X
>    draft:               X
>    secret:
>
> The two rules leading to such scheme are:
>
> 1) Thou shalt not pick phases name whose initial clash with each other.
>    (eg: no Public/Private)
>
> 2) Thou shalt not pick phases whose initial clash with '--force' or
> '--rev'. (eg: no frozen )
>
> Multiple people express enthusiasm for using "private" instead of "secret".
> I prefer "private" too but we need a valid replacement for "public" to
> avoid initial clash. Anyone with an idea brilliant enough to convince Matt
> should speak quickly.
>
>
> Phase Appearance In UI
> ======================
>
> Data related to phase will appear in several places:
>
> Changesets Log
> -----------------
>
> hg log output will include phase name for changeset not in the public
> phase.
>
>    changeset:   15781:2ebe3d0ce91d
>    branch:      stable
>    user:        FUJIWARA Katsunori <foozy at lares.dti.ne.jp>
>    date:        Fri Dec 16 21:09:41 2011 +0900
>    summary:     i18n: use encoding.lower/upper for encoding aware case
> folding phase:       draft
>
> This also applies to other commands with similar output
>
> On the template side, {phase} and {phasestr}  keyword can be used to
> display phase number and phase name of a changeset.
>

I don't think we should expose the numerical phase number.
I feel this is more a detail of implementation that shall be hidden from the 
user.

Moreover, I would renumber phases from 0,1,2 to 10,20,30 or similar to allow 
some spare numbers if adding intermediate phase is needed (as suggested below 
in solution A).
If you don't want to renumber, making those numbers private could allow a 
future renumbering under the hood.

> Phase Movement
> --------------
>
> The user will be informed of phase movement the same way changegroup
> addition are notified (check last line):
>
>    % 22:31 marmoute at yamac ~/src/pylint > hg pushing
>    real URL is http://hg.logilab.org/pylint
>    pushing to http://hg.logilab.org/pylint
>    searching for changes
>    adding changesets
>    adding manifests
>    adding file changes
>    added 60 changesets with 173 changes to 314 files
>    90 changesets changed phases
>
> more verbose output may provide additional information:
>
>    90 changesets changed phases
>    73 changesets moved to public phase
>    17 changesets moved to draft phase
>
> This applies to any command changing the phase of changesets.
>
> Extension
> -----------
>
> Extensions rewriting history will refuse to work on immutable changeset:
>
>    abort: Can't rebase immutable changeset e1c4361dd923
>    (see hg help phases for details)
>
> Impacted core extensions are: mq and rebase
>
> revset
> -------
>
> revset to select changeset according to their phase will be implemented.
>
> The naive solution is:
>
>    public()     match changeset in public phase.
>    draft()      match changeset in draft phase.
>    secret()     match changeset in secret phase.
>
> But in practice we want to be able to do more complicated queries:
>
>    * "Match all changeset at least draft" --> (draft() + secret())
>    * "Match all changeset at most draft" --> (draft() + public())
>
> There are multiple options to achieve this.
>
> Solution A: add more revset symbols
> ```````````````````````````````````````````````````
>
> Adding "exchanged()" and "mutable()" should do it.
>
> pro:
>   * simple to use
> con:
>   * multiplies symbols
>   * Does not scale well if we add phases
>
> Solution B: add argument to revset
> ``````````````````````````````````````````````````
>
> We add an "operator" argument to revset to control how it should be
> interpreted:
>
>    Match any changeset in phase draft or lower --> "draft('<=')"
>
> Possible values are '<', '<=', '='(default), '>=', '>'.
>
> pro:
>    * keep simple usage simple
>    * cover most things people will want to express (except phase between X
> and Y) cons:
>    * complicated usecase are a bit more complicated
>
>
> Solution C: Use a single symbol
> ``````````````````````````````````````````````````
>
> We can use a single "phases" revset taking a "phase-set" in argument:
>
>    match changesets in draft phase --> phase('draft)
>    match changesets in draft phase or lower --> phase('<=draft)
>    match changeset between public and secret phase --> 
> phase('public::draft')
>
> pro:
>    * Add less symbol
>    * everything is done using the same symbol
>    * complex case are simpler to express
>    * cover any complicated case people might want
> cons:
>    * Make simple case more verbose
>

Slightly prefer solution C as it is explicit.
In particular "phase('public::draft')" because it is consistent with revsets.
Anyway, revsets already have some aliases like author/user, so a mix of 
solution A and C shall be possible.
>
> Automatic phase movement
> ========================
>
> Push/Pull:
>
>    Pull and push Synchronize phase with remote side
>
>    Pushing to publishing server makes changesets public
>
> mq:
>
>    changeset handled by mq are secret.
>
>    qnew and qpush create secret changeset
>
>    qimport moves changeset into secret phase
>
>    qfinish moves changeset into draft phase if they do not have secret
> parent (small chance of error here)
>
> Tag:
>
>    Current history rewriting extension does not handle tag.
>
>    As suggested by Matt during 1.9 sprint, hg tag should make changeset
> public.
>
> Rollback:
>
>    Restore phase to they state prior last revlog transaction (as for
> bookmark)
>
>
>
> Phase command
> =============
>
> Phase of changeset can be manually altered with the "hg phases" command
>
> hg phases [-C|-p|-d|-s] [-b|-e] [revset]
>
> set or show phase of changeset
>
> If no revset is provided, it applies to the current working directory
> phase.
>
> options:
>
> -p --public   Set target into public phase
> -d --draft    Set target into draft phase (or leave it in lower phase
> (public)) -s --secret   Set target into secret phase (or leave it in lower
> phase (draft and public))
>
>
> -b --backward reverse the logic, phase are left in upper phase, not lower
> -e --exact    all target changeset are exactly set in the specified phase
>
> -C --clear    reset next commit phase to default (max of parent phase and
>               phases.new-commit option)
>
>
> Exact help text is to be tuned to remove the confusing lower//upper phase
> stuff.

I am quite confused with the command, in particular because the essential 
rule "A child changeset can not be in a lower phase than its parents" is not 
expressed in the help. Changing phase in an ancestor can change phase in the 
descendants.
So I think that "--exact" may probably be the default and only behavior for 
the time being, as the lower/upper/backward makes it more (too much?) 
complex.

Regards.
Gilles.



More information about the Mercurial-devel mailing list