Home / Alt manpages / git-show-ref(1)

  • git-show-ref(1)
  • User command
  • linux

Inspect Git References Safely with git show-ref

You will finish with a reliable way to list local Git branches and tags, verify one exact ref, test ref existence in a script, and filter a stream of candidate refs. The examples match Git 2.43.0 and git-man 1:2.43.0-1ubuntu7.3, installed on this system.

Allow about fifteen minutes. You need Git and a repository you can read. Every command below is ordinary user-level inspection. None changes commits, branches, tags, the index or repository configuration.

Checkpoint: run the version check before relying on an option in automation:

$ git --version
git version 2.43.0
$ dpkg-query -W -f='${Package} ${Version}\n' git-man
git-man 1:2.43.0-1ubuntu7.3

1. See the repository's refs

Change to the repository you want to inspect, then run the default form:

$ cd /path/to/repository
$ git show-ref

Each result is an object ID followed by a space and a full ref name, such as refs/heads/main, refs/tags/v1.2.0 or a remote-tracking ref under refs/remotes/. The default view includes heads, tags and remote refs. Output order is not a user-facing sorting contract, so sort it yourself if a report needs stable order:

$ git show-ref | sort -k2

A repository can be a normal working tree with a .git directory, a bare repository whose Git directory is the repository itself, or a worktree whose .git file points elsewhere. That is why reading .git/refs directly is a poor substitute. git show-ref asks Git for the repository's logical refs and also accounts for refs recorded in packed-refs.

If there are no matching refs, the command returns status 1. An empty display is therefore not automatically a damaged repository. It may simply mean that your filters matched nothing.

2. Narrow the list to branches or tags

Use --heads for local branch heads and --tags for tags:

$ git show-ref --heads
$ git show-ref --tags

The options can be combined when you want only local branches and tags, excluding remote-tracking refs and other namespaces:

$ git show-ref --heads --tags

These switches limit what is displayed; they do not create or remove anything. A tag normally appears as the object it names. An annotated tag can name a tag object rather than a commit, which matters when another tool expects a commit ID.

3. Dereference annotated tags deliberately

Add --dereference when you want Git to print the object reached through a tag as well:

$ git show-ref --tags --dereference
bb8adfa6778c16c65c34103822358d3242a7e062 refs/tags/v1
c5e88e5ba904d6e347aa16c1f098b13404a4c24e HEAD^{}

The IDs above are illustrative output from a temporary repository, so yours will differ. The important marker is ^{} appended to the dereferenced tag ref. Do not assume the first ID is the commit that a release points to. If your consumer wants commit-like targets, use dereferenced output and handle lightweight tags, annotated tags and non-commit objects according to that consumer's contract.

To emit only IDs, use --hash:

$ git show-ref --heads --hash
c5e88e5ba904d6e347aa16c1f098b13404a4c24e

With --hash, ref names disappear. Add an abbreviation length only when the receiving tool accepts abbreviated IDs, for example git show-ref --hash=12 --heads. Full IDs avoid ambiguity and are the safer default for records that may be compared later.

4. Verify one exact ref

A pattern such as main is intentionally broad. It can match a ref whose final component is main, including a branch, remote-tracking ref or tag. For an exact path, use --verify and the complete ref name:

$ git show-ref --verify refs/heads/main
c5e88e5ba904d6e347aa16c1f098b13404a4c24e refs/heads/main

Put -- before a shell-expanded ref name when you want the option boundary to be unambiguous:

$ head_name='main'
$ git show-ref --verify -- "refs/heads/$head_name"
c5e88e5ba904d6e347aa16c1f098b13404a4c24e

For a silent check, add --quiet. A present exact ref returns 0. A missing or invalid verification target returns 1, and without --quiet Git also prints an error. This is the form to use when you need exactness and do not want normal output:

if git show-ref --quiet --verify -- "refs/heads/$head_name"; then
    printf '%s\n' 'branch exists'
else
    printf '%s\n' 'branch is absent' >&2
    exit 1
fi

Do not use --verify with a short name and expect Git to resolve it like a command such as git checkout. The point of this mode is the exact full ref path.

5. Check whether a ref exists

Git 2.43.0 also provides --exists for one reference. It checks whether the reference exists, but does not check whether it resolves to an object:

$ git show-ref --exists refs/heads/main
$ printf 'status: %s\n' "$?"
status: 0
$ git show-ref --exists refs/heads/missing
error: reference does not exist
$ printf 'status: %s\n' "$?"
status: 2

The documented statuses are 0 for present, 2 for missing and 1 for a lookup error other than absence. That distinction is useful in scripts. Capture the status immediately, because a later command replaces the shell's $? value:

git show-ref --exists -- "refs/heads/$head_name"
status=$?
case "$status" in
    0) printf '%s\n' 'ref exists' ;;
    2) printf '%s\n' 'ref is missing' ;;
    *) printf 'ref lookup failed, status %s\n' "$status" >&2; exit "$status" ;;
esac

Use --verify --quiet instead when you need the older, exact-checking interface or need to support an environment where --exists is unavailable. Do not silently treat every non-zero result as "missing"; repository errors deserve investigation.

6. Filter candidate refs from standard input

--exclude-existing reverses the usual direction. It reads one ref per input line and prints only well-formed refs that do not exist locally:

$ printf '%s\n' \
    refs/heads/main \
    refs/heads/missing \
    refs/tags/v1 \
    refs/heads/new \
    | git show-ref --exclude-existing
refs/heads/missing
refs/heads/new

Existing branch and tag refs are removed from the output. A trailing ^{} is stripped for the existence test, and malformed ref names are skipped with a warning. Add a pattern such as refs/heads/ to consider only input refs beginning with that text:

$ printf '%s\n' refs/heads/new refs/tags/new | \
    git show-ref --exclude-existing=refs/heads/
refs/heads/new

The input is data, not an option list. Keep each ref on its own line and pass trusted, validated names into the pipeline. This form is useful for finding proposed refs that a local repository does not yet contain; it does not fetch, create or delete them.

7. Keep the safety boundary clear

git show-ref is an inspection and filtering command. It does not repair a missing branch, update a remote, rewrite packed-refs or edit files under the repository. Do not respond to an unexpected result by manually editing .git/refs. The repository layout distinguishes loose refs, packed refs, shared common directories and worktree-specific state, so direct edits can leave a repository inconsistent.

If a ref is missing, first confirm the repository with git rev-parse --show-toplevel or git rev-parse --git-dir, then inspect the exact namespace with git show-ref --heads --tags. For a remote branch, remember that a remote-tracking ref is normally under refs/remotes/<remote>/<branch>, not refs/heads/<branch>. No elevated privilege is needed for these checks. If permissions prevent reading a repository, fix its ownership or access policy through your normal administrative process rather than running broad commands as root.

Done means

  • You can list local refs and recognise the object ID plus full ref-name format.
  • You use --heads and --tags to limit output instead of parsing unrelated refs.
  • You use --verify --quiet with a complete ref path for an exact check.
  • Your --exists script distinguishes present, missing and lookup-error statuses.
  • You know that --dereference adds the object reached through an annotated tag.
  • You have not edited repository files or changed Git state while inspecting refs.