tags:

views:

404

answers:

2

There seems to be a difference between the last commit, the HEAD and the state of the file I can see in my directory.

What is HEAD, what can I do with it and what mistake should I avoid?

+5  A: 

HEAD is a reference to the last commit in the current checked out branch.

poke
So why can you have two heads?
e-satis
@e-satis: because HEAD is a commit that you have checked in the working directory, and since the working directory can only display *one* commit at a time (from which you do some modifications), you can only have one HEAD.
VonC
@e-satis: sometimes you'll see branches referred to as heads - they're stored in `refs/heads`. Lower-case head is different from `HEAD`, though. My answer clarifies this a bit.
Jefromi
Ok, and what does HEAD^ means? I use that in "reset", but don't know why. See any regexp knowledge helping me here.
e-satis
@e-satis: That's not regex. The `^` is just git's notation for "the commit before" - that's the commit before the current one. (If the current is a merge, it uses the first parent.)
Jefromi
@e-satis: See the specifying revisions section of the man page for git-rev-list for more information about all the ways to specify commits - this is just one tiny piece. http://www.kernel.org/pub/software/scm/git/docs/git-rev-parse.html#_specifying_revisions
Jefromi
Thanks for your answer. They help me much more than the doc. I really hate git's doc, it's so not user friendly. It feels like being in maths lectures again : plenty of formula and no concrete uses.
e-satis
You said "(If the current is a merge, it uses the first parent.)". Why does it do that ?
e-satis
Because a merge commit has multiple parents, and there is just one notation. So they just decided to give you the first parent of the available ones. You can however use `rev^2` to get the second parent of the revision, or for example `HEAD^3` to get the third parent of the HEAD commit.
poke
Ok. The first parent of a merge, it's the one we merged from or the one we merged into? And is there difference between rev^2 and HEAD^2 if rev is the top revision? Sorry to harass you with that :-) I don't like to work with things I don't understand.
e-satis
No, when rev and HEAD are pointing to the same commit, there is no difference. And you could even write the commit id (the SHA-1 value) instead of rev or HEAD. And don't worry, you don't harass us with the questions :) (me at least :P)
poke
Cheers. Love SO. You can have 14K rep and still be a noob :-p
e-satis
+4  A: 

HEAD is a ref (reference) to the currently checked out commit.

In normal states, it's actually a symbolic ref to the branch you have checked out - if you look at the contents of .git/HEAD you'll see something like "ref: refs/heads/master". The branch itself is a reference to the commit at the tip of the branch. Therefore, in the normal state, HEAD effectively refers to the commit at the tip of the current branch.

It's also possible to have a "detached HEAD". This happens when you check out something besides a (local) branch, like a remote branch, a specific commit, or a tag. The most common place to see this is during an interactive rebase, when you choose to edit a commit. In detached HEAD state, your HEAD is a direct reference to a commit - the contents of .git/HEAD will be a SHA1 hash.

Generally speaking, HEAD is just a convenient name to mean "what you have checked out" and you don't really have to worry much about it. Just be aware of what you have checked out, and remember that you probably don't want to commit if you're not on a branch (detached HEAD state) unless you know what you're doing (e.g. are in an interactive rebase).

Jefromi
This is something I don't understand. If you checkout a remote branch, why do you end up with a "detached HEAD". Why don't you automatically jump in the branch in your local repo that correspond to your remote?
e-satis
@e-satis: If you want the local branch, check out the local branch. Remember that the two aren't necessarily the same - you have to tell the local one to merge the remote one (or pull). The tracking is just so it knows which one to automatically pull when you ask. The reason it's detached is that the remote branch is intended to be a pointer to the last-seen location of the branch in the remote repo. If you try to commit to it, the remote repo doesn't change, so the remote branch shouldn't either.
Jefromi
OK, that's what I didn't get : having a local branch named in a way doesn't imply it's the same as the remote one. Really hard to get at the beginning cause I come from a SVN background :-) Thanks man. BTW, how do you move a headless HEAD to a local branch to commit it here ?
e-satis
@e-satis: The general answer is `git rebase <branch> HEAD`. This will find the last common ancestor of `<branch>` and `HEAD`, and then take all the commits from there to `HEAD` and apply them (rebase them) onto `<branch>`. It essentially does this by applying them as patches, so if the two branches are really different, there could be conflicts. But if `<branch>` is an ancestor of `HEAD` (i.e. you were in the right place, just forgot you'd detached `HEAD`) the rebase is just a fast-forward merge.
Jefromi