Home / Alt manpages / gitformat-signature(5)

  • gitformat-signature(5)
  • File format
  • linux

Choose and Verify Git Signature Formats Without Guesswork

A green tick next to a commit only tells you the signature checks out, not that you should trust the person behind the key. This guide shows you how Git stores signatures, how to pick a signing format for a repository, and how to verify signed commits or annotated tags without conflating cryptographic validity with actual trust. The examples match Git 2.43.0 from the git-man package installed on this machine.

Allow about fifteen minutes. You need Git and a repository. Signing also needs the external program and key material for whichever format you choose, this guide does not generate keys, touch an agent, or ask you to trust an unfamiliar one. The inspection commands are ordinary user commands and none of them need sudo.

1. Check the local Git version and the signing interface

Start by recording the version that will actually interpret your repository configuration:

$ git --version
git version 2.43.0
$ git commit -h 2>&1 | grep -E -- '-S|gpg-sign'
                  [(--trailer <token>[(=|:) <value>])...] [-S[<keyid>]]
    -S, --[no-]gpg-sign[=<key-id>]

The manpage describes signatures on Git objects and transactions. For everyday work, the two cases that matter are signed annotated tags and signed commits. A signed tag appends its detached signature to the tag object. A signed commit stores the signature as a multiline gpgsig header, with continuation lines prefixed by a space.

Checkpoint: if your installed command does not show -S, stop and read that installation's own documentation. Do not lift a signing command from a different Git release and run it against an unverified script.

2. Inspect the objects before changing configuration

Use Git's own object printer to see what is actually stored. This is read-only, and it works on unsigned objects too:

$ git cat-file -p HEAD
tree <tree-object-id>
parent <parent-object-id>
author Example User <[email protected]> <timestamp>
committer Example User <[email protected]> <timestamp>

commit message
$ git cat-file -p <annotated-tag-name>
object <commit-object-id>
type commit
tag <tag-name>
tagger Example User <[email protected]> <timestamp>

tag message

Swap the angle-bracketed values for your own repository's values. An unsigned commit has no gpgsig header, and an unsigned annotated tag has no signature block after its message. Do not hand-edit either object, changing its contents changes its object ID and can break references or published history.

3. Choose the backend deliberately

Git selects the signature format with gpg.format. Current upstream configuration docs call the values openpgp, x509 and ssh, while the Git 2.43.0 signature-format manpage labels the corresponding blocks gpg, x509 and ssh. For the local Git configuration, use the documented configuration value, not the ASCII armour heading:

$ git config --local gpg.format ssh
$ git config --local --get gpg.format
ssh

--local writes this repository's .git/config. To test a value without writing anything, use a one-off override instead:

$ git -c gpg.format=ssh config --get gpg.format
ssh
$ git -c gpg.format=x509 config --get gpg.format
x509

Pick the format that matches the verification ecosystem your collaborators already use. openpgp uses the OpenPGP backend, ssh uses SSH signing, and x509 uses X.509 signing, and Git can call different helper programs for each. A format setting is not a key, certificate or trust decision on its own, so changing it does not make signing start working by itself.

Security checkpoint: inspect the effective settings before signing anything:

$ git config --show-origin --get-regexp '^gpg\.'
file:.git/config	gpg.format ssh

The output can include global and system configuration and can expose helper paths, so review it before using a shared repository or automation account. If you decide not to keep the repository setting, remove only that key with git config --local --unset gpg.format so Git falls back to its normal default. Confirm the exact key with --get-regexp first, since this undo command changes configuration too.

4. Create or inspect a signed commit

Once the backend and key material are ready, sign a normal commit with -S. Supplying an explicit key ID is optional and backend-specific:

$ git commit -S -m 'Record the release decision'
[main <commit-id>] Record the release decision
$ git show --format=raw --no-patch HEAD
commit <commit-id>
tree <tree-object-id>
gpgsig -----BEGIN <signature-type> SIGNATURE-----
 <continuation-lines-prefixed-by-a-space>

The exact armour heading and helper output depend on the selected format, so do not compare signature text byte-for-byte across different backends. The structural check that matters is the gpgsig header and its space-prefixed continuation lines.

Warning: if signing fails, leave the commit unsigned and investigate the helper's error, configured key and agent. Do not disable verification or paste private key material into a repository. If no commit was created there is nothing to undo; if you accidentally committed sensitive material, stop and follow your normal incident and history-rewrite process rather than treating a fresh signature as a fix.

5. Verify the object and read the result carefully

Verify a commit with the command built for commits:

$ git verify-commit -v HEAD
gpg: Good signature from "Example User <[email protected]>"
tree <tree-object-id>
parent <parent-object-id>
author Example User <[email protected]> <timestamp>
committer Example User <[email protected]> <timestamp>
$ printf 'verification status: %s\n' "$?"
verification status: 0

For an annotated tag, verify the tag name itself, not the commit it points to:

$ git verify-tag -v <annotated-tag-name>
$ printf 'verification status: %s\n' "$?"
verification status: 0

A successful verification means the signature matches the signed payload and the verifier accepts the key or certificate it has available. That is all it means. It does not, on its own, prove the identity behind the key is who you expect, so read the fingerprint, certificate chain or SSH allowed-signers result according to your organisation's trust process. A warning about an uncertified key is not a cryptographic failure, but it is a reason to pause before accepting authorship or release provenance.

6. Diagnose the common boundary errors

  • No signature found: inspect the object with git cat-file -p. You may be verifying an unsigned commit, a lightweight tag, or the wrong object type entirely.
  • Bad signature: the payload and signature simply do not match. Fetch the intended object again and check you are not verifying a rewritten local history.
  • Unknown or untrusted identity: verify the key fingerprint or certificate through a channel you already trust. Do not solve this by lowering trust settings globally.
  • Signing helper failure: check gpg.format, the relevant helper program and key availability. Git's signature format controls how signing happens, it does not install the backend for you.

The visible ASCII armour is useful for spotting a format at a glance, but the object's position matters more: tags carry the block in the tag payload, commits carry it in gpgsig, and a merge of a signed tag can carry the entire tag object in a mergetag header. Preserve whitespace when inspecting these headers, a continuation line that loses its leading space is no longer the same Git object.

Done means

  • You recorded the Git version used for the workflow.
  • You identified whether the object is a signed commit or an annotated tag.
  • You selected gpg.format to match the agreed verification ecosystem.
  • Verification passed: git verify-commit or git verify-tag returned status 0.
  • You checked identity separately: trust evidence was reviewed apart from the cryptographic result.