Mercurial Phases: Keep Experiments Local Before They Become Public
Mercurial phases classify commits as public, draft, or secret to prevent accidental history rewriting and premature pushes to shared repositories.
27 May 2026, 17:16 UTC

The problem: rewriting history your teammates already pulled
You finish a feature branch, run hg commit --amend to clean up a message, and Mercurial either blocks the change or—worse—lets you rewrite a changeset that a teammate already pulled. The next time they pull or merge, their repository diverges from yours, and you spend the afternoon untangling duplicate heads.
This is exactly the situation Mercurial phases are designed to prevent. Phases are a built-in safety mechanism that classifies every changeset as public, draft, or secret. The classification governs whether Mercurial will let you amend, rebase, strip, or push that changeset.
Public, draft, and secret: what each phase means
- Public: The changeset has been shared, or Mercurial treats it as shared. Local history modification is blocked to protect collaborators who may already have it.
- Draft: The changeset is local only and has not been pushed. You can amend or rebase it freely, but a normal push will mark it public on the remote side.
- Secret: The changeset never leaves your local repository during ordinary push or pull operations. Use this for experiments you do not want to share yet.
Phases have been part of Mercurial core for many years and are enabled by default in modern releases. They are workflow guards, not cryptographic controls, so a determined user can still bypass them.
Worked example: protect an experiment, then promote it
Run these commands in your Mercurial working copy. You need read and write access to the local repository; pushing additionally requires write access to the remote.
Check the current phase of your changesets:
hg phaseExpect each listed changeset to carry a phase label such as
public,draft, orsecret.Create a changeset for experimental work and mark it secret:
hg commit --secret -m "experimental refactor"Because it is secret,
hg pushwill not send it to a remote repository.Amend the secret changeset safely:
hg commit --amend -m "experimental refactor, cleaned up"Mercurial permits this because secret changesets are not protected from local editing.
When the work is ready to share, move it to draft:
hg phase --draftReplace
<changeset-id>with the identifier shown byhg phase.Push to the remote:
hg pushAfter a successful push, the changeset typically becomes public on the remote side. Run
hg phaselocally afterward to confirm the current labels.
Risk: Do not run hg phase --public on changesets your teammates have already pulled unless you have coordinated with them. Rewriting public history can invalidate their local work.
Limitations and practical checks
Phases are client-side workflow guards. They do not cryptographically prevent anyone from bypassing them, and older Mercurial versions or some hosting tools may interpret phase data differently. Advanced operations such as phase-aware rebase often require the evolve extension, which is not enabled by default.
Before you rewrite any shared history, run:
hg phase
If the changeset is public, assume other repositories already contain it and avoid hg commit --amend, hg rebase, or hg strip without team coordination. If it is draft or secret, local editing is generally safe.
Make phase checks a habit
Add hg phase to your pre-rewrite checklist. Use secret for experiments, promote to draft when you are ready to collaborate, and let a normal push move the changeset to public. That small habit keeps accidental history rewriting out of your shared repository.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.