Signing Git commits with GPG on Windows (feat. SourceTree)

Git allows us to commit as anyone we want. Simply putting user.name and user.email in .gitconfig, you can be literally anyone. This also means that anyone can use your identity. Check out A Git Horror Story: Repository Integrity With Signed Commits by Mike Gerwitz to see how this can be worse.

To prevent this mess, Git allows us to sign commits using GPG (GNU Privacy Guard) to identify our works. Thankfully, Git for windows provides the command-line version of GPG out of the box.

However, most Windows users might want to use GUI-based Git applications like SourceTree, but using it with GPG sign enabled is always a real pain. Most of GUI-based VCS applications like SourceTree uses git.exe internally, which is exactly same as what we used in the Git Bash shell, to do their works.

For instance, SourceTree, utilizes `git.exe` internally to do their works.

But here is the question: "How these applications cope with my key passphrase when signing commits?". In the command line, we just type a passphrase, done. But how about in GUI applications? The answer is "They can't".

But thanks to gpg4win, interacting with GUI applications becomes quite simple. gpg4win utilizes gpg-agent and pinentry, a small collection of dialog programs, to allow GnuPG to read passphrases from a user in a secure manner.

This post consists of two paths: if you already have generated GPG key, go directly to 'Part 1-2'. If you are first to this or want to start over, follow 'Part 1-1' and skip 'Part 1-2'. Be sure gpg4win is installed for both paths.

Part 1-1: Creating your first GPG key

Start up Kleopatra, the gpg4win key manager. Choose "New Key Pair" or simply Ctrl + N:

Choose OpenPGP key pair:

Enter your name and e-mail address, and move to 'Advanced Settings...':

In Key Material section, set both RSA key size to the maximum value of 4096:

Review your information and key parameters, and press "Create Key":

We are almost there. Type a passphrase to secure your key:

Done. You can optionally back up the generated key, just in case.

Keys are listed in the main window. Proceed to Part Two.

Part 1-2: Import GPG key to Kleopatra

Open up Git Bash shell and use gpg --list-secret-keys command to list GPG keys for which you have both a public and private key.

$ gpg --list-secret-keys
C:\Users\bskim\.gnupg/secring.gpg
---------------------------------
sec   4096R/C8528BF2 2018-01-18
uid                  Bumsoo Kim <bskim45@gmail.com>
ssb   4096R/8911C702 2018-01-18

From the list of GPG keys, copy the GPG key ID you'd like to use. For this example, the GPG key ID is C8528BF2.

Now export your private key with command gpg --export-secret-key -a {KEY_ID} > private.asc. Replace KEY_ID with your key id copied above. Your private key is saved to private.asc file.

$ gpg --export-secret-key -a C8528BF2 > private.asc

Launch Kleopatra, click 'Import' or simply Ctrl + I and pick a private key file created above:

You will be prompted to confirm that the key file is yours. Press 'Yes':

Your key is successfully imported:

Part 2: Tell Git to interact with gpg4win

So far, we created/imported key to Kleopatra, which is default key manager for gpg4win. Keys are ready, but we need to tell Git to use gpg4win for signing commits instead of embedded gpg.exe.

Open up Git Bash shell, type this command replacing KEY_IDwith your own GPG key id.

$ git config --global user.signingkey C8528BF2

FYI: The number in the rightmost column in Kleopatra window is your key ID

In Git versions 2.0.0 and above, you don't have to specify -S for each commit anymore. To configure your Git client to sign commits automatically by default in any local repository on your computer, run:

$ git config --global commit.gpgsign true

You can omit --global flag if you want to set default only for certain local repository.

Finally, tell Git to use the gpg4win version of gpg.exe.

$ git config --global gpg.program "C:/Program Files (x86)/GNU/GnuPG/gpg2.exe"

If you are using 32-bit Windows, or if you have installed gpg4win into another location, replace it with the correct location of the program.

To check everything works, make a commit somewhere. You should be prompted to enter the passphrase:

You can verify that your commit has been signed:

$ git log --show-signature -1
commit 92e5d9505a8e593beba40b6e3d82a2fff85bbd6a (HEAD -> master)
gpg: Signature made 01/18/18 15:56:27 Korea Standard Time^M
gpg:                using RSA key BE86FF03DCD709AE0C3B5EFEB64A2E17C8528BF2^M
gpg:                issuer "bskim45@gmail.com"^M
gpg: Good signature from "Bumsoo Kim <bskim45@gmail.com>" [ultimate]^M

Also, check out this works seamlessly with SourceTree: