Experimental implementation of liquid-hg

Pierre-Yves David pierre-yves.david at ens-lyon.org
Tue Jan 18 18:43:32 CST 2011


On Tue, 2011-01-18 at 20:04 +0100, Matt Mackall wrote:
> On Tue, 2011-01-18 at 19:38 +0100, Pierre-Yves David wrote:
> 
> > The *liquid* extension is integrated with mq:
> > 
> > * Changesets created by ``qpush`` or ``qnew`` are *liquid*.
> > * Changesets imported with ``qimport -r`` are *liquefied*.
> 
> I think this is the wrong semantic. "Frozen" should correspond to
> "published", which means that mq and rebase and the like should refuse
> to operate on them at all (at least without a big ugly force switch).
> The whole point of liquid is for people to avoid accidentally modifying
> or deleting or rebasing publicly-visible changesets.
> 
> > * Changesets left by ``qfinish`` are frozen if possible (when ``qbase`` is *frozen*)
> 
> And this is similarly not quite right. It's the act of pushing a
> changeset to a public repo that should freeze it. Changesets that are
> local only should remain liquid indefinitely.

I think we mostly agree on the goal of liquid changeset. In order to not change
too much stuff at the same time I was a bit shy for the semantic of this
experimental implementation. As we seems to share most vision on liquid. I'll
propose a more ambitious semantic.

I think we agree on the two following statements.

    (1) Man *CAN NOT* use any history editing commands on "Frozen" changeset.
        (You shall only edit *liquid* changeset)

    (2) Any changeset you published *MUST* be frozen.
        (Liquid changeset are meant to be local only)

Therefore I think that every body will agree that.

    (A) Commit are created "liquid". (This apply only to commit you create locally).

    (B) Send liquid changeset to any "Public Place" should freeze them.

We need to decide the following topic:

    - How to define "Public Place" ?

    - Are the liquid changeset from elsewhere liquid ?

    - Are liquid changeset push by default ?

    - What are the ways to freeze a changeset ?

    Each pairs of questions are highly entangled.

How to define "Public Place" ?
================================

The whole idea is to prevent user to mess up with change they have already
shared with the rest of the world. Then every changeset shared with the rest of
the world should be "Frozen". However, as mercurial is a *Distributed* Version
Control System it's difficult to know when a changeset is shared with the rest
of the world. Here is some examples:


* I use ``hg bundle`` to backup some changesets before getting rides of them and
  store the bundle in a "I'll probably never need them but let's keep them in
  case of need" directory.

    I **do not publish** my changeset with ``bundle``.

* I my home internet connection dropped. I use ``hg bundle`` to export my work
  and carry them with a usb dongle to another machine with internet connection.

    I **do publish** my changeset with ``bundle``.

* I use ``hg push`` to send my changeset to the central repository of my company.

    I **do publish** my changeset with ``push``.

* I use ``hg push`` to send my changeset to a continuous integration server that
  will run some test with them, send me a report before discarding them.

    I **do not publish** my changeset with ``push``.

* I use ``hg push`` to send my changeset to a temporary virtual machine for some
  validation.

    I **do not publish** my changeset with ``push``.

* I use ``hg push`` to send changeset from a "branch clone" to my main one.
  Then rm the branch clone.

    I **do not publish** my changeset with ``push``.

In this example we see that we can use ``push`` and ``bundle`` to both
*publish* and *not publish* changeset.

My conclusion is that detecting use of push/bundle doesn't ensure that changeset are published.

I see two solutions:

