Signed commits in Git¶
Anyone can configure a name and email in Git and make a commit that appears to come from someone else. This is a risk when identity traceability matters, especially in:
- Open source projects with many collaborators.
- Repositories where contributions count toward legal or compliance certification.
- Teams that need to prove who introduced a change.
Git solves this with cryptographic signatures: each commit can come with a mathematical proof that it was generated by the person it claims to be from. GitHub (and GitLab) validate that signature and display the "Verified" badge next to the commit.
flowchart LR
Dev[Your PC] -->|git commit -S| Commit[Signed commit]
Commit -->|hash + signature| GitHub
GitHub -->|verifies signature with your public key| Badge[Verified badge]
1. Choose a signing tool¶
There are two modern ways to sign commits:
| Tool | Algorithm | Support | Notes |
|---|---|---|---|
| GnuPG (GPG) | RSA, Ed25519, ECC | GitHub, GitLab, Bitbucket, Gitea | Classic standard. Requires installing GPG. |
| SSH signing | Ed25519, RSA | GitHub (since 2022), GitLab | Reuses your existing SSH key. Simpler. |
In this guide we use GPG because it's the most universal method. If you already have SSH configured, you can check out the official GitHub guide on SSH signing as an alternative.
2. Install GnuPG¶
- Download Gpg4Win.
- In the installer, only check "GnuPG" (the other tools are optional and add noise to the menu).
- After installing, open Git Bash and verify:
3. Generate the GPG key¶
Generate a new key with the Ed25519 algorithm (recommended) or RSA 4096 (wide compatibility):
The final 0 means the key never expires. If you want it
to expire, replace it with a duration like 1y (one year) or
2y.
After a few seconds, GPG confirms with a message like:
gpg: key 5F2A8B3C9D4E1F6A marked as ultimately trusted
gpg: revocation certificate stored as '/home/user/.gnupg/openpgp-revocs.d/5F2A8B3C9D4E1F6A.rev'
Keep the revocation certificate
The .rev file serves to revoke the key if it's
compromised. Store it in a safe place (not on the same machine).
4. Get the key ID¶
For Git and GitHub to identify your key, you need the long ID:
You'll see something like:
sec ed25519/5F2A8B3C9D4E1F6A 2026-01-15 [SC]
1234567890ABCDEF1234567890ABCDEF12345678
uid [ultimate] Your Name <your.email@example.com>
ssb ed25519/A1B2C3D4E5F6G7H8 2026-01-15 [E]
The ID you need is the one that appears after ed25519/ in the
sec line: in this case, 5F2A8B3C9D4E1F6A.
5. Export the public key in ASCII format¶
To upload it to GitHub:
Copy everything in the output, including the lines:
The armor command
Without --armor, GPG exports the key in binary. GitHub needs
the ASCII format (base64) to paste it in a web form.
6. Upload the key to GitHub¶
- Go to github.com/settings/gpg/new.
- Title: a descriptive name (e.g. "GPG MacBook personal").
- Key: paste the block you copied.
- Click Add GPG key.
If the key's email matches a verified email of your GitHub account, commits signed with that key will be displayed as Verified.
Multiple emails
If you use multiple emails (work + personal), add each one to
the key when generating it, or generate separate keys and
upload each one. For a signed commit to display as verified,
the Git user.email must match an email on the key AND be
verified on GitHub.
7. Configure Git to use the key¶
Tell Git which key to use for signing:
git config --global user.signingkey 5F2A8B3C9D4E1F6A
git config --global commit.gpgsign true # sign ALL commits
git config --global tag.gpgsign true # sign tags too
With commit.gpgsign true, you don't need to remember to type -S
on each commit; Git signs automatically.
If gpg is not in your PATH
On Windows with Git Bash, GPG is installed in
C:\Program Files (x86)\GnuPG\bin\gpg.exe. If Git can't find
it, configure the path manually:
8. Make signed commits¶
If you enabled commit.gpgsign true, all your commits are signed
automatically. If you disabled it:
For merges:
--verify-signatures rejects the merge if any of the incoming
commits are not signed. Useful when the repository requires
mandatory signing (you'll see this in the branch protection rules).
9. Verify signatures locally¶
To inspect a commit's signature:
You'll see:
commit 8a4f9c2b3e1d7a6f...
gpg: Signature made [date]
gpg: using EDDSA key 5F2A8B3C9D4E1F6A
gpg: Good signature from "Your Name <your.email@example.com>"
If the signature is invalid, GPG shows BAD signature. In that case,
don't trust the commit: it may have been tampered with.
10. Rotate a compromised key¶
If your private key is exposed (laptop stolen, backup leaked), revoke the key immediately:
- Import the revocation certificate:
- Publish the revocation on a public key server:
-
Remove the key from GitHub (Settings → SSH and GPG keys).
-
Generate a new key and repeat the upload process.
Preventive expiration
An alternative to the revocation certificate is to generate keys with expiration (e.g. 1 year) and renew them before they expire. It's discipline, but it reduces the window of exposure.
11. Storing GPG credentials (passphrase cache)¶
Every time you sign a commit, GPG asks for your passphrase to
unlock the private key. Typing it on every commit quickly becomes
tedious. The fix is gpg-agent, a background process (analogous to
ssh-agent) that caches the unlocked passphrase for a
configurable amount of time.
Configuring the cache TTL¶
The default TTL is usually 10 hours (3600 seconds × 10) after the
last time you used the key. To change it, edit
~/.gnupg/gpg-agent.conf:
After editing, reload the agent:
Pinentry: the window that asks for the passphrase¶
gpg-agent delegates passphrase capture to a program called
pinentry. The behavior differs per system:
By default it uses pinentry-tty (reads the passphrase from
the terminal). If you prefer a GUI, install pinentry-gnome3
(GNOME) or pinentry-qt (KDE) and select it in
gpg-agent.conf:
GPG Suite installs pinentry-mac, a
native window with a "Save in Keychain" option so the
passphrase is not asked again until the TTL expires.
Gpg4win ships pinentry-qt or pinentry-w32 (selectable from
gpg-agent.conf). The passphrase is cached by gpg-agent until
the configured TTL.
gpg-agent is not the same as Git Credential Manager
gpg-agent caches the passphrase of your GPG key for
signing commits. It does not cache HTTPS credentials. For
HTTPS authentication use Git Credential
Manager
(GCM), which handles user and token but does not sign
commits. They are independent systems.
If VS Code can't find gpg
On Windows with Git Bash, GPG is installed at
C:\Program Files (x86)\GnuPG\bin\gpg.exe. If signing a commit
from VS Code fails with gpg: failed to start..., set the path
manually:
Next step¶
With cryptographic signing covered, you can return to Git and GitHub Fundamentals to review the Pull Requests workflow, or jump to the Practice section for full exercises.