Refs and HEAD

Refs, HEAD and the Symbolic Reference Chain

A ref gives a commit a name: branches live under refs/heads/, tags under refs/tags/ and remote-tracking branches under refs/remotes/. In the default files backend each ref is a text file holding a hash, and HEAD is a symbolic ref that normally names a branch rather than a commit:

Following HEAD to a commitShell
cat .git/HEAD
cat .git/refs/heads/main
git branch feature
git show-ref
git switch --detach -q HEAD~1
cat .git/HEAD
git switch -q main
Output
ref: refs/heads/main
0be51cec615ba290d0cd9cd68508412c95aa6182
0be51cec615ba290d0cd9cd68508412c95aa6182 refs/heads/feature
0be51cec615ba290d0cd9cd68508412c95aa6182 refs/heads/main
653fc97f05515c8f22fe7b7865e1ae16351816d0

Creating feature wrote one 41-byte file and copied nothing. A commit writes the new object, then moves the branch that HEAD names. After switch --detach, HEAD holds a hash itself, a detached HEAD, and commits made there belong to no branch, which is how work gets "lost" (Reflog and Recovery gets it back). 4 shows both states.

HEAD names a branch, and the branch names a commit
HEAD names a branch, and the branch names a commit