Keep Unfinished Mercurial Commits Out of Pushes with Phases
Prevent unfinished Mercurial changesets from reaching your team by using draft and secret phases before you push.
23 Oct 2026, 08:37 UTC

The problem: an unfinished changeset reaches the shared server
You commit a half-finished experiment in Mercurial, then run hg push to send a separate, finished fix. Depending on server configuration, Mercurial may push the experiment along with the fix. Your teammates now see broken code in the shared history, and someone may build on it before it is ready.
The practical response is to label unfinished work with Mercurial Phases before pushing. Phases are per-changeset labels that control what leaves your clone: draft work is held back from explicit pushes by default, secret work never leaves your local repository through normal commands, and public work is eligible for sharing.
How the phases behave
- draft: the default phase for new local commits. Mercurial does not push draft changesets when you push a specific revision, and many servers reject draft publication.
- secret: stricter than draft. Secret changesets are hidden from
hg outgoingandhg push, so they cannot be shared accidentally through normal commands. - public: ready for the shared repository. This is the phase Mercurial pushes.
Moving a changeset from draft to public is explicit. Mercurial 2.1 and later support phases, and the transition is intentional rather than automatic.
Worked example: push only the finished fix
Run these commands in a local terminal inside your Mercurial repository. You need write permission to the repository directory.
hg init example-repo
cd example-repo
# Finished change
echo "ready" > ready.txt
hg add ready.txt
hg commit -m "finished fix"
# Unfinished change; new commits are draft by default
echo "experiment" > wip.txt
hg add wip.txt
hg commit -m "work in progress"
# Inspect phases before sharing anything
hg phase
# Promote only the finished changeset. Replace the placeholder with the
# changeset number or hash of the finished commit.
hg phase --public --rev <revision-of-finished-fix>
# Push only that changeset and its ancestors
hg push --rev <revision-of-finished-fix>
After hg phase, the finished commit should show as public and the experiment as draft. Pushing by revision sends only the finished changeset and its ancestors; the draft experiment remains local unless you explicitly push it.
Risk: promoting the wrong changeset with hg phase --public makes unfinished work eligible for sharing. Running hg push without --rev may send draft changesets depending on server configuration. Review hg log before changing any phase.
Limitations and verification
- Not all Mercurial clients or extensions honor phases, so a teammate using older tooling might still observe draft changesets if they pull directly from your clone.
- Phases do not replace code review. A public changeset can still contain defects.
- Server configuration matters. If the server does not enforce phase checks, draft changesets can be published on the shared repository even if you did not intend to share them.
Practical check: after pushing, run hg phase locally and confirm the experiment is still draft. On the server, run hg log --rev <revision-of-experiment>; the changeset should not appear in the shared repository history.
Closing
Commit experiments without promotion, make hg phase part of your pre-push routine, and treat phase labels as a safety net rather than a guarantee. If your team uses multiple Mercurial clients, agree on which tools respect phases before relying on them.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.