On the behalf of Logilab I put a lot of efforts to include a new core feature named phases in Mercurial 2.1. Phases are a system for tracking which changesets have been or should be shared. This helps to prevent common mistakes when modifying history (for instance, with the mq or rebase extensions). It will transparently benefit to all users. This concept is the first step towards simple, safe and powerful rewritting mecanisms for history in mercurial.

This serie of three blog entries will explain:

Preventing erroneous history rewriting

History rewriting is a common practice in DVCS. However when done the wrong way the most common error results in duplicated history. The phase concept aims to make rewriting history safer. For this purpose Mercurial 2.1 introduces a distinction between the "past" part of your history (that is expected to stay there forever) and the "present" part of the history (that you are currently evolving). The old and immutable part is called public and the mutable part of your history is called draft.

Let's see how this happens using a simple scenario.

A new Mercurial user clones a repository:

babar@Chessy ~ $ hg clone http://hg.celesteville.com/palace requesting all changes adding changesets adding manifests adding file changes added 2 changesets with 2 changes to 2 files updating to branch default 2 files updated, 0 files merged, 0 files removed, 0 files unresolved babar@Chessy ~/palace $ cd palace babar@Chessy ~/palace $ hg log --graph @ changeset: 1:2afbcfd2af83 | tag: tip | user: Celeste the Queen <Celeste@celesteville.com> | date: Wed Jan 25 16:41:56 2012 +0100 | summary: We need a kitchen too. | o changeset: 0:898889b143fb user: Celeste the Queen <Celeste@celesteville.com> date: Wed Jan 25 16:39:07 2012 +0100 summary: First description of the throne room

The repository already contains some changesets. Our user makes some improvements and commits them:

babar@Chessy ~/palace $ echo The wall shall be Blue >> throne-room babar@Chessy ~/palace $ hg ci -m 'Add wall color' babar@Chessy ~/palace $ echo In the middle stands a three meters round table >> kitchen babar@Chessy ~/palace $ hg ci -m 'Add a table in the kichen'

But when he tries to push new changesets, he discovers that someone else already pushed one:

babar@Chessy ~/palace $ hg push pushing to http://hg.celesteville.com/palace searching for changes abort: push creates new remote head bcd4d53319ec! (you should pull and merge or use push -f to force) babar@Chessy ~/palace $ hg pull pulling from http://hg.celesteville.com/palace searching for changes adding changesets adding manifests adding file changes added 1 changesets with 1 changes to 1 files (+1 heads) (run 'hg heads' to see heads, 'hg merge' to merge) babar@Chessy ~/palace $ hg log --graph o changeset: 4:0a5b3d7e4e5f | tag: tip | parent: 1:2afbcfd2af83 | user: Celeste the Queen <Celeste@celesteville.com> | date: Wed Jan 25 16:58:23 2012 +0100 | summary: Some bedroom description. | | @ changeset: 3:bcd4d53319ec | | user: Babar the King <babar@celesteville.com> | | date: Wed Jan 25 16:52:02 2012 +0100 | | summary: Add a table in the kichen | | | o changeset: 2:f9f14815935d |/ user: Babar the King <babar@celesteville.com> | date: Wed Jan 25 16:51:51 2012 +0100 | summary: Add wall color | o changeset: 1:2afbcfd2af83 | user: Celeste the Queen <Celeste@celesteville.com> | date: Wed Jan 25 16:41:56 2012 +0100 | summary: We need a kitchen too. | o changeset: 0:898889b143fb user: Celeste the Queen <Celeste@celesteville.com> date: Wed Jan 25 16:39:07 2012 +0100 summary: First description of the throne room

Note From here on this scenario becomes very unlikely. Mercurial is simple enough for a new user not to be that confused by such a trivial situation. But we keep the example simple to focus on phases.

Recently, our new user read some hype blog about "rebase" and the benefit of linear history. So, he decides to rewrite his history instead of merging.

Despite reading the wonderful rebase help, our new user makes the wrong decision when it comes to using it. He decides to rebase the remote changeset 0a5b3d7e4e5f :"Some bedroom description." on top of his local changeset.

With previous versions of mercurial, this mistake was allowed and would result in a duplication of the changeset 0a5b3d7e4e5f :"Some bedroom description."

babar@Chessy ~/palace $ hg rebase -s 4 -d 3 babar@Chessy ~/palace $ hg push pushing to http://hg.celesteville.com/palace searching for changes abort: push creates new remote head bcd4d53319ec! (you should pull and merge or use push -f to force) babar@Chessy ~/palace $ hg pull pulling from http://hg.celesteville.com/palace searching for changes adding changesets adding manifests adding file changes added 1 changesets with 1 changes to 1 files (+1 heads) (run 'hg heads' to see heads, 'hg merge' to merge) babar@Chessy ~/palace $ hg log --graph @ changeset: 5:55d9bae1e1cb | tag: tip | parent: 3:bcd4d53319ec | user: Celeste the Queen <Celeste@celesteville.com> | date: Wed Jan 25 16:58:23 2012 +0100 | summary: Some bedroom description. | | o changeset: 4:0a5b3d7e4e5f | | parent: 1:2afbcfd2af83 | | user: Celeste the Queen <Celeste@celesteville.com> | | date: Wed Jan 25 16:58:23 2012 +0100 | | summary: Some bedroom description. | | o | changeset: 3:bcd4d53319ec | | user: Babar the King <babar@celesteville.com> | | date: Wed Jan 25 16:52:02 2012 +0100 | | summary: Add a table in the kichen | | o | changeset: 2:f9f14815935d |/ user: Babar the King <babar@celesteville.com> | date: Wed Jan 25 16:51:51 2012 +0100 | summary: Add wall color | o changeset: 1:2afbcfd2af83 | user: Celeste the Queen <Celeste@celesteville.com> | date: Wed Jan 25 16:41:56 2012 +0100 | summary: We need a kitchen too. | o changeset: 0:898889b143fb user: Celeste the Queen <Celeste@celesteville.com> date: Wed Jan 25 16:39:07 2012 +0100 summary: First description of the throne room

