Understanding HEAD in Git

In this post, we will learn about HEAD in Git & how we can use it to reduce keystrokes when doing git push to remote.

Note: If you're using GUI tools to do a git push, this tip might not be that helpful. However, IMO it is essential to understand the fundamentals concepts like HEAD to know how things work in Git and use it whenever required.

In Git, a Commit is the smallest unit representing our code snapshot at a particular point in Git history. We all are aware of commits in Git. However, besides commits in Git, there are three other useful things.

  • Tags (we won't be talking about this today)
  • Branches
  • HEAD

All these three things - Tags, Branches and HEAD are nothing but pointers to our commits.

Pointers in Git

To understand it more clearly, let's look closely at the .git folder of a project containing develop and master branches.

> tree .git

|__ HEAD
|__ refs
    |__ heads
    |   |__ master
    |   |__ develop
    |__ remotes
    |   |__ origin
            |__ develop
            |__ master
    |__ tags
# There are other imp folders too. Removed them here for brevity.


As you can see in the above diagram, there are two refs of local branches, develop and master.

> cat ./git/refs/heads/master

> cat ./git/refs/heads/develop

If you check their content using the cat command like the above, you will see that they contain which "commit" the "branch" points to.

Let's check what HEAD contains. Checkout to develop branch locally and run the following command:

> cat .git/HEAD
ref: refs/heads/develop # HEAD points to "develop" branch

Switchig to master branch and running the above command again:

> cat .git/HEAD
ref: refs/heads/master # HEAD points to "master" branch

As you can see, HEAD always points to your currently checked-out branch locally. It is a pointer to the now checked-out branch. In other words, these are just references to one another.

HEAD -> Branch -> Commit

Credit to Nina Zakharenko's course on Git In-Depth on FrontendMasters where i learned this concept couple of yrs back.

Git Push using HEAD

We now know what HEAD is! Considering it points to your current branch, why not use it to push your current local branch to remote? You must be thinking, why even use HEAD? I can run git push, and it works most of the time.

You're right. However, it doesn't work when you try to push some local branch to remote for the first time. That is because it only works after the upstream branch has been set.

Every time you run git push for the first time on any new branch, you see the following error:

> git push

fatal: The current branch chore/config-changes has no upstream branch.
To push the current branch and set the remote as upstream, use

git push --set-upstream origin chore/config-changes

And then you go ahead and run command it suggests. This is fine! 😅

As per our recent learning, HEAD points to our currently checked-out branch. So, why not use one of the variant of git push involving HEAD where we don't have to see the same error again. :)

> git push origin HEAD

Yup, that's it 🎉

  • No more errors as git push during the first push.
  • No need to type your branch name as well.
    E.x. - git push origin chore/config-changes

To reduce keystrokes even further, you can set an alias in the .rc files of your default system shell.

alias gpush="git push origin HEAD"

Now, you can run the below command whenever you want to push anything to the remote without worrying about typing long branch names or dealing with errors during the first push.

> gpush

Despite using GUI tools for all such git tasks, knowing small things like this is helpful because it can help understand how things work under the hood. So, whenever needed, we can use them. I hope that was useful. Thanks for reading 🙂