Diagnosing Mercurial Push Failures Caused by Changeset Phases
Mercurial push failures and "can't rebase public changesets" errors usually trace back to the phase system. Learn to diagnose draft, secret, and public states and fix them safely.
04 Apr 2026, 19:15 UTC

You run hg push and Mercurial refuses, reports "no changes found" even though you have local commits, or a teammate cannot see changesets you thought you shared. In most cases the cause is not a network or permission problem — it is Mercurial's phase system silently classifying your changesets as not-yet-shareable. This guide shows how to recognize phase-related symptoms, diagnose which changesets are involved, and fix the state safely.
What phases are and why they block you
Every changeset in a Mercurial repository has one of three phases:
- draft — local work in progress. Drafts can be rewritten (amended, rebased, stripped) freely. They push normally to non-publishing repositories.
- secret — explicitly hidden. Secret changesets are never pushed or pulled, and other clones do not see them at all.
- public — shared and immutable. Mercurial refuses to rewrite public changesets without forcing, because collaborators may already have them.
The subtle part is publishing repositories. A repository with phases.publish = True (the default for normal clones) automatically marks everything it receives as public. A repository marked non-publishing (common for shared "integration" servers) preserves draft state, so changesets stay mutable after push. When your push target and your local repo disagree about this, you get confusing behavior: commits that stay draft on the server, or commits that became public locally and now refuse history edits.
Symptom-to-cause table
| Symptom | Likely cause | First check |
|---|---|---|
Push says "no changes found" but hg log shows local commits | Changesets are secret | hg phase -l 10 |
| Rebase or amend fails with "can't rebase public changesets" | Changesets became public, often after pushing to a publishing repo | hg log -r . -T '{phase}' |
| Teammate's clone is missing your pushed work | You pushed from/to a non-publishing repo; changesets stayed draft and a later operation ignored them | hg phase on the server repo |
| Push rejected by server hooks mentioning phases | Server enforces a phase policy (e.g., drafts not allowed on a release branch) | Server-side config / hook output |
Ordered diagnostic checks
Run these in your local working repository. All are read-only except where noted; no special permissions are needed beyond normal repository access.
- List recent phases. Run
hg phase -l 15. This prints the phase of the newest 15 changesets. Look forsecretentries you expected to share, orpublicentries you expected to still edit. - Check what a push would actually send. Run
hg outgoing. If it is empty but you have local commits, those commits are almost certainly secret —hg outgoingonly considers pushable (draft or public) changesets. - Check whether the remote is publishing. The remote's
hgrccontrols this. If you have shell access to the server, look forphases.publish = Falseunder[phases]in the repository's.hg/hgrc. Without access, infer it: push a throwaway draft commit, then check on the server (or via a fresh clone) whether it arrived as public or draft. - Confirm the exact changeset involved. Use
hg log -r REV -T '{node|short} {phase} {desc|firstline}\n'with the revision from the error message, so you are fixing the right commit rather than guessing.
Fixes matched to findings
Finding: changesets are secret and should be shared
Promote them to draft:
hg phase -d REV
Run this locally as the repository owner; replace REV with the revision number or hash. Verify with hg phase -l 5, then retry hg push. This is safe — it only changes local metadata until you push.
Finding: changesets are public but you need to rewrite them
First, stop and check whether anyone else has pulled them. If the changesets exist only on your machine and a backup, you can demote:
hg phase -d --force REV
The --force flag is required because moving backwards (public → draft) defeats the safety model. Risk: if collaborators already have these changesets, rewriting them after demotion creates divergent history that will produce multiple heads and painful merges for everyone. Only do this when you are certain the changesets have not propagated.
Finding: push target is non-publishing and drafts are piling up
This is often intentional (a review or staging server). If changesets should become public after review, an administrator can promote them on the server with hg phase -p REV, or the team can adopt a convention of promoting after merge. Do not "fix" this by flipping the server to publishing without team agreement — it changes behavior for every future push.
Finding: server hook rejects drafts on a protected branch
This is policy enforcement, not a bug. Either push to the designated draft/staging branch, or ask the repo administrator to promote your changesets after review. Do not work around it with --force on your side; the hook will still reject the push and you will have only complicated your local state.
Escalation criteria
Stop and involve your repository administrator or team lead when:
- You need
hg phase --forceon changesets that may exist in other clones — this is a history-integrity decision, not a solo fix. - The remote's publishing configuration is unknown or undocumented and your team's workflow depends on it.
- A server hook rejects pushes with phase errors you cannot map to any local state — the hook may reference server-side phase data you cannot inspect.
hg phase -loutput contradicts whathg outgoingreports, which can indicate repository corruption; runhg verifyand escalate rather than repair by hand.
Verifying the fix
After any phase change, confirm three things: hg phase -l 5 shows the intended state, hg outgoing lists exactly the changesets you expect to send, and a real hg push completes without phase-related messages. If you demoted anything with --force, also confirm with collaborators (or by checking shared clones) that no divergent copies exist before rewriting history.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.