References: Branches, Tags, and HEAD

Updated

October 30, 2026

References: Branches, Tags, and HEAD

After this page you can say what a ref is, where it lives, and how HEAD relates to a branch.

A ref is a name for a hash

A ref (reference) is a name that points at a commit (or, for annotated tags, at a tag object). Git stores them as files under .git/refs/ and, when there are many, in .git/packed-refs.

Ref Typical path Meaning
Branch .git/refs/heads/main Movable name for a line of work
Tag .git/refs/tags/v1.0 Name meant to stay put
Remote-tracking .git/refs/remotes/origin/main Last-seen tip of a branch on a remote
HEAD .git/HEAD Where you are
git rev-parse main
git rev-parse HEAD
cat .git/HEAD
# ref: refs/heads/main

git rev-parse turns a name into a hash. Use it when a diagram and the disk disagree in your head.

Branches move, tags mostly do not

git branch                  # local branches
git branch feature          # new name at current HEAD
git switch feature          # HEAD now points at feature
git switch -c hotfix        # create and switch

git switch is the modern command for changing branches (git checkout still works; this book uses switch for branches and restore for files).

A tag is a bookmark:

git tag v0.1                # lightweight: a name at HEAD
git tag -a v0.1 -m "first"  # annotated: a tag object

Moving a published tag surprises people who already fetched it. Moving a branch is normal.

HEAD is usually a pointer to a pointer

.git/HEAD          →  ref: refs/heads/main
.git/refs/heads/main →  a1b2c3d4….

Commit while on main: Git writes a new commit whose parent is a1b2c3d4…, then overwrites refs/heads/main with the new hash. HEAD did not change its text; the branch it names did.

Detached HEAD: .git/HEAD contains a raw hash instead of ref: refs/heads/…. You get there with git switch --detach, or by checking out a tag. To keep work from a detached HEAD:

git switch -c keep-this

That creates a branch at the current commit and attaches HEAD to it.

Remote-tracking names

After you add a remote named origin and fetch (chapter 11):

refs/remotes/origin/main

That is your last photograph of main on that remote. It updates on fetch. You do not commit onto it. Your local main is a separate name you push.

Plumbing vs porcelain

git branch, git switch, git tag are porcelain (human commands). git update-ref and git symbolic-ref are plumbing (the same operations, no sugar). This book stays on porcelain until internals (chapter 16). Knowing refs are files is enough to understand why creating a branch is cheap: Git writes a 41-byte file.