Mercurial Changeset Evolution
Mercurial Changeset Evolution
Posted Apr 25, 2023 10:01 UTC (Tue) by farnz (subscriber, #17727)In reply to: Mercurial Changeset Evolution by kleptog
Parent article: Avoiding the merge trap
So the point of the distinction between "secret", "draft" and "public" is to prevent user error.
If you try to push a set of commits where one of them is secret (e.g. with the equivalent of git push origin HEAD), Mercurial will refuse and tell you which secret commits you tried to push. You have to use hg phase to change the secret commit to draft; similarly, someone pulling from your repo cannot pull secret commits until you use hg phase to make them draft.
Mercurial knows at the protocol level whether a remote branch is immutable or not - and will automatically convert commits from draft to public when they're pushed to an immutable branch. Similarly, if you pull from an immutable branch, it can include markers to tell you that a public commit obsoletes one of your draft commits, whereas if you pull from a mutable branch, it'll keep the commits as drafts.
You can always tell Mercurial that it's got it wrong with hg phase --force, and convert a public commit to a draft. Mercurial's revset language makes it relatively easy to script this, too, because you can define a revset that catches all the commits you're going to work with, and force their phase to draft.
There is, though, a different mindset between git and hg in this respect - git assumes that the user is infallible, and trusts you to never make a mistake. hg assumes that you're fallible, and expects to provide "safety rails" so that you can do your "normal" workflow without fear of doing something bad (like accidentally modifying a commit that's supposed to be immutable). But, like any good safety rails, hg provides ways for you to remove them - that's not going to be part of your normal workflow (you wouldn't do hg phase … && hg rebase … normally), but it's there for you if you need it.