Skip to content

References and HEAD

A Commit has an immutable Object ID. A branch name gives us a stable way to find the current tip of a line of work without memorizing that ID. Git stores that name as a reference, or ref, whose value points to a Commit.

For a local branch named master, the full reference name is refs/heads/master:

reference name: refs/heads/master
reference value: <commit-id>

The name is not a Commit object. After a new Commit on master, Git creates a new Commit and updates the reference value:

before: master → C3
after: master → C4 → C3

The old Commit C3 does not change. C4 records C3 as its parent.

While working on master, HEAD is normally a symbolic reference:

HEAD → refs/heads/master → C4

The .git/HEAD file can contain:

ref: refs/heads/master

Making another Commit on master leaves that text unchanged. Git updates the value of refs/heads/master, so resolving HEAD now reaches the new Commit.

Two branches may point to the same Commit. Comparing only their Commit IDs cannot tell which branch is currently checked out; the symbolic target of HEAD can.

Use read-only commands inside a disposable repository:

Terminal window
git symbolic-ref HEAD
git rev-parse HEAD
git show-ref --verify refs/heads/master

They answer different questions:

Command What it reports
git symbolic-ref HEAD The reference name currently selected by symbolic HEAD, such as refs/heads/master.
git rev-parse HEAD The Object ID reached by resolving HEAD, usually the current Commit ID.
git show-ref --verify refs/heads/master Whether that exact branch ref exists, followed by its Object ID and full name.

In our training repository, the first command returned refs/heads/master; the latter two resolved to the same Commit ID shown by git log -1. On another branch, rev-parse HEAD follows that branch while show-ref --verify refs/heads/master still checks master.

HEAD can point directly to a Commit ID instead of a branch name:

symbolic: HEAD → master → Commit C
detached: HEAD ─────────→ Commit C

In the detached state, git rev-parse HEAD can still report the Commit ID, but git symbolic-ref HEAD cannot report a current branch. A branch elsewhere might also point to the same Commit; that does not attach HEAD to it. The practical workflow for detached HEAD belongs to a later checkpoint.

A branch ref may exist as an individual file under .git/refs/heads/. Git can also store refs in .git/packed-refs. Therefore, the absence of .git/refs/heads/master alone does not prove that master is absent. Use git show-ref --verify refs/heads/master to ask Git whether the ref exists.

A reflog records local updates to a reference. HEAD has a reflog, and a branch such as master can have its own reflog:

Terminal window
git reflog -3

An entry such as HEAD@{0} is the newest recorded position of HEAD; HEAD@{1} is the preceding position. Switching branches can add an entry to the HEAD reflog without moving either branch tip. Making a Commit on the current branch updates both the branch tip and the Commit reached through HEAD, so both reflogs record the movement even though .git/HEAD still names the same branch.

git log follows Commit parent relationships. A reflog describes local reference movements, including movements that create no Commit. Reflogs are local records, not permanent backups; recovery use and retention details belong to a later checkpoint.

  • Treating refs/heads/master as the Commit ID rather than the reference name.
  • Assuming the text in .git/HEAD changes after every Commit on the same branch.
  • Assuming equal branch tip IDs reveal which branch is checked out.
  • Assuming a missing loose ref file means the branch does not exist.
  • Confusing the HEAD reflog with a branch reflog or with Commit history.

HEAD normally names the current branch ref; that ref holds a Commit ID. A Commit moves the current branch tip without changing older Commits or the symbolic text in .git/HEAD. Resolve HEAD to learn the current Commit, inspect a named ref to learn its value, and use reflogs to see local ref movement.

Two branches point to one Commit. How can you tell which is current?

Inspect git symbolic-ref HEAD. Matching Commit IDs alone do not identify the checked-out branch.

What changes after a new Commit on the current branch?

The branch ref moves to the new Commit. The Commit reached through HEAD changes, so HEAD and branch reflogs record the update, while .git/HEAD keeps its symbolic branch name.