Signed Git Commits

December 01, 2020

When using git, everybody is able to set any name and email address for their commits by using:

git config "John Doe"
git config [email protected]

So anybody can impersonate you and create commits in your name without your approval. To verify it’s you that made a commit you can sign it with your private PGP key. PGP stands for Pretty Good Privacy and is an encryption program that allows you to encrypt and sign data using public key cryptography. By using asymmetric encryption you are holding a private/secret key, that is able to decrypt/sign data and a public key, that can be distributed to anybody to either encrypt data that only you should be able to decrypt with your private key or to verify it’s you that signed a piece of data.

So according to the principles of public key cryptography you are the only one that is able to sign data in your name, because you are the only one holding your private/secret key. Enough theory let’s get started.

Create a PGP key pair

In order to create a PGP key pair we need a PGP client on our system. In this case we are using GNU Privacy Guard or GnuPG. You can install it by using a package manger or you can also do it by hand:

# MacOS
brew install gnupg

# Debian
apt install gpg

# Arch Linux
pacman -S gnupg

# Fedora / CentOS
yum install gpg

# Windows
winget install GnuPG.GnuPG

After you’ve installed GnuPG on your workstation you can create a key pair by running the following command. Make sure to use the same email address as the one used for your GitHub / GitLab account.

$ gpg --gen-key

gpg (GnuPG) 2.2.12; Copyright (C) 2018 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

gpg: directory '/root/.gnupg' created
gpg: keybox '/root/.gnupg/pubring.kbx' created
Note: Use "gpg --full-generate-key" for a full featured key generation dialog.

GnuPG needs to construct a user ID to identify your key.

Real name: John Doe
Email address: [email protected]
You selected this USER-ID:
    "John Doe <[email protected]>"

Change (N)ame, (E)mail, or (O)kay/(Q)uit? O

We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.

gpg: /root/.gnupg/trustdb.gpg: trustdb created
gpg: key EBC5077B9E800AAA marked as ultimately trusted
gpg: directory '/root/.gnupg/openpgp-revocs.d' created
gpg: revocation certificate stored as '/root/.gnupg/openpgp-revocs.d/E1D7E4402C4D7765C9D1DF0AEBC5077B9E800AAA.rev'
public and secret key created and signed.

pub   rsa3072 2020-12-01 [SC] [expires: 2022-12-01]
uid                      John Doe <[email protected]>
sub   rsa3072 2020-12-01 [E] [expires: 2022-12-01]

You can also run gpg --full-generate-key to get advanced options for the key generation like the key size, expiration date, …

Configure Git to use the PGP key

First make sure that your name and email address are set in the git config. For that you can run git config --list. If they are not set or if you want to override them run:

git config --global "John Doe"
git config --global [email protected]

After that you need to get the id of your PGP key so that it can be specified in the git config. To get the id run:

$ gpg --list-keys

gpg: checking the trustdb
gpg: marginals needed: 3  completes needed: 1  trust model: pgp
gpg: depth: 0  valid:   1  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 1u
gpg: next trustdb check due at 2022-12-01
pub   rsa3072 2020-12-01 [SC] [expires: 2022-12-01]
uid           [ultimate] John Doe <[email protected]>
sub   rsa3072 2020-12-01 [E] [expires: 2022-12-01]

To set the signing key and also the gpg executable run:

# Set signing key
git config --global user.signingkey E1D7E4402C4D7765C9D1DF0AEBC5077B9E800AAA

# Set gpg executable
git config --global gpg.program gpg

Configure GitHub / GitLab

Next you need to configure your Git-repository manager (GitHub / GitLab). GitHub / GitLab must be aware that the key that is being used to sign commits is actually yours. Therefore you need to copy your public key (that can be shared with anyone) and paste it in your account settings.

To get the public key run:

$ gpg --export --armour [email protected]




Go to and click on “New GPG key”. Then copy your public key (make sure to also include the beginning and end line) and paste it in the text field on GitHub.

Add GPG key GitHub


Go to Then copy your key (make sure to also include the beginning and end line) and paste it in the text field on GitLab.

Add GPG key GitLab


After configuring your Git-repository manager you can test if it works by doing a test commit. Execute the following commands to create a test setup where you can check if everything works as expected.

# Create test directory
mkdir /tmp/git-signed-commits
cd /tmp/git-signed-commits

# Initialize git repository
git init

# Add test file
echo test > test.txt

# Stage file
git add test.txt

Now you can commit the changes but don’t forget to use the argument -S to sign the commit.

$ git commit -S -m "Initial commit"

error: gpg failed to sign the data
fatal: failed to write commit object

If you are getting the same error run the following:

# Export tty
export GPG_TTY=$(tty)

# Add to bashrc
echo "export GPG_TTY=$(tty)" >> ~/.bashrc

After that you can try running git commit again and it should work fine:

$ git commit -S -m "Initial commit"

[master (root-commit) 4ff4d29] Initial commit
 1 file changed, 1 insertion(+)
 create mode 100644 test.txt

To test if the verification on GitHub / GitLab works add a remote repository you created on GitHub / GitLab (it should be a new repository to prevent any unwanted errors for this test) and push the test commit to it.

# Add remote (only add the one you need)
git remote add github
git remote add gitlab

# Push to remote
git push github master
git push gitlab master

If you take a look at your commit on GitHub / GitLab you will see that the commit is verified, because it got signed with your PGP key.

Verified Commit GitHub

Verified Commit GitLab

Written by default