A release maintainer wants to know whether a particular key signed the exact commit being reviewed. A name and email in Git metadata cannot answer that question: anyone can configure those strings. A digital signature binds an object to a key and detects changes to the signed data. This guide uses Git's SSH signing support in a disposable repository, then explains the separate decision of trusting that key. You need Git 2.34 or later and OpenSSH tools. Run the Bash commands in Git Bash on Windows or a Bash terminal elsewhere.
Identify the object and the trust decision
A commit signature covers the commit object, including its tree, parents and metadata. An annotated tag has its own object and can carry its own signature. Signing a tag does not retroactively sign every commit reachable from it, and signing a commit does not automatically sign a tag pointing to it. Decide whether your review process requires signed commits, signed release tags or both. The signature answers a precise question about one object; the repository policy decides whether that answer is sufficient.
Cryptographic validity and trusted identity are different checks. A signature can verify mathematically with a public key even when your organization has never approved that key. For SSH verification, Git can consult an allowed-signers file mapping principals to accepted public keys. Obtain those keys through a trusted channel and review changes to the trust file. A key copied from an untrusted contribution cannot establish the contributor's identity by itself. Signature verification also does not establish that the code is safe, tested or approved.
Separate authentication from signing
An SSH key used to authenticate a network connection proves access to an account or server. An SSH signing key signs repository objects locally. The same key material can sometimes serve both roles, but configuration and trust decisions remain separate. Registering a key for repository access does not automatically configure Git's signing format or local verification policy. Teams may choose separate keys to make rotation, access removal and auditing easier to reason about.
In the example, user.signingkey points to a disposable private key file. Keep that file private and outside versioned project content. A normal setup might use a public key whose corresponding private key is available through an SSH agent instead. Never paste a private key into a workflow, issue, tutorial output or repository. The lab ignores its temporary files and never sends them to a service. Replace the whole demonstration setup with your team's key-management process before using signing for real releases.
Configure and verify deliberately
The gpg.format setting selects ssh; the name reflects Git's signing interface and does not mean this lab uses a GPG key. The allowedSignersFile setting supplies the path Git reads during local SSH verification. The file associates learner@example.test with the generated public key. It is a small trust policy, not a list of repository commit authors. A commit may claim one author while being signed by a different authorized maintainer, so inspect both fields when that distinction matters.
The -S option signs a commit. For a tag, lowercase -s creates a signed annotated tag; capitalization matters. Verification commands return a nonzero status when verification fails, which makes them useful in scripts. git log's %G? placeholder summarizes the signature status, while %GS reports the recognized signer. Do not build a release gate around a human-readable message containing a fingerprint. Use command status, the expected object identifier and a reviewed trust policy, then record the evidence you need.
Understand rewritten history and rotation
A rebase, amend or cherry-pick creates a new commit object. The old signature belongs to the old object; it cannot be copied as proof for changed data. If your policy requires signatures on rewritten commits, arrange for the appropriate signer to sign the new objects. First coordinate history changes with collaborators, because signatures do not remove the normal risks of replacing shared commits. Compare the resulting object identifiers and verify the intended tip rather than assuming that an earlier check still applies.
Keys also have operational lifetimes. A lost or compromised key needs a response that updates access, signing configuration and verification policy. Historical verification may require carefully retained public-key evidence and validity information. Avoid silently replacing the allowed-signers file and then interpreting every historical result as if the new policy had always existed. Explain how your team evaluates old releases after rotation. This lesson demonstrates mechanics; the release policy should explicitly identify who can sign, what they sign and how their keys are reviewed.
Sources and prerequisites
Begin with Git tags, configuration and history. Consult the official signing configuration, commit verification and tag verification references when selecting a format and interpreting results.
Sign and Verify Git Commits and Tags Summary
- Verify the exact commit or tag under an explicit trusted-key policy.
- Authentication settings and signing settings serve different purposes.
- Rewritten commits need their own signatures; a signed tag remains a separate object.
Sign and Verify Git Commits and Tags Examples
Each example shows the code, the output it produces and what each part does.
Verify a locally signed commit
Create a fresh directory and run the complete sequence. The key has an empty passphrase only because it is disposable lab material. Keep real signing keys under your normal protection policy. The command prints G after both the cryptographic signature and allowed signer are recognized.
Repository initialization and commit summaries also appear. The output fence shows the final verification status. This result depends on the locally configured trust file; it is not a claim that a hosting service or another teammate trusts the same key. No network access or account registration is involved.
mkdir signing-lab
cd signing-lab
git init -b main
git config user.name Learner
git config user.email learner@example.test
ssh-keygen -q -t ed25519 -N '' -f signing_key
printf 'learner@example.test %s\n' "$(cat signing_key.pub)" > allowed_signers
printf 'signing_key*\nallowed_signers\n' > .gitignore
git config gpg.format ssh
git config user.signingkey ./signing_key
git config gpg.ssh.allowedSignersFile ./allowed_signers
printf 'Signed notes\n' > notes.txt
git add notes.txt .gitignore
git commit -S -m 'Signed demonstration'
git log -1 --format='%G?'GCommon Sign and Verify Git Commits and Tags Mistakes
Treating a signature as a code review
A recognized signing key establishes an object-level signing result under your policy. It does not run tests, check dependencies or approve a pull request. Keep signature requirements alongside the other release checks, and verify the actual object you intend to publish.
Sign and Verify Git Commits and Tags in Real Projects
Create and verify a signed release tag
Continue in signing-lab. Create a signed release tag, verify it and print the signer of the underlying commit. Predict whether signing the tag changes the existing commit's identifier before running the commands.
git tag -s -m 'Demo release' v1
git verify-tag v1
git log -1 --format='%GS'learner@example.testVerification also reports a good signature and a variable key fingerprint. The displayed signer comes from the allowed-signers policy. The tag is a separate object pointing to the commit, so creating it does not rewrite that commit. To examine the distinction further, compare git rev-parse v1 with git rev-parse 'v1^{}': the first identifies the annotated tag object and the second peels it to its target.
Sign and Verify Git Commits and Tags FAQ
Why can Git report an unknown signer for a valid SSH signature?
The public key may be sufficient to check the cryptography while your allowed-signers policy does not recognize an accepted principal for that key. Inspect the trust-file path, its contents and the expected signer before changing anything. Obtain the key through a trusted process instead of adding whatever key the object presents. A verification policy becomes ineffective when it automatically trusts every unfamiliar signer.
Does GitHub SSH access automatically enable signed commits?
No. Repository authentication and object signing use separate settings and verification processes. You still select the signing format, configure the signing key and choose when Git signs commits or tags. A hosting service may also distinguish authentication and signing registrations. Check that service's current documentation for its verification behavior, and do a local verification of the exact object instead of relying only on the fact that an SSH push succeeded.
Can I sign an existing commit without changing its hash?
Adding a signature changes the commit object, so the resulting commit has a different identifier. Amending or rebuilding commits to sign them is a history change and may affect descendants. Coordinate that operation if the commits are shared. A signed annotated tag can instead identify an existing commit without rewriting it, but that supplies a tag signature rather than a signature embedded in the commit itself.
Should the allowed-signers file be committed to the repository?
That depends on where your trust policy is anchored. A versioned file can make reviewed policy changes visible, but a file supplied by the same untrusted branch you are verifying cannot independently establish trust. Some teams maintain the policy outside the repository or use an independently reviewed version. Decide who may change it, how updates are authenticated and which policy version applies to a historical release before automating verification.
Sign and Verify Git Commits and Tags Exercises
Answer each one and check it instantly. If you get stuck, open the hint before the answer.
In the lab, which principal should %GS report after successful verification?
Sign and Verify Git Commits and Tags Quiz
2 questions to check what you learned.
Which operation creates a separate signed object without rewriting its target commit?
- Creating a signed annotated tag
- Changing the commit's author with amend
- Rebasing the commit onto a new parent
What does a trusted good signature establish in this lesson?
- Every reachable commit passed all tests
- The accepted key signed the exact object being verified
- The hosting account approved the code review