Understanding Mercurial Phase Semantics for Safe History Management
Mercurial's phase system (draft, secret, public) controls which operations are allowed on changesets, preventing accidental history corruption in shared repositories.
15 Oct 2025, 16:11 UTC

Understanding Mercurial Phase Semantics for Safe History Management
When working with shared Mercurial repositories, the line between safe experimentation and accidental history corruption can blur quickly. Mercurial’s phase system, introduced in version 2.1, provides a mechanism to distinguish between changesets that are still being worked on and those that should be treated as immutable. The key insight is that phases are not just labels—they actively govern which operations Mercurial will permit. Unlike some systems that rely solely on user discipline, Mercurial enforces phase rules during pushes and updates, making it harder to accidentally expose or corrupt shared history.
Every changeset in Mercurial carries one of three phases:
- Draft – The default phase for new commits. These changesets are considered mutable and can be rewritten, rebased, or amended. However, pushing draft changesets to a shared repository is restricted by default to prevent accidental exposure.
- Secret – Changesets explicitly marked as secret are never pushed, even if you force the push. This phase is useful for sensitive changes or work you want to keep local.
- Public – Changesets that have been shared with others. These are considered immutable, and Mercurial will refuse to rewrite them unless you explicitly override the safety checks.
How Phases Control Operations
The phase of a changeset directly influences what Mercurial allows. For example, attempting to push a draft changeset to a repository that already has the same changeset as public will be blocked. Similarly, rebasing a public changeset is prohibited unless you use the --force flag, which bypasses phase protections.
You can inspect the phases of changesets in your repository using:
$ hg phase --verbose
This command shows the phase of each changeset in your history. To change a changeset’s phase, use:
$ hg phase --public
$ hg phase --secret
A Practical Example: Managing Draft Work
Imagine you’ve created several local commits that you want to reorganize before sharing. Start by checking the current phases:
$ hg phase --verbose
changeset: 1
phase: public
changeset: 2
phase: draft
changeset: 3
phase: draft
If you attempt to rebase changeset 2 onto a newer base, Mercurial will allow it since it’s in the draft phase:
$ hg rebase --source 2 --dest .\n
However, if changeset 2 were already public, the same command would fail:
$ hg rebase --source 2 --dest .\nabort: cannot rebase public changeset 2
To safely reorganize public history, you must explicitly force the operation:
$ hg rebase --source 2 --dest . --force\n
The Trade-off: Flexibility vs. Safety
The phase system strikes a balance between flexibility and safety. On one hand, draft changesets can be freely rewritten, enabling experimentation without fear of breaking shared history. On the other hand, once a changeset becomes public, Mercurial treats it as immutable, protecting collaborators from unexpected changes.
However, this system relies on users understanding and correctly applying phase transitions. For instance, forgetting to mark a changeset as secret when handling sensitive data could lead to accidental exposure. Similarly, overzealous use of --force can undermine the safety guarantees the phase system provides.
Practical Recommendations
- Use
hg phase --secretfor any changesets containing sensitive information or experimental work you don’t want shared yet. - Before pushing to a shared repository, verify that your changesets are in the correct phase using
hg phase --verbose. - If you need to rewrite public history, understand that this is a team decision and should be coordinated with collaborators.
- Consider using the
evolveextension for more advanced history management workflows, which provides additional safety checks and commands likehg uncommitandhg prune.
In summary, Mercurial’s phase system is a powerful tool for managing shared history safely. By understanding the semantics of draft, secret, and public phases, and by using commands like hg phase and hg rebase correctly, you can work with confidence that your history modifications won’t unexpectedly disrupt your team’s workflow.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.