Turn Git Object IDs into Useful Names with git name-rev

git name-rev turns a bare 40-character commit ID from a bug report into a name you recognise, such as main~2 or tags/v1.0. You will also be able to annotate text containing full commit IDs and restrict which refs Git may use.

Allow about ten minutes. You need Git and a repository containing at least one commit. The examples use Git 2.43.0, the version installed on this machine as package git-man 1:2.43.0-1ubuntu7.3. They are read-only: git name-rev does not create, move or delete refs, so there is no state to undo and no elevated privilege is required.

1. Check the installed command

Run these ordinary, read-only checks in the repository you want to inspect:

$ git --version
git version 2.43.0
$ git name-rev --help
usage: git name-rev [<options>] <commit>...

The command accepts a commit-ish, which means a revision format understood by git rev-parse. A branch name, tag name, HEAD or a full object ID can therefore be useful input. The names it returns are relative to refs that exist locally. A remote-tracking ref is local too, but an un-fetched branch on a server is invisible.

Checkpoint: Confirm that you are in the intended repository before interpreting the result:

$ git rev-parse --show-toplevel
/path/to/project
$ git rev-parse HEAD
<40-character-commit-id>

2. Name the current commit

Pass one or more revisions as ordinary arguments:

$ git name-rev HEAD
HEAD main

The exact first field depends on the argument. For a full ID, Git prints that ID followed by the best matching symbolic name. A commit at the tip of a local branch normally receives the branch name. An ancestor may receive a suffix such as ~2, meaning two first-parent steps behind the named ref.

Compare a commit ID with its normal Git history when you need context:

$ commit_id=$(git rev-parse HEAD~2)
$ git name-rev "$commit_id"
<40-character-commit-id> main~2

The name is a description of reachability from local refs, not a permanent identity. If branches are moved, tags are added, or the repository is fetched later, the preferred name can change. Keep the object ID when you need an unambiguous reference.

3. Prefer tags when release context matters

Use --tags when branch names would distract from release information:

$ git name-rev --tags HEAD
<40-character-commit-id> tags/v1.0~3

This only considers tags. If no tag can reach the requested commit, the default output is undefined. That is a useful distinction from a branch-based answer: it says the command could not find a matching tag in the refs visible to this clone.

For scripts that need only the name, add --name-only:

$ git name-rev --tags --name-only HEAD
v1.0~3

With --tags, --name-only omits the usual tags/ prefix. Without --tags, it prints only the selected ref-based name, such as main. Do not parse the normal two-column form if your consumer only wants a name; choose this option explicitly.

4. Restrict or exclude refs

Use --refs when the answer must come from a known family of refs. Its value is a shell pattern matched against branch, tag or fully qualified ref names:

$ git name-rev --refs='refs/heads/main' "$commit_id"
<40-character-commit-id> main~2

Patterns can be given more than once. This example permits either of two local branches:

$ git name-rev \
    --refs='refs/heads/main' \
    --refs='refs/heads/release/*' \
    HEAD

Add --exclude to remove refs from the permitted set. When both options are present, a ref must match at least one --refs pattern and no --exclude pattern:

$ git name-rev --refs='refs/heads/*' --exclude='refs/heads/feature/*' HEAD

Quote patterns so the shell does not expand a wildcard against files in the current directory. The --no-refs and --no-exclude forms clear patterns already supplied on the command line. They are mainly useful when composing an option list programmatically.

5. Annotate logs or other text

--annotate-stdin reads standard input and replaces full 40-character SHA-1 commit IDs with the ID and its name. It does not replace abbreviated IDs:

$ git log --pretty=oneline | git name-rev --annotate-stdin
<40-character-commit-id> (main) Add a release check
<40-character-commit-id> (main~1) Update the build
<40-character-commit-id> (tags/v1.0) Start the project

Use --name-only when the IDs should be replaced by names rather than retained:

$ git log --pretty=oneline | git name-rev --name-only --annotate-stdin
main Add a release check
main~1 Update the build
v1.0 Start the project

The output depends on your history and refs. A commit may be named differently after another branch or tag is created, so generated reports should include the repository state or the original IDs if they need to be reproduced later.

6. Handle missing names deliberately

By default, an existing but unreachable-from-the-selected-refs commit is printed with the name undefined. Use --no-undefined when that condition must fail a check:

$ git name-rev --no-undefined "$commit_id"
<40-character-commit-id> main~2

To obtain a stable abbreviated object ID when no symbolic name is available, use --always. This is a fallback, not a branch or tag lookup:

$ git name-rev --always --refs='refs/tags/*' "$commit_id"
<40-character-commit-id> v1.0

In that example the earlier commit_id is the tagged commit, so the tag wins. If the filtered refs cannot name a commit, Git can show a unique abbreviated commit object instead. Do not mistake that fallback for evidence that a tag exists. If a script needs to distinguish a symbolic name from a fallback, keep the ref filter and test the output or use a separate git show-ref policy check.

Trap: an invalid object ID is not the same as a valid commit with no matching ref. Check that input with git rev-parse --verify first when it comes from a file, hook or external system. Do not silently turn a misspelled ID into a successful report.

7. List every reachable commit

Use --all to list commits reachable from all refs:

$ git name-rev --all
<commit-id> tags/v1.0
<commit-id> main~1
<commit-id> main

This can produce a large result in a busy repository, and the chosen name is still dependent on local refs. Combine it with --tags, --refs or --exclude when you need a narrower report. Redirecting the output to a file changes that file, so check the destination before using shell redirection in an automated job.

Done means