Diagnosing Mercurial 'push creates new remote heads' and multi-head divergence
Push aborts with 'push creates new remote heads'? Run read-only checks for heads, phases and incoming/outgoing, then choose merge, close-branch or local rewrite. Know when to escalate.
20 Apr 2026, 03:48 UTC

Recognizable condition
The push aborts with:
abort: push creates new remote heads on branch 'default'or another named branch. The working directory is clean according to hg summary, yet hg heads shows more than one head for the same branch. After a pull you may also see hg heads list two tips while your local branch name is unchanged.
Takeaway: Mercurial is refusing to create a second tip on the remote. The repo already has a head you do not have locally, or you have diverged from a head that is already published.
Cause to symptom table
| Condition you see | Typical cause | Diagnostic hint |
|---|---|---|
| push aborts, heads = 2, both heads draft | Two clones committed in parallel on same branch | hg outgoing shows your changesets, hg incoming shows theirs | push aborts, one head public, one head draft | Local amend/rebase/histedit/rollback rewrote history another clone already has | hg phase -r <rev> differs between heads | heads = 2 with unrelated roots | Pull from unrelated repository with --force | hg log -G -r "head()" shows two roots, no common ancestor | heads = 2, working directory shows merge in progress | Merge started but never committed | hg summary reports "merging" and hg heads shows pre-merge tip |
Read-only checks in order
Run all checks in a scratch clone first: hg clone -U <repo-url> /tmp/diag. No write permission needed.
Branch and phase state
Run in repo root. Requires read access.hg summaryNote current branch, parent revisions, and phase. Phase is draft/public/secret. Public means the changeset is considered published.
List heads
hg headshg log -G -r "head()"Expected check: one line per head. Record the node ids and branch names.
What would cross the wire
hg outgoing <remote>hg incoming <remote>These show exactly which changesets would be pushed or pulled. No changes made.
Phase of each head
hg phase -r <head-rev>Run for each head. Draft heads can be rewritten locally. Public heads cannot be safely removed from a publishing remote.
Repository integrity
hg verifyRun after any crash or lock error before any fix.
Confirm extensions are enabled: hg debuginstall. Evolve, rebase, and strip are bundled but not enabled by default. Phase defaults and flag names vary across Mercurial 4.x/5.x/6.x.
Pick a fix based on findings
Both heads are published or remote is publishing
Default correct answer. Preserve both histories.
hg pull -uhg merge <other-head>hg commit -m "merge divergent heads on <branch>"hg pushRisk: merge conflicts must be resolved. Requires write access to the repo. After push, hg outgoing should report no changesets and hg heads <branch> should list one head.
One head is intentionally abandoned
Close the branch rather than deleting changesets.
hg update <abandoned-head>hg commit --close-branch -m "close abandoned head"hg pushThe head disappears from hg heads but changesets remain for audit. Only do this if no other clone depends on that head.
Local head is draft and should supersede remote work
Rewrite locally, do not duplicate.
hg update <local-draft-head>hg rebase --dest <remote-head>Or with evolve: hg prune / hg fold. Keep a bundle before rewriting: hg bundle -a /tmp/backup.hg.
Force-push is last resort: hg push -f. It only succeeds when the remote is non-publishing and the changesets are not public. On a publishing repository phases become public and force-push is blocked, which is a signal to merge instead.
Cautions: hg rollback undoes only the last transaction and can discard committed work; never run it on a shared repository without a backup. hg strip and hg prune discard changesets from the local repo. Do not delete .hg/store/lock by hand; use hg recover for abandoned transactions.
Escalation criteria and safety limits
hg verifyreports damage.- Remote is publishing and force-push is refused.
- CI or other clones depend on the heads you would remove.
- Divergence involves secret-phase changesets or obsolescence markers you cannot explain.
- Second root from an unrelated repository. Clean recovery is usually re-cloning, not merging unrelated histories.
When escalating, provide the repository owner with hg heads, hg log -G -r "head()", phase output, and a bundle: hg bundle -a /tmp/repo-backup.hg. Do not rewrite shared history without a backup clone.
Verification after fix: hg outgoing reports nothing, hg heads <branch> lists exactly one head, and hg log -G shows a single line of descent for that branch.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.