The Git HEAD is a Git reference object that represents the current branch. Checking out a branch will change the HEAD to point to the checked out branch. The HEAD will point to the tip of a branch by default, but can be set to point to any commit. When pointed at a specific commit the HEAD is considered to be in a ‘detached’ state. Detaching is useful if you need to branch from a midpoint commit instead of the branch HEAD.
The Git reference objects include tags, branches and remote references. The Git HEAD is a special reference object that always points to the current branch. To list all reference objects in a local repository use the “git show-ref” command:
$ git show-ref
In this example you can see the references in the repository include the master branch, the remote master branch and the Add-Email-Collection branch.
To display refs including the HEAD:
$ git show-ref --head
Add the --head argument displays the commit that HEAD is currently referencing. Since the current branch is ‘Add-Email-Collection’ the HEAD is currently set to this branch.
When you checkout a commit by name, git creates an anonymous branch called a detached HEAD.
According to “Version Control with Git, O'reilly, 2012”
“Git creates a detached HEAD when you:
Let’s do the ‘Check out a commit that is not the head of a branch’ scenario. The other scenarios require a deeper dive, so I will leave those for another post.
Continuing the example from above, running the command:
$ git checkout d89fb8e72bf82fd
detaches HEAD from the “Add-Email-Collection” branch and points it directly at the “d89fb8e…” commit.
So instead of HEAD pointing to the “Add-Email-Collection” branch, and the branch pointing to the “d89fb8e” commit. The Git HEAD is now pointing directly at the commit, and is thus detached from a branch.
Running the "git status" or "git branch" commands indicate that the HEAD is in a detached state.
So, if I commit the current working directory changes they will be checked into the anonymous branch. Git will readily create a commit for the changes.
You can see here that I have commited the pending changes against the detached HEAD and changed branches back to the HEAD. Git warns that my change is floating around unattached to a branch, and thus is not part of a change stream. At this point Git recommends creating a branch from the commit with:
$ git branch <new-branch-name> 6a44441
I also have the option to cherry pick the commit into my current branch, or just leave it to twist in the ether, but I don’t want to lose track of this change so I will merge it in.
The “git reflog” command displays the history of HEAD references and provides useful information to make sense of how the HEAD evolved and where commits may have been orphaned.
Let’s pick through this output.
As you can see, “git reflog” is a useful forensic tool for telling the story of the HEAD reference object.
I’m going to proceed with git’s suggestion to branch from the orphaned commit. This action is the equivalent to branching from the ‘Add-Email-Collection’ branch and committing to the branch directly.
git branch orphaned-changes 6a44441
So now if I run git show-ref
You can see that the “orphaned-changes” branch points to the commit created on the anonymous branch. I can now switch to this branch and work from it, or merge it into my ‘Add-Email-Collection’ branch.
For the cherry-pick example I’ve detached the HEAD again, made a change and committed on an anonymous branch. Below are the console commands and output from git reflog showing the history.
I create a commit 4f6ef34… and checkout the feature branch. Instead of branching and merging I can quickly resolve the change into the current branch with a cherry-pick. This saves having to create, merge and delete a branch.
The git HEAD is a convenience reference object that specifies the current branch context. It tracks against the current checkout and if that checkout is not a branch head, then the HEAD is considered detached. It allows you to easily reference any commit in the change history and branch changes from that commit.