Inspect and Change Git Symbolic Refs

Your .git/HEAD file is not a commit ID, it is a pointer to another ref, and git symbolic-ref reads or rewrites that pointer directly. You will use it to see which branch HEAD names, create a symbolic ref that points at a branch, and remove that ref without editing files by hand. The examples use Git 2.43.0, supplied here by the Ubuntu git-man package. They take about five minutes in an existing test repository. No command here needs elevated privileges.

What a symbolic ref is

A normal ref ultimately identifies a commit. A symbolic ref instead contains a name beginning with ref: refs/ and points at another ref. The familiar .git/HEAD file is normally one: while you are on branch main, it points to refs/heads/main. Git uses this portable text-file mechanism instead of relying on filesystem symbolic links.

The command has three useful shapes:

git symbolic-ref <name>
git symbolic-ref <name> <ref>
git symbolic-ref --delete <name>

The command reports ref paths relative to the repository's .git/ directory.

Checkpoint: confirm the current branch

Change into the repository you want to inspect.

cd /path/to/repository
git symbolic-ref HEAD

On a checkout of main, the expected output is:

refs/heads/main

For the shorter branch name, add --short:

git symbolic-ref --short HEAD
main

This is useful in shell scripts, but it succeeds only when the argument is a symbolic ref. A detached checkout has a commit ID in HEAD, not a branch ref. In that state, the ordinary command exits with status 128 and prints an error. Use quiet mode when that is an expected possibility:

if branch=$(git symbolic-ref --quiet --short HEAD); then
    printf 'on branch %s
' "$branch"
else
    printf '%s
' 'detached HEAD or another symbolic-ref error' >&2
fi

--quiet suppresses the diagnostic for a non-symbolic HEAD, and the exit status is 1 in that case. Do not treat the absence of a branch name as proof the repository is broken: detached HEAD is a valid Git state.

Create a symbolic ref

Creating a symbolic ref changes repository metadata. Use a disposable repository or a ref name owned by your workflow before trying this in automation.

Checkpoint: point refs/heads/release at the existing main branch.

git symbolic-ref refs/heads/release refs/heads/main
git symbolic-ref refs/heads/release
git symbolic-ref --short refs/heads/release

Expected output is:

refs/heads/main
main

The first command creates the ref; the next two verify both its full target and its shortened target. If the symbolic ref already exists, the same two-argument form updates it. This is a ref operation, not a commit and not a branch merge: the target name changes, while the commits named by the target branches do not.

Tip: if you want an audit reason recorded in the ref's reflog, supply -m while creating or updating it.

git symbolic-ref -m 'point release at main'   refs/heads/release refs/heads/main

The reason option is valid only for creation or update. It cannot be combined with deletion or a read-only query.

Follow one level or the whole chain

Git follows symbolic refs recursively by default. Suppose refs/heads/release points at another symbolic ref, refs/heads/stable, which points at refs/heads/main. A normal read follows the chain to refs/heads/main. To inspect only the first link, use --no-recurse:

git symbolic-ref --no-recurse refs/heads/release

The output in that chain would be:

refs/heads/stable

This distinction matters when debugging indirection. A shortened result can hide the fact you are inspecting a link rather than a direct branch target, so use the full form first when correctness matters.

Delete only the ref you own

Warning: --delete removes the named symbolic ref. It is a destructive metadata change, although it does not delete commits. Check the exact name before running it, and do not use it on HEAD as a way to leave detached state.

git symbolic-ref refs/heads/release
git symbolic-ref --delete refs/heads/release

Deletion prints no success message. Verify it by reading the ref and checking the status:

if git symbolic-ref --quiet refs/heads/release; then
    printf '%s
' 'release still exists' >&2
    exit 1
else
    printf '%s
' 'release symbolic ref is absent'
fi

Recovery: if you deleted the wrong symbolic ref, recreate it with the two-argument form, provided you know the intended target.

git symbolic-ref refs/heads/release refs/heads/main

That restores the ref name and target, but it does not restore any reflog history that was removed with the ref.

Common failure modes

Done means