By admin , 28 April 2026

Introduction

A symbolic ref is a reference whose value is another ref name rather than an object hash. The canonical example is HEAD, which usually contains ref: refs/heads/main. Symbolic refs let Git track "the current branch" as data, not state.

Reading and writing

git symbolic-ref HEAD
# refs/heads/main

git symbolic-ref refs/remotes/origin/HEAD
# refs/remotes/origin/main

git symbolic-ref HEAD refs/heads/feature/login   # change without checkout
git symbolic-ref --short HEAD                      # short form: main
git symbolic-ref --delete refs/remotes/origin/HEAD

HEAD as a symbolic ref

When you commit, Git resolves HEAD to find the current branch and updates that branch's tip. When HEAD is detached it stops being symbolic and contains a raw SHA.

cat .git/HEAD
# ref: refs/heads/main         (symbolic)
# vs after detach:
# a1b2c3d4...                  (raw)

Remote HEAD

Each remote can have a symbolic HEAD indicating its default branch. Set or refresh:

git remote set-head origin --auto       # query server
git remote set-head origin main         # set explicitly
git remote set-head origin --delete

This is what makes git log origin resolve to origin/main.

Why use them

  • "Current branch" can change without rewriting history.
  • Tools can ask "what is the default?" without hardcoding names.
  • Hooks can target the currently checked out branch generically.

Worktrees and per-worktree HEAD

Every linked worktree (git worktree add) has its own HEAD, stored under .git/worktrees/<name>/HEAD. Each can point at a different branch:

git worktree add ../wt-feature feature/login
cat ../wt-feature/.git
# gitdir: /path/to/main/.git/worktrees/wt-feature
cat .git/worktrees/wt-feature/HEAD
# ref: refs/heads/feature/login

Detection

git symbolic-ref -q HEAD && echo "on a branch" || echo "detached"

Renaming the default

To rename master to main safely:

git branch -m master main
git symbolic-ref HEAD refs/heads/main
git push -u origin main
git symbolic-ref refs/remotes/origin/HEAD refs/remotes/origin/main

Inspecting symbolic resolution

git rev-parse resolves a name through symbolic refs all the way to a SHA, while git symbolic-ref only follows one level. The pair is useful for scripts:

git symbolic-ref HEAD                       # refs/heads/main
git symbolic-ref --short HEAD               # main
git rev-parse HEAD                          # SHA
git rev-parse --symbolic-full-name HEAD     # refs/heads/main
git rev-parse --symbolic-full-name @{u}     # refs/remotes/origin/main

Use --symbolic-full-name when you want the canonical ref name no matter what shorthand the user typed.

Common mistakes

Editing .git/HEAD by hand and forgetting the trailing newline, leaving Git unable to parse it. Use git symbolic-ref. Treating refs/remotes/origin/HEAD as authoritative when it is actually cached; refresh with git remote set-head origin --auto. Confusing a symbolic ref pointing at a missing branch with a real error; git symbolic-ref -q exits non-zero, which scripts can handle. Finally, deleting the underlying ref without updating the symbolic one, leaving a dangling symref; tools may report it but it is harmless and easy to fix with another symbolic-ref.