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). Phases are a part of the core Mercurial client code, enabled in any new client without preventing 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; as such, they're not permanent and leave no audit trail.

Phases are introduced in Mercurial 2.1. See the built-in help for details.

/!\ If you are new to phases you may want to read Introduction To Mercurial Phases first.

2. Available Phases

Phases are used to:

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









Phases split the history in a coherent set of changesets. Every changeset in a phase has an ancestor in a phase compatible with its phase. Compatible means an changeset's ancestors must at least have the same traits as the changeset itself, e.g.: a shared changeset always has shared ancestors and an immutable changeset always has immutable ancestors.

In other words the phase of a changeset is always equal to or higher than the phase of its ancestors, 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 movement from draft to public can happen on transferring changesets between clones. Secret changesets have to be moved explicitly (except for bundles specified with the --base option).

3. Phase Movements

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

On standard exchange commands, phases of changesets on both sides are compared. If phases on both sides are not equal, the lowest phase is chosen, e.g.: a changeset known as draft locally but public remotely is set to public locally, because public < draft in the phase hierarchy.

This update happens during standard exchange commands:

The real behavior is a bit more complicated than changesets on a remote repository are seen as public, but this is true for simple repository setups. If you need finer-grained behavior, consult the section on publishing repositories.

New changesets committed locally are in the draft phase, but some extensions (like mq) may create secret changesets and handle the move from secret to draft in some other way.

Consult the #upgrade_Notes section to check how phases will move the first time a new version of Mercurial touches an existing repository.

4. Command line interface

Phases are intended to be transparent for most users. People should not need to manually handle them and won't generally run into any behavior changes except to prevent common mistakes. Advanced users may want finer control over phase changes; this section describes how to change phases manually.

4.1. Core Command

The phase concept introduces a single new command: phase. This command will allow users to see and change phases of changesets.

$ 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 displays changeset phases when --debug is used.

All commands related to changeset exchange will ignore secret changesets, including:

A warning will be displayed when outgoing operation (outgoing, push, bundle) fails to push anything in the face of unsynchronized secret changesets.

no changes to push but 7 secret changesets

To see the changesets that are secret, use hg log -r "secret()". (The same searching can be done for public and draft statuses by searching for public() and draft() respectively)

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 changesets. When applying any of these extensions to a public changeset, an error will be thrown:

abort: revision 8184 is not mutable

4.3. Impact on cloning

If you have any secret changesets in your repository, then a local clone will be forced to use the relatively slow pull protocol, instead of the faster methods of making file copies or HardlinkedClones.

5. Publishing Repository

By default, any changeset exchanged over the wire protocol is set to public. Advanced users may want some other behavior; the publishing repository concept is designed for this purpose.

5.0.1. What is a "publishing repository"?

Setting a repository as "publishing" alters its behavior **when used as a server**: all changesets in the repository 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.

A repository is "publishing" by default. To make a repository non-publishing, add these lines to its hgrc configuration:

publish = False

Note: the "publish" property has no effects for local operations.

5.0.2. Old repository are publishing

Phase is the first step of a series of features aimed at better handling mutable history within Mercurial. Old clients do not support this feature and are unable to keep track of phase data. The safest solution is to consider as public any changeset going through an old client.

Moreover, most hosting solutions will not support phases 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 servers will advertise them as draft. Having publishing repository be 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".

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 Compatibility

Phase data are stored in a new file and do 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 work with the repository. This allows new client to store and handle phase related logic on **all repositories**.

6.2. Adding phase data to an old repo

There are a lot of repositories out there with plenty of changesets but lacking any phase data. When looking at such a repository, a new client will take the safe road and decide everything is 'public'. Some extensions register logic to tune this choice; for example, mq will set every changeset under its 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 "outgoing() and public()"

6.3. Touching a phased repo with an old client

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

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


Phases (last edited 2014-12-04 14:50:53 by KimRandell)