In more complicated setups it's a fairly common mistake, Even in big and successful projects and with other DVCSs.

In the new Mercurial version the user won't be able to make this mistake anymore. Trying to rebase the wrong way will result in:

babar@Chessy ~/palace $ hg rebase -s 4 -d 3 abort: can't rebase immutable changeset 0a5b3d7e4e5f (see hg help phases for details)

The correct rebase still works as expected:

babar@Chessy ~/palace $ hg rebase -s 2 -d 4 babar@Chessy ~/palace $ hg log --graph @ changeset: 4:139ead8a540f | tag: tip | user: Babar the King <babar@celesteville.com> | date: Wed Jan 25 16:52:02 2012 +0100 | summary: Add a table in the kichen | o changeset: 3:0d1feb1bca54 | user: Babar the King <babar@celesteville.com> | date: Wed Jan 25 16:51:51 2012 +0100 | summary: Add wall color | o changeset: 2:0a5b3d7e4e5f | user: Celeste the Queen <Celeste@celesteville.com> | date: Wed Jan 25 16:58:23 2012 +0100 | summary: Some bedroom description. | o changeset: 1:2afbcfd2af83 | user: Celeste the Queen <Celeste@celesteville.com> | date: Wed Jan 25 16:41:56 2012 +0100 | summary: We need a kitchen too. | o changeset: 0:898889b143fb user: Celeste the Queen <Celeste@celesteville.com> date: Wed Jan 25 16:39:07 2012 +0100 summary: First description of the throne room

What is happening here:

Changeset 0a5b3d7e4e5f from Celeste was set to the public phase because it was pulled from the outside. The public phase is immutable.

from Celeste was set to the public phase because it was pulled from the outside. The public phase is immutable. Changesets f9f14815935d and bcd4d53319ec (rebased as 0d1feb1bca54 and 139ead8a540f ) have been commited locally and haven't been transmitted from this repository to another. As such, they are still in the draft phase. Unlike the public phase, the draft phase is mutable.

Let's watch the whole action in slow motion, paying attention to phases:

babar@Chessy ~ $ cat >> ~/.hgrc << EOF [ui] username=Babar the King <babar@celesteville.com> logtemplate='[{phase}] {desc} ({node|short})\

' EOF

First, changesets cloned from a public server are public:

babar@Chessy ~ $ hg clone --quiet http://hg.celesteville.com/palace babar@Chessy ~/palace $ cd palace babar@Chessy ~/palace $ hg log --graph @ [public] We need a kitchen too. (2afbcfd2af83) | o [public] First description of the throne room (898889b143fb)

Second, new changesets committed locally are in the draft phase:

babar@Chessy ~/palace $ echo The wall shall be Blue >> throne-room babar@Chessy ~/palace $ hg ci -m 'Add wall color' babar@Chessy ~/palace $ echo In the middle stand a three meters round table >> kitchen babar@Chessy ~/palace $ hg ci -m 'Add a table in the kichen' babar@Chessy ~/palace $ hg log --graph @ [draft] Add a table in the kichen (bcd4d53319ec) | o [draft] Add wall color (f9f14815935d) | o [public] We need a kitchen too. (2afbcfd2af83) | o [public] First description of the throne room (898889b143fb)

Third, changesets pulled from a public server are public:

babar@Chessy ~/palace $ hg pull --quiet babar@Chessy ~/palace $ hg log --graph o [public] Some bedroom description. (0a5b3d7e4e5f) | | @ [draft] Add a table in the kichen (bcd4d53319ec) | | | o [draft] Add wall color (f9f14815935d) |/ o [public] We need a kitchen too. (2afbcfd2af83) | o [public] First description of the throne room (898889b143fb)

Note rebase preserves the phase of rebased changesets babar@Chessy ~/palace $ hg rebase -s 2 -d 4 babar@Chessy ~/palace $ hg log --graph @ [draft] Add a table in the kichen (139ead8a540f) | o [draft] Add wall color (0d1feb1bca54) | o [public] Some bedroom description. (0a5b3d7e4e5f) | o [public] We need a kitchen too. (2afbcfd2af83) | o [public] First description of the throne room (898889b143fb)

Finally, once pushed to the public server, changesets are set to the public (immutable) phase

babar@Chessy ~/palace $ hg push pushing to http://hg.celesteville.com/palace searching for changes adding changesets adding manifests adding file changes added 2 changesets with 2 changes to 2 files babar@Chessy ~/palace $ hg log --graph @ [public] Add a table in the kichen (139ead8a540f) | o [public] Add wall color (0d1feb1bca54) | o [public] Some bedroom description. (0a5b3d7e4e5f) | o [public] We need a kitchen too. (2afbcfd2af83) | o [public] First description of the throne room (898889b143fb)

To summarize: