HEAD in GIT is a special pointer. It is a pointer to the last commit snapshot. In simple words, it always points to the most recent commit in the current checkout branch. When you checkout to other branch, it is known as the active or current branch.

HEAD^ and HEAD~

In Git HEAD^, the caret sign (^) denotes the parent of a specific commit. The parent of the current HEAD commit is referred to as HEAD^.

The tilde sign (~) is a shorthand for a row of several characters (^). For example

  • HEAD~2 is equivalent to HEAD^^
  • HEAD~3 is equivalent to HEAD^^^
  • HEAD~4 is equivalent to HEAD^^^^
  • and so on…

Above can also be written as

  • HEAD~ is always the same as HEAD^
  • HEAD~~ is always the same as HEAD^^
  • HEAD~~~ is always the same as HEAD^^^
  • HEAD~~~~ is always the same as HEAD^^^^ and so on

Detached HEAD

To checkout a specific commit, you can use the git checkout command and provide the revision hash as a parameter:

git checkout 757c47d4

When we checkout a git branch, HEAD points to the top of that branch. If you checkout a particular commit (means using a specific commit as your most recent commit) as shown above, now the state is changed to detached HEAD. Git will not put the HEAD in the branch. This means that when you make changes and commit them, these changes do NOT belong to any branch. The consequence is that these changes can easily get lost once you check out a different revision or branch.

HEAD vs index

From Git’s point of view the journey of a file goes from three areas.

  • Working directory (Workspace) : It is the directory tree of (source) files that you see and edit.
  • Staging area : Git index serves as the staging area between the files you have on your filesystem and your commit history. Essentially, the contents of the index are what will go into the new commit (though if you do git commit -a, this will automatically add all changes to files that Git knows about to the index before committing, so it will commit the current contents of your working tree). git add will add or update files from the working tree into your index.
  • Local Repository : It is a hidden directory (.git) including an objects directory containing all versions of every file in the repo (local branches and copies of remote branches) as a compressed blob file.

Below figure shows the various stages from which a files moves.

A file journey in GIT
A file journey in GIT
  • When you run git add, the files from your working directory are hashed and stored as objects in the index. The index is a binary file (generally kept in .git/index) containing a sorted list of path names. git ls-files --stage can show you the contents of the index.
  • When you run git commit, the staged changes as stored in the index are used to create that new commit. Now HEAD points to this commit.
  • When you run git checkout, Git takes the data from a commit and writes it to the working directory and the index.