Keep Your Experimental Code Hidden with Mercurial Phases
Learn how Mercurial’s phase system lets you commit unfinished work locally, promote it when ready, and avoid accidental exposure while keeping history clean.
31 Aug 2026, 01:54 UTC

Why Exposing Unfinished Code Is a Problem
In fast‑moving teams, developers often experiment on the same branch that others use for production. A single accidental push can surface incomplete logic, confusing reviewers and potentially breaking downstream work. Traditional approaches—creating a dedicated feature branch or using tags—add extra steps and can clutter history with merge commits.
Mercurial’s Phase Feature to the Rescue
Mercurial introduces a lightweight phase system with three states:
- draft – changesets exist only locally and are invisible to others.
- public – changesets are ready to share; they are sent to remote repositories.
- secret – changesets are hidden from any push and are not visible in
hg incomingorhg outgoing.
By default, new commits start as draft. You can later promote them to public with a single command, keeping the workflow simple and the history clean.
Step‑by‑Step Example
Assume you are working on feature fancy‑api in a shared repo repo‑main. You want to keep the work private until a code‑review session.
- Clone the repo locally (if you haven’t already):
hg clone https://example.com/repo-main my‑clone cd my‑clone - Make your changes and commit as draft:
hg add new_module.py hg commit -m "draft: add fancy API"The new changeset is automatically marked
draft. - Review locally (run tests, run
hg status, etc.) - Promote to public when ready:
hg phase --public .This marks the current working directory’s changeset, and any ancestors that are still
draft, aspublic. Only public changesets are sent when you push. - Push to the remote:
hg pushOnly the
publicchangeset(s) are transmitted. If you had anysecretchangesets, they would be ignored.
Verification: After the push, run hg log --template '{rev}:{phase} {desc}\n' on the remote clone to confirm that the changeset is marked public. On a fresh clone, hg incoming shows no secret changesets, proving isolation.
Automating Promotion with a Hook
To avoid forgetting to promote, add a prepush hook that automatically promotes the working directory’s draft changesets before pushing. Edit .hgrc in your home directory or the repo’s .hg/hgrc file:
[hooks]
prepush = hg phase --public .
Now every hg push will first run hg phase --public ., ensuring that only ready changesets leave the local repo. Remember, this hook runs locally; it does not affect remote repositories.
Trade‑Offs and Caveats
- Memory of Promotion: You must remember to promote. Draft changes that never get promoted remain local forever. Document the workflow in your team’s README.
- Immutable Public History: Once a changeset is public, you cannot edit it in place. Any fix requires a new changeset. If you mistakenly promote an incomplete commit, you’ll need to create a new commit that corrects it.
- Secret Phase Risks: Secret changesets are never pushed. If you clone the repo elsewhere while secret changes exist locally, those changes are lost to the new clone. Use
hg clone --pullonly after you’ve promoted all intended changes. - Phase Sync Across Repos: Phases are local metadata. Pushing a public changeset that has secret ancestors will fail. Always ensure secret changesets are not ancestors of public ones before pushing.
Practical Checklist
- Commit new work as
draft(default). - Run tests and review locally.
- Promote with
hg phase --public .or let theprepushhook do it. - Push and verify with
hg incomingon the remote orhg log --template '{rev}:{phase} {desc}\n'locally. - Document the phase workflow for new contributors.
Conclusion
Mercurial’s phase system gives you a clean, single‑command way to keep experimental commits from leaking into shared history. By committing as draft, promoting only when the work is ready, and optionally automating promotion with a hook, you reduce accidental exposure and keep your project history tidy. Just remember the pitfalls—public changes are immutable, and secret changes can be lost if not promoted before a clone. With a simple checklist, phases become a powerful ally in collaborative development.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.