Signing Commits

Anyone can set user.name and user.email to anything, so the author line of a commit proves nothing on its own. Signing commits with a key you control lets others verify that a commit really came from you — and GitHub shows a Verified badge next to it.

Why it matters

Git records whatever identity is configured. A commit claiming to be from a well-known maintainer could have been made by anyone. Signatures add cryptographic proof: the commit (or tag) is signed with your private key, and anyone with your public key can check it. Some organisations and open-source projects require signed commits on protected branches.

Choosing a key type

FormatNotes
SSHSimplest — reuse the SSH key you may already have for pushing (lesson 31). Supported since Git 2.34.
GPG / OpenPGPThe traditional method; needs GnuPG and its own key management.
X.509 (S/MIME)Certificates issued by an organisation; common in some companies.

Signing with an SSH key

Tell Git to use SSH signatures and which public key to sign with:

$
git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_ed25519.pub

Sign a single commit with -S, or sign everything automatically:

$
git config --global commit.gpgSign true
git config --global tag.gpgSign true
echo "Omelette: eggs, butter" > omelette.txt
git add omelette.txt
git commit -m "Add omelette recipe"
Output
[main 72fe997] Add omelette recipe
 1 file changed, 1 insertion(+)
 create mode 100644 omelette.txt

(The setting names contain "gpg" for historical reasons; they apply to SSH signing too.)

Verifying signatures

To check SSH signatures locally, Git needs to know which keys belong to whom. That's an allowed signers file: one line per person, with their email and public key.

$
echo "sam@example.com $(cat ~/.ssh/id_ed25519.pub)" > ~/.ssh/allowed_signers
git config --global gpg.ssh.allowedSignersFile ~/.ssh/allowed_signers
git log --show-signature -2
Output
commit 72fe997816d883bedac1ad6a1757aecf8eb36c1e (HEAD -> main)
Good "git" signature for sam@example.com with ED25519 key SHA256:BcVhKgf1CLwlPGvEls5r20nskRyXxBFW5IKP+fc93xE
Author: Sam Rivera <sam@example.com>
Date:   Mon Mar 2 09:56:00 2026 +0000

    Add omelette recipe

commit c4f5e477cc93474bd7d8597fe508a0ba50d132f6
Author: Sam Rivera <sam@example.com>
Date:   Mon Mar 2 09:14:00 2026 +0000

    Add pancake recipe

The newest commit has a good signature; the older one was made before signing was turned on, so it has none. git verify-commit HEAD and git verify-tag v1.0 check a single commit or tag, and git log --format="%h %G? %s" prints a one-letter status (G good, N none, B bad…):

$
git log --format="%h %G? %s"
Output
72fe997 G Add omelette recipe
c4f5e47 N Add pancake recipe

Showing "Verified" on GitHub

Add the same public key to GitHub as a signing key: Settings → SSH and GPG keys → New SSH key → key type Signing Key. (An SSH key used for both pushing and signing has to be added twice, once as each type.) Your signed commits then show a green Verified badge, as long as the commit email matches a verified email on your account.

GitHub's optional vigilant mode also marks your unsigned commits as "Unverified", making impersonation easy to spot. Commits you make through GitHub's website are signed by GitHub automatically.

GPG in brief

$
gpg --full-generate-key                  # create a key
gpg --list-secret-keys --keyid-format=long
git config --global user.signingkey 3AA5C34371567BD2
git config --global commit.gpgSign true
gpg --armor --export 3AA5C34371567BD2    # paste into GitHub → New GPG key

Signed tags

git tag -s v1.0 -m "Release 1.0" creates a signed annotated tag (or plain -a when tag.gpgSign is on). Signing release tags is common even in projects that don't sign every commit, because it lets users verify that a release really came from the maintainers.

Try it yourself

Configure SSH signing with your own key, make a signed commit, and check it with git log --show-signature. Add the key to GitHub as a signing key, push, and look for the Verified badge on the commit page.