Before you deploy a release, run git verify-tag to check whether the tag actually carries a valid GPG signature rather than just existing. This guide shows a successful check next to a merely-existing tag, and how to inspect the tag object when the result needs more context. The workflow is read-only: git verify-tag does not create, move or delete tags.
Allow about ten minutes for a known repository and a little longer if the signing key is not already in your keyring. This guide describes the Git 2.43.0 command supplied by the git and git-man packages, both version 1:2.43.0-1ubuntu7.3. Other Git releases may format diagnostics differently, but the exit status and the options documented here are the useful parts to build into a check.
Run these ordinary, unprivileged commands in the repository that contains the tag. No sudo is needed:
$ command -v git
/usr/bin/git
$ git --version
git version 2.43.0
$ git verify-tag -h
usage: git verify-tag [-v | --verbose] [--format=<format>] [--raw] <tag>...
The command accepts one or more tag names. The manual describes the operands as SHA-1 identifiers of tag objects, while normal Git use also resolves a tag name to the object you mean. Use an exact tag name in scripts, and do not assume a lightweight tag has a signature: signatures are created on annotated tag objects.
Checkpoint: you have confirmed the Git version and know the exact tag or tags you intend to examine.
First make sure the tag exists locally, then verify it:
$ git show-ref --tags --verify refs/tags/RELEASE_TAG
0123456789abcdef0123456789abcdef01234567 refs/tags/RELEASE_TAG
$ git verify-tag RELEASE_TAG
gpg: Signature made ...
gpg: Good signature from "Release signer ..."
Release signer ...
Replace RELEASE_TAG with a real tag such as v2.43.0. The hash and GPG lines are examples of the shape of successful output, not fixed text. The signer, key identifier and timestamp come from your local GPG installation. A successful command exits with status zero.
A valid cryptographic signature only proves the tag object was signed by the corresponding private key. Do not treat the signer's name as proof the release is the one you intended: you still need to decide whether that key belongs to the project or maintainer you trust.
For a manual check, read the output. For automation, test the status immediately after the command:
$ if git verify-tag RELEASE_TAG > /tmp/git-verify-tag.out 2>&1; then
> echo "signature check passed"
> else
> status=$?
> echo "signature check failed (status $status)" >&2
> sed -n '1,20p' /tmp/git-verify-tag.out >&2
> exit "$status"
> fi
signature check passed
The temporary file is only for this diagnostic example. Remove it once you have finished reviewing the output:
$ rm -- /tmp/git-verify-tag.out
That removal is safe because the file contains captured diagnostics, not repository data. If the command fails, preserve the output until you have recorded why. Do not turn a failed verification into success by ignoring the exit status.
Pass multiple tag names to one invocation when you want every supplied tag checked:
$ git verify-tag v2.42.0 v2.43.0
gpg: Good signature ...
gpg: Good signature ...
The overall command must succeed for the batch to be useful. In a shell loop, stop on the first failure and print the tag that caused it:
$ for tag in v2.42.0 v2.43.0; do
> git verify-tag "$tag" || { echo "failed: $tag" >&2; exit 1; }
> done
Quote tag variables even though common version tags contain no spaces. Quoting keeps the command safe if a value later comes from a file or another process. Do not feed arbitrary option text into the command through an unreviewed variable.
Add --verbose or -v when you need the tag contents printed before validation:
$ git verify-tag --verbose RELEASE_TAG
object 0123456789abcdef0123456789abcdef01234567
type commit
tag RELEASE_TAG
tagger Release signer <[email protected]> ...
Release RELEASE_TAG
gpg: Good signature ...
This helps you check what the signature covers: the referenced object, object type, tag name and tagger information. It does not change the object, and it does not verify the contents of the referenced commit or tree beyond what the tag itself identifies. Inspect the tagged commit separately with a command such as git show RELEASE_TAG if you need to review it.
The --raw option writes raw GPG status output to standard error instead of Git's usual human-readable output:
$ git verify-tag --raw RELEASE_TAG 2>gpg-status.txt
$ sed -n '1,20p' gpg-status.txt
[GNUPG:] ...
The exact status records depend on the installed GPG version and keyring. Treat this stream as machine-facing diagnostic data, not as a stable sentence to show users. The command still reports success or failure through its exit status. Delete gpg-status.txt after review if it is no longer needed; it can contain signer and key metadata.
If Git reports that the tag cannot be found, check the local tag list and fetch policy before doing anything else:
$ git tag --list 'RELEASE_TAG'
$ git show-ref --tags --verify refs/tags/RELEASE_TAG
A missing tag is not a signature failure: it means this clone does not have the named reference. Fetching tags changes local repository state, so review the remote and the refspec first. If you do fetch, use your normal repository policy and verify the tag again afterwards. Do not delete or recreate a tag to make a check pass.
Warning: if GPG says the key is missing, the signature cannot be trusted on this machine yet. Obtain the signing key from the project's documented, independently trusted distribution channel, import it according to your local security policy, and rerun the check. Do not blindly import a key from an arbitrary keyserver or accept an unknown fingerprint just because the tag name looks familiar.
Warning: a bad signature, an unknown signer or an unexpected fingerprint is a stop condition for release verification. Compare the full fingerprint with the project's primary documentation or another trusted channel. Do not use --raw to bypass the result; it only changes diagnostic formatting.
git verify-tag.