Subject: Re: Newbie grief

From: Ted Ts'o <[email-masked]>
Date: Tue, 1 May 2012 07:14:15 -0400

On Tue, May 01, 2012 at 09:14:24AM +0530, Sitaram Chamarty wrote:
> 
> > Multiple heads are the idea that a single commit can "branch" in the
> > repository and that both commits can be HEADS of the same branch at once in
> > a single repository.  This allows a potential collision to exist in the
> > repository and to be pushed and pulled through multiple repositories.  It
> 
> That is bizarre; I have no other word for it.
> 
> I teach git (occasionally), and if this feature existed I would
> totally ignore it in my teaching material because I wouldn't know how
> to defend or explain the need for "hydra branches".

I wouldn't use the verb branch (and certainly not "hydra branch"),
because it's confusing to someone who thinks this has something to do
with noun "branch".  But that's a confusion because of the english, or
rather the terminology that was used.

I would put it this way.  Every non-merge commit has a parent (we'll
ignore merge commits for now).  When you look at that commit via "git
show <commit-id>", what you see is the diff between its parent and the
state of the source tree as described by that commit-id.  If you put
it this way, it becomes obvious that a particular parent commit can
have multiple child commits.  (This seems to be what you are calling
"hydra branches".)

A branch is a pointer to a commit.  When you add a commit to a branch,
you are adding a new commit whose parent is pointing to the current
branch head, and afterwards, the branch head pointer is changed to
point at the new commit.

> Does Hg do this?  That would explain why my (admittedly half-hearted)
> attempts to learn it have failed -- whatever tutorial I used must have
> been written with the idea that hydra branches are intuitive and
> logical and sane, but did not express the concept as clearly and
> succinctly as you did.

What Hg does is it requires that all terminal commits (commits that do
not have children) must be named by a branch pointer.  So when you
pull in some changes from Hg, there may be a non-terminal commit, but
before the hg pull finishes, it will create a merge commit which
merges the current branch pointer and the newly pulled in commits, so
that when you are done, the branch pointer points at the new merge
commit, and the requirement that there be no non-named terminal
commits is maintained.

Git differs in that you can have a child commit which is not pointed
to by a branch pointer, and which is referred to only by commit-id.
These child commits can disappear on you, when you do a garbage
collection; but it allows you to have multiple child commits hanging
off of a single parent commit, and you can do diffs, cherry picks,
etc.  But they *do* have a unique name --- the commit id, which is a
SHA1 hash of the contents of the diff.

Does this help?

						- Ted