Public-1
`````````

    push/bundle freeze any changeset exported changeset.

    Add  "--no-freeze" option to bundle/push. When this option is present,
    push/bundle doesn't freeze exported changeset

    Add a "no-freeze-destination" (or "private-destination") option in the
    "liquids" section to store destinations that have --no-freeze turned on by
    default:

        [paths]
        vm1=ssh://192.168.18.42/myproject/
        test=ssh://selenic.com/pushtest/
        babar=../babar-main/
        [liquids]
        no-freeze-destination=test, vm1, babar

Public-2
``````````````

    Liquid changeset are not include in push/bundle by default.

    ("""42 liquids changeset ignored. Use "hg freeze" to freeze them or use the
    --freeze option of push""" warning should be added for confused user)

    Add a --freeze option to push? If this option is present liquid changeset
    are included in the push and exported changeset are frozen.

    The``hg freeze`` command allow to freeze changeset. By using this command
    you say "I'll not touch this changeset again and I want it to be shared"

    You can push changeset that are still liquid by both specify an explicit
    changeset-hash/bookmark to push and use the --force option. Changeset
    pushed this way are not frozen.


    This solution is more explicit but introduce a huge change in behaviour for
    standard usage of mercurial. A series of commit followed by a push won't
    push those commit.


I would prefer Public-1 as this solution doesn't introduce change in basic
usage of mercurial. I also feel it more natural.

Bonus questions
````````````````
(Bonus-1) how to handle pull based publish ?

    I have no simple idea.

(Bonus-2) What to do when local frozen changeset are descendants of liquid changesets on the remote side ?

    1) Freeze liquid ancestors of local pushed changesets.
    2) Add local changeset as liquid descendants of the liquid remote.
    3) Reject the push and require --force to push (freezing remote liquids).
    4) Reject the push and require --force to push (adding changesets as liquids).

I would reject solution 2 and 4, if you already have those liquids changeset
they should have already been frozen on the remote.  I would lean toward (1).
Freezing them is logic as you already have a frozen copy and adding more
"reject behaviour" is frustrating from the user point of view. (2) is more
explicit but less logic and more frustrating.

Are the liquid changeset I get from elsewhere "liquid" ?
========================================================

Problem we had with pull/bundle also applies to pull/unbundle.

* I unbundle a local backup of unpublished changesets:
  -> the changegroup are liquid

* I unbundle a bundle of official changesets:
  -> the changegroup are frozen

* I pull from a branch clone:
  -> the changegroup are liquid

* I pull from the official repository:
  -> the changegroup are liquids

In this example we see that we can use ``pull`` and ``unbundle`` to add both
"published" and "unpublished" changesets.

My conclusion is that detecting use of push/bundle does ensure that changeset
are published.

I can't see any sane and simple solution other than the Public-1 approach:

    pull/unbundle add "frozen" changeset by default.

    Add  "--liquid" option to pull/bundle. When this option is present,
    pull/bundle add "liquid" changesets.

    Add a "no-freeze-source" (or "private-source") option in the
    "liquids" section to store source that have --liquid turned on by
    default:

        [paths]
        babar-featureA=../babar-featureA
        babar-featureB=../babar-featureB
        [liquids]
        no-freeze-source=babar-featureA, babar-featureB

Using Public-1 for pull is an argument in favor of Public-1 for push.


Bonus questions
````````````````

What do you do when pulled changeset apply local liquids ?

    (1) make pulled changeset liquid assuming this changegroup come from a local backup.
    (2) Freeze local liquids.
    (3) Reject the pull and required either the use --liquid option to add then
        as liquid or --force to freeze your local changesets

(1) Is probably wrong (increase inconsistency created pull based publish).
(2) Is a bit too implicit for my taste.
(3) Is my preferred solution.


Are liquid changeset push by default ?
======================================

As I already said not pushing liquid changeset by default would introduce a
huge change in behaviour that we probably doesn't want. Moreover requiring the
user to explicitly freeze changeset will complexity the mercurial UI (think
about the git index). One of the hg strength is it's simplicity.

However implicitly pushing liquid changeset will lead to premature publishing
in progress changeset for people who use extension that edit they history. I'll
then promote the inclusions of a "strict-local" option in the "liquid" section.
If this option is set to True, liquid changeset won't be published by default.
You either have to freeze them explicitly or to use the --freeze option of
pull/bundle.

This solution allow advanced used to choose what is to be published while keeping
mercurial simple for standard user.

What are the ways to freeze a changeset ?
========================================================

Do we want push/bundle(pull/unbundle) to be the only command that freeze
changeset or do we introduce a "freeze" command that allow to explicitly mark a
changeset as frozen ? (the freeze command better have some rollback support).

The solution I promote for the three other questions would benefit from a
``freeze`` command. However, standard user better have to be able to use
mercurial without it.




Do think about other solution I may have forget or other issue I may have
missed ? What solution do you prefer for the final implementation of liquid ?

--
Pierre-Yves David

ps: I'm very happy to see the liquid topic moving forward.


More information about the Mercurial-devel mailing list