Branches and Heads

Stuart Marks Stuart.Marks at Sun.COM
Fri Feb 16 03:11:29 UTC 2007


Russell Suter wrote:
> If I create a branch on a branch it appears that there is only
> one head for both branches -- the head is on the second branch.
> 
> 10
> |
> +--11 (branch 1)
>     |
>     +--12 (branch 2) (head) (tip)
> 
> If I set back to branch 1, the branch command reports that I'm
> on branch 1 as expected but the revision is revision 12 even if
> I do an update -C.  If I update to revision 11 and commit a change
> (creating revision 13) the heads command will show that I have
> two heads:
> 
> 10
> |
> +--11--13 (head)(tip)
>     |
>     +--12 (head)
> 
> What I would expect is that revision 11 stays the head of branch 1
> even when branch 2 / revision 12 is created.  Also, when I go back
> to branch 1 and update, I get revision 11.

It sounds like you're thinking that 'hg branch' actually creates branches. This 
is understandable, since hg's branching doesn't really seem to be described 
very well anywhere.

As I understand it, 'hg branch' merely sets or gets the branch name of the 
working copy, which is significant only when a commit is done. At that point 
the rev created by the commit has a branch label associated with it. This 
doesn't affect the topology of the history tree in any way.

Also, 'hg branch' doesn't change the parent rev of the working copy. You have 
to do an 'hg update' to do that.

To create a branch explicitly, you need to update the working copy to a 
non-head rev and commit a new rev there. This occurs regardless of whether 
you've set a branch name with 'hg branch'. If you have, you've created a named 
branch; otherwise you've created an unnamed branch.

A "head" is simply a description of where a rev is in the history tree. If a 
rev has no children (i.e., it's a leaf node) it's a head, otherwise not. This 
is independent of whether it has a branch name.

In your example, I think you did the following:

$ hg parent
changeset:   10:ea198e780bce
tag:         tip
...
$ hg branch "branch 1"
$ hg commit                # creates rev 11, labeled "branch 1"
$ hg branch "branch 2"
$ hg commit                # creates rev 12, labeled "branch 2"

If so, then you're simply adding new revs to the tip. This gives a linear 
sequence of revs, with no branches, that happen to have a couple different 
branch labels. Since rev 11 is now an interior node in the history tree, it's 
not a head.

As you observed you can update back to rev 11 and commit a new rev there, which 
truly creates a branch. You can also do 'hg update "branch 1"' which will 
update the working copy to the tipmost rev with that branch name, whether or 
not that rev happens to be a head.

> To complicate matters, if I do this in a clone of a parent repository,
> when I go to push revision 13, It aborts with the "push creates new
> remote branches!" message.

Right, doing a push that creates a new head is unusual enough that push warns 
about it. This is often the case if you did a pull that had a conflict that you 
forgot to merge. But if it's truly your intent to create a new head in the 
parent, just use push -f.

s'marks



More information about the Mercurial mailing list