By default, git commit writes Author and Committer fields into
the commit. These are plain strings from user.email in your config.
Anyone can put someone else's name there:
git config user.email "linus@kernel.org"
git commit -m "fix: ..."
# Author: Linus Torvalds <linus@kernel.org>
This is not forgery in any cryptographic sense. It is just metadata. If you need proof that a commit was really made by the owner of a given identity, you need a signature.
Setting up GPG signing
# Generate a key (if you do not have one)
gpg --full-generate-key
# Find the key ID
gpg --list-secret-keys --keyid-format=long
# Configure Git
git config --global user.signingkey <KEY-ID>
git config --global commit.gpgsign true
# Optional: sign tags too
git config --global tag.gpgsign true
After this, every commit is signed automatically. Without the
commit.gpgsign flag you can sign individual commits:
git commit -S -m "..."
SSH signing (Git 2.34+)
If you already have an SSH key for GitHub, you can use it for commit signing instead of a separate GPG key:
git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_ed25519.pub
git config --global commit.gpgsign true
One key for push and for signing. GitHub supports SSH signature verification on the same settings page where you upload auth keys (see ssh-keys-git).
What the remote sees
On GitHub, signed commits appear with a green Verified badge. The
signature is checked against the public key you uploaded in your
profile settings. Unsigned commits show no badge.
# Verify signatures locally
git log --show-signature
# commit abc123
# gpg: Signature made ...
# gpg: Good signature from "Your Name <you@example.com>"
Can you require signatures?
- On GitHub: branch protection → "Require signed commits." Pushes without a signature are rejected.
- On a bare server: via a server-side hook (see force-push);
a pre-receive hook checks
git log --show-signature.
Requiring signatures makes sense when identity spoofing is a real risk: open-source projects with thousands of contributors, or enterprise environments with compliance requirements.
Pitfalls
- gpg complains "Inappropriate ioctl": gpg cannot prompt for the
passphrase from the terminal. Fix it by adding
export GPG_TTY=$(tty)to your.bashrc. - Signature not showing on GitHub after uploading the key. The
email in your Git
user.emailmust match the email in the GPG key and the verified email in your GitHub account. Any mismatch and the badge does not appear. - Key expiry. GPG keys are typically created with an expiry date. After expiry, old signatures remain valid, but new ones require you to extend the key first.
- CI with signed commits. If CI creates a merge commit, the bot also needs a key. Alternatively, enable "squash and merge" to avoid creating merge commits.