It is good practice to sign your commits, the reason you sign a commit is to show that a commit was created by you. By default git accepts whatever author you provide it with, so anyone can pretend to be you. If someone would get access to your repository, for example by stealing your SSH-key, or cracking your password, they can commit whatever they want. Of course having an password protected SSH-key and a strong password with 2FA is good protection, but it still does not validate that you created the commit.

The default way this is handled is by creating a GPG key, you can see this as your personal signature that you sign your work with.

The default tool to use is GnuPG, and is available on every common operating system.

If you want to get it done right away, there is an excellent tutorial on GitHub or Gitlab.

This article helps you understand what GPG is and what else you can do it with it.

Installation

If not yet installed, you can install GPG using any common Linux package manager, as well as HomeBrew

brew install gpg

Creating a key

To create a new key, run the following command:

gpg --full-gen-key

The defaults are sensible, make sure you pick a strong password, and use a real and email address. This key is meant to identify you after all.

After you complete the questions, you have generated a personal keypair. You can run the following commands to see the keys:

gpg --list-keys
gpg --list-secret-keys

Always protect your secret key, no one can have this but you.

How to use

These are some common use cases:

Sign a file, output a test.doc.asc signature file

gpg --clearsign test.doc

Export your public key, to share with someone

This example shows how to find your key by email. You can have multiple keys for the same email address, GPG will pick the first one then. It is safer to do it by ID as shown further down in the article, but works just fine if you only have one key. Note: the –armor flag tells GPG to output in base64 encoded data, by default GPG outputs binary data.

gpg --export --armor your@email.com > your-public-key.txt

Export your private key for a backup, please handle this securely

gpg --export-secret-keys --armor your@email.com > your_super_secret_private_key.txt

Import someone else’s key

gpg --import someone_elses_public_key.txt

Encrypt a file asymmetrically, and sign it

For this you need to import the recipients public key first:

gpg --encrypt --sign --recipient someone@else.com doc.txt

Compress a file, sign it, and output in binary format

gpg --clearsign test.doc

Signing commits

What we want to achieve is to sign our commits using our private key, so it can be validated remotely using our public key.

A safe way to identify a GPG key is to use the longer format, the default short format is sensitive to collision attacks. Therefore we use the longer 64bit/16hex character ID. To find our ID:

You’ll first see “sec”, then the encryption method used, then after the forward slash, you find the 16 character long key ID.

gpg --list-secret-keys --keyid-format=long

To tell git to use this as your ID:

git config --global user.signingkey {keyid}

To tell git to sign your commits by default:

git config --global commit.gpgsign true

On the remote repository there will be a GPG key link in your settings. Just like the public key of an SSH keypair, you need to add the GPG public key here. You can export the key by email or ID. It’s safer by ID, because you can have multiple keys with the same email address.

Note: the ID of the secret key is the same as that of the public key, they’re a pair after all.

gpg --export --armor your_long_key_id

The next time you push code to the remote repository of your choice, you should see an indication the commit was verified.

Tips

Adjusting cache timeout of your private key password

By default when you are prompted for your password, the password is cached for 10 minutes. After 10 minutes you will be prompted again. You can adjust this timeout by creating the following file if it does not exist:

mkdir ~/.gnupg/
cd ~/.gnupg/
touch gpg-agent.conf

Here you can set two values:

  • default-cache-ttl: the timeout in seconds after the last gpg activity. Default is 600sec.
  • max-cache-ttl: the timeout in seconds after you last entered your password. Default is 2 hours.

For example, if you want to set the timeout for both to an hour:

default-cache-ttl 3600
max-cache-ttl 3600

After this you need to restart the gpg agent:

gpgconf --kill gpg-agent
gpg-agent --daemon --use-standard-socket

Further reading