Mercurial (as of 2.1) Now Has Phases
In my last post I pondered (ranted?) on the reluctance of Mercurial people to edit repository history, especially as compared to git people. Today I noticed that Mercurial 2.1 has been released, and it has a new feature that makes editing your local repository much safer, phases (more detail here).
To me this looks like a really cool idea. Phases explicitly mark changesets as either public (have been pushed or pulled, and should not be edited) or draft (still local to your repository and can be freely edited). Changesets are given a phase automatically behind the scenes (though you can override this, of course), and history editing tools respect phases so that now it is even harder to shoot yourself in the foot when editing your repository history with tools like rebase or mq.
There is also one more phase, secret, that can be enabled for use with patches in your Mercurial Queues. Secret changesets will not be pushed, pulled, or cloned (or even show up in the output of incoming or outgoing). That's a nice touch too.
I wonder if git will ever pick this idea up? Git users seem to already be pretty comfortable with history editing procedures, but I have also read (old?) debates about when it is a good idea and when it is definitely a bad idea to use rebase with git repositories. It seems like phases could clear up confusion in the git world too.
Comments
---
Phase movements are automatic and transparent; most users don't have to care much about them. The base rule is very simple:
"Any changesets seen in a remote repository are public"
---
Of course git would be the same.
If the Git developers were to implement a similar feature for treating public and private commits differently, I think Git would probably not explicitly keep track of the status of each commit, but rather regard any commit as public if it is pointed to by a remote ref or is an ancestor of such a commit.
In mercurial, you can do an hg update to any revision in the history and then create a new commit as a child of that revision. If the parent of this new commit was not already a head in the directed acyclic graph, you now have a new branch. If that's all you do then the branch does not have a name, but it won't ever be garbage collected or anything like that (you can always find it by running hg heads).
If you want to use git-style (implicit, as you say) branching, you can now use the hg bookmark command to create a bookmark for this branch, which is a named reference or pointer just like git branches are. Of course you can create the bookmark first too if that's more intuitive.
You can also use the original style of mercurial branches that you mention, where before committing you run the hg branch command to create a branch name, and then all commits along that branch in the DAG will have a branch name associated with them.
This is getting a little bit out of date (bookmarks have evolved to be even more like git branches), but I think it's still the best description of mercurial branches out there:
http://stevelosh.com/blog/2009/08/a-guide-to-branching-in-mercurial/#branching-with-bookmarks
http://stevelosh.com/blog/2009/08/a-guide-to-branching-in-mercurial/