Phases

1. Introduction

Phases improve safety of history rewriting and provide control over changesets exchanged among different repositories (read more). Phases are intended to transparently "just work" for most users (read more). It is part of Core and always enabled in any new client but doesn't prevent older clients from working on a repository (read more). Advanced users may decide to handle phases manually to provide finer control (read more).

Like bookmarks, phases are not stored in history and thus are not permanent and leave no audit trail.

Phases are introduced in Mercurial 2.1.

2. Available Phases

Phases are used to:

To achieve this, three phases share a hierarchy of traits:

immutable

shared

public

x

x

draft

x

secret

Phases split the history in coherent set of changeset. Every changeset in a phase have ancestor in a phase compatible with its phase. Compatible means an changeset ancestors have at least the same traits that the children changeset. eg: A shared changeset alway have shared ancestor and an immutable changeset always have immutable ancestors.

In other word the phase of a changeset is alway equal of higher that the phase of it's descendant. According to the following order:

A changeset is not expected to automatically move from a lower phase to an higher phase (eg: from public to draft) but automatic

3. Phase Movements

Phase movement are automatic and transparent and most user don't have to care much about them. The base rule is very simple:

On standard exchange commands, the phase of changesets on both side are compared. If differ the lowest phase is choosed. (eg: a changeset known as draft locally but public remotely is set public localy. Because public < draft)

This update happen during standard exchange commands:

The real behavior is a it's a bit more complicated than changesets on a remote repository is seen as public, but this is true for repository keeping default . If you need a finer behavior, consult the publishing repository section.

New changeset committed locally are draft, but some extension like mq may create secret and handle the move from secret to draft automatically

Consult the #upgrade_Notes section to check how phase will move the first time a new version of Mercurial touch and existing repository.

4. Command line interface

The phase are intended to be transparent, for most user. People should not need to manually handle them and won't meet any behavior changes except to prevent common mistake.

But some people might want to have a fine control on their phase and manually handle them. This section describe how to do change phase and what is the exact impact on phase on common operation.

4.1. Core Command

The phase concept introduce a single new command: phase. This command will allow to see and change phases of changeset.

$ hg phase -r 8183::8186
8183: public
8184: public
8185: secret
8186: secret

$ hg phase -v --draft 8185
phase change for 1 changesets
$ hg phase -r 8183::8186
8183: public
8184: public
8185: draft
8186: secret

See the command documentation for details.

the hg log command display phase of changeset when --debug is used

All commands related to changeset exchange will ignore secret changeset. This applies to:

A nice message will be displayed when outgoing operation (outgoing, push, bundle) fails to push anything but there is unsynchronized secret changeset.

no changes to push but 7 secret changesets

Note that when using the --base option of bundle. Secret changeset are included.

4.2. Impact on extension(s)

Extensions that rewrite history like, MQ, rebase, collapse or histedit will refuse to work on immutable changeset. When trying to work with them on public changeset you are expected to meet the following error:

abort revision 8184 is not mutable

5. Publishing Repository

By default any changeset exchanged over the wire are set public. Advanced user may want a finer behavior. The Publishing repository concept is designed for this purpose.

5.0.1. What is a "publishing repository"?

Setting a repository as "publishing" alter its behavior **when used as a server**: all changesets are **seen** as public changesets by clients.

So, pushing to a "publishing" repository is the most common way to make changesets public: pushed changesets are seen as public on the remote side and marked as such on local side.

Note: the "publishing" property have no effects for local operations.

5.0.2. Old repository are publishing

Phase is the first step of a series of features aiming at handling mutable history within mercurial. Old client do not support such feature and are unable to hold phase data. The safest solution is to consider as public any changeset going through an old client.

Moreover, most hosting solution will not support phase from the beginning. Having old clients seen as public repositories will not change their usage: public repositories where you push *immutable* public changesets *shared* with others.

5.0.3. Why is "publishing" the default?

We discussed above that any changeset from a non-phase aware repository should be seen as public. This means that in the following scenario, X is pulled as public::

~/A$ cd ../B
~/B$ new-hg pull ../A # let's pretend A is served by old-hg
~/B$ new-hg log -r tip
summary: X phase: public

We want to keep this behavior while creating/serving the A repository with new-hg. Although committing with any new-hg creates a draft changeset. To stay backward compatible, the pull must see the new commit as public. Non-publishing server will advertise them as draft. Having publishing repository the default is thus necessary to ensure this backward compatibility.

This default value can also be expressed with the following sentence: "By default, without any configuration, everything you exchange with the outside is immutable.". This behaviour seems sane.

5.0.4. Why allow draft changeset in publishing repository

Note: The publish option is aimed at controlling the behavior of server. Changeset in any state on a publishing server will always be seen as public by other client. "Passive" repository which are only used as server for pull and push operation are not "affected" by this section.

As in the choice for default, the main reason to allow draft changeset in publishing server is backward compatibility. With an old client, the following scenario is valid::

~/A$ old-hg init
~/A$ echo 'babar' > jungle
~/A$ old-hg commit -mA 'X'
~/A$ old-hg qimport -r . # or any other mutable operation on X

If the default is publishing and new commits in such repository are "public" The following operation will be denied as X will be an immutable public changeset. However as other clients see X as public, any pull//push (or event pull//pull) will mark X as public in repo A.

6. Upgrade Notes

The important points to remember are:

6.1. Backward Compatility

Phase data are stored in a new files and does not alter any part of the existing mercurial repository format. This means that a new client can safely write phase related data without preventing an old client to works with the repository. This allow new client store and handle phase related logic on **all repository**.

6.2. Adding phase data to old repo

There are a lot a repository out there with plenty of changeset but yet any phase data. When looking at such repository, a new client take the safe road and decided everything is 'public'. Some extension register logic to tune this choice. For example, mq set every changeset under it's control as secret in this situation.

You can set all changesets not pushed to a repository in the draft phase again using:

hg phase --force --draft 'children(remote())'

6.3. Adding phase data to old repo

Beware that and old client won't be able to move phase when touching a repo.

(If you were looking for the developer oriented page: PhaseDevel)