Git is full of useful commands, powerful capabilities, and often overlooked features. I would argue that one of its hidden gems is its ability to sign commits and tags with a key. For this job, Git turns to GPG, a widely-adopted and open-source program designed for tasks such as this.
The team behind GPG, or the GNU Privacy Guard, describes it as a program which “allows you to encrypt and sign your data and communications.” This tool is useful for securing and cryptographically validating data sent via messaging applications, emails, and version-control systems, such as Git. Thankfully, the Git development team has done the heavy lifting for us and baked native support for GPG signing straight into the application.
Before diving into the “how,” I’d first like to address the “why.” Entrepreneurs, big businesses, and all those in-between may not see a reason to justify incorporating GPG keys into their development flow. There are a few essential arguments I’d like to make in favor of adding this practice to everyday development. After all, if it isn’t worth using, why does Git bother to include native support for it?
Aren’t usernames and passwords or SSH keys enough to keep users’ work adequately secured? The short answer is no and no. For better or worse, both mechanisms work to grant or deny access to the Git repository. Once access is granted, the engineer must go through additional steps to provide their identity before making any commits:
Once I am granted access with either my password or SSH key, it’s game over. Imagine a scenario where a fellow engineer named Alice and I are working on a project. If I found out that my change broke in production and cost the company thousands of dollars, I could pull down the
develop branch, claim her identity, rewrite history, and say it was Alice’s commit instead of mine. A simple run of the
git log would tell me all I need to know about her identity. Of course, had I done something like this, the branch’s
HEAD would diverge across the multiple Git instances, but it still proves a point. Not all hackers need brilliance to cause trouble. Had Alice signed her commits, I couldn’t impersonate her identity without the Git provider flagging my attempt as unverified and untrusted.
Encryption and digital signatures are all about inspiring confidence. All of the major players in the Git world reward those who go the extra mile to provide their identity with GPG. GitLab, GitHub, and Bitbucket all show a badge next to each commit whose author has signed it with GPG. GitHub goes further to indicate when a verified author signs their tags and releases. Talk about a friendly pat on the back!
For engineers, cryptography is often synonymous with pain. Did your key expire? Time to generate a new one and put it in all of the right places. Did you forget to use your key here? Well, you’ve just opened up a big hole. Etcetera, etcetera. In my opinion, Git makes it so easy to use that I find no reason not to. I tell Git what GPG key to use, ask it to sign each commit for me, and proceed using Git like I always have. Business as usual couldn’t be any easier.
GPG provides much flexibility regarding how you can configure the creation of your key. Personally, here are the options I like to use:
- Key type: RSA and RSA, an asymmetric key pair for encryption and decryption
- Bit length: 4096 for the highest amount of entropy
- Expiration date: None. Entirely up to you and your use case, but I’m only here to prove my identity on Git, not rotate my keys to guard state-sponsored secrets.
The process is quite simple:
- Open a terminal
gpg --full-generate-keyto enter the creation flow
- Select the desired key type. For me, I selected
1for RSA and RSA.
- Enter the bit length. I used
- Specify the validity duration, using
0to indicate no expiration. That was my choice. It will ask you to confirm your selection.
For the next few prompts, I line up my answers with the identity values I provide to Git.
- For the real name prompt, enter your display name. Of course, mine is
- The email address should match your commit email. In my example, I used
email@example.com, but in the real world, I prefer to use the masked email that GitLab and GitHub provide me. This feature is a nice added layer of privacy that many major Git providers offer.
- For the comment, I leave a human-readable description to indicate where I plan on using this key. In my example, I used
GitLab GPG Key.
Here is a video of that same flow in action.
Signing your commits won’t be of much use unless your Git provider can validate them. Therefore, we’ll need to export the public key to share with GitLab and GitHub. I’ll also export the private key to keep it safe in my password vault should I get a new computer or accidentally lose my local copy.
To begin, we need to tell GPG which key we intend to export. Start by listing all of the keys on your current system:
This action should yield a result like this:
Of course, if you have more keys on your computer, you’ll see them all show up. I’m interested in one particular piece of information, the long key ID. It shows up twice, once in a shorthand version and again with the complete ID. Here is the difference:
Notice how I am referring to the IDs beside the word
sec. At the bottom of the picture is another ID beside the phrase
ssb. The IDs at the top refer to the secret key (i.e., “sec”), and the ID at the bottom refers to the secret su*b*key (i.e., “ssb”). For this purpose, ignore the
You can refer to the intended key by its short ID for the next step, but I prefer to be explicit and use its long ID for precision. Armed with the long key ID, use it to export both the public and private keys:
Just like telling Git your name and email, you can similarly provide the GPG key configuration. Again, using the long key ID is preferable here for greater precision. I’ll use that ID in my command below and follow up with another configuration option telling Git to always use that key for each commit, even if I neglect to be explicit about it during the commits in my development cycle.
Now, Git signs all of your commits with GPG without any changes to your workflow. Just commit like you always have. You can verify all signed commits like this:
Of course, Git will only tell you if the commit is properly signed if you are the only person on the team or working on a distributed team, and each person has the public keys of the entire team. Otherwise, you’ll see Git report trust issues with commits signed by your teammates. In this case, I don’t bother and refer to GitLab and GitHub when I want to make sure someone has signed a commit properly. This way is a bit easier since the Git provider is responsible for holding all of the public keys, and each teammate must use the website to keep her or her public key up to date.
If you don’t tell Git to sign your commits automatically, you’ll need to do so at each commit:
I’ve found that signing tags is still a manual process, though:
Notice the difference between the above two lines. Signing a commit uses the capital
-S as a flag, and the tagging operation uses a lower case
-s. That would not be the first Git idiosyncrasy I’ve encountered.
In all, the headache of using GPG with your everyday workflow is almost invisible. Indeed, this level of ease makes an argument against using it quite challenging to believe.
Under the hood, I asked GPG to generate an RSA key pair for me. As with any asymmetric key, you’ll need to share the public key with a third party if you intend to share any information with them. Of course, since we are talking about pushing to Git repositories, we will most certainly share information. Thankfully, GitLab and GitHub makes this process very easy.
Before importing the public key to any Git provider, make sure you open up the public key you exported earlier in your favorite text editor. Please make sure you open the public key, not the private key.
This process is the same if you use GitLab.com or GitLab self-hosted. Log into your account, select your profile at the top-right, and go to Settings.
From the panel on the left, choose GPG Keys.
Paste the public key into the text box, and press the Add Key button.
Observe the key in your GPG key list.
You will find that installing a key onto GitHub is very similar to GitLab’s process. Log into your account, select your profile at the top-right, and go to Settings.
From the panel on the left, choose SSH and GPG Keys.
Press the New GPG Key button.
Paste the public key into the text box, and press the Add Key button.
Observe the key in your GPG key list.
Disasters are something we hope never to have, but for which we should always prepare. Storing your keys in a safe place could help avert the most painful aspects of such an event. As I stated earlier, I like to use one of two places to hold this kind of information: LastPass or ProtonDrive. No, these companies have not sponsored me to recommend them. They work well enough to deserve an unsolicited recommendation.
Even on their free account, LastPass allows you to place binary files in encrypted storage. Since I manage several GPG keys, I created a custom item type for all of the information I would ever want to know about my keys. Here is what it looks like:
I also like ProtonDrive since it is a fully encrypted, zero-access file storage service. A more common alternative, if you prefer, would be something like the OneDrive Personal Vault. The idea is the same in both places. I drop each key in the encrypted vault, along with a note containing the password, and it’s ready for use in the future, should I need it again.
Did you suffer data loss on your development machine? Did you get a new computer? Do you need to work on a second computer? All of these are valid reasons to crack open your vault and import your keys. Once you download the
.asc files to your new setup, typing these commands will add the public and private keys to your keychain:
Notice how I import the public key before the private key. Let’s double-check to see if that worked as expected.
Unfortunately, while the key is present in the keychain, it does not have the system’s trust since this machine is not responsible for creating the key in the first place. Let’s fix that:
- In your terminal, type:
gpg --edit-key key-id, where
key-idis the ID of the key you intend to edit.
- You have entered the GPG command-line editor.
- Type the word
- Since this is your key, you should be able to give it ultimate trust in your system. Thus, at the trust level prompt, enter
5for ultimate trust and confirm your choice. This level is the same trust value assigned to the key whenever you created it in the first place and used it on the same machine.
quitto exit the GPG prompt.
Double-checking our work again shows what we are looking for. The key pair is available and has ultimate trust on the system.
I’m a Windows user, but I prefer to use bash and Zsh when I need a terminal. Yet, I’ve noticed that GPG doesn’t work when I try to use it on Ubuntu under WSL (Windows Sub-System for Linux). If you run into problems signing your commits on WSL or any other Linux distribution, you may need to install GPG2. Here is how I do this on Ubuntu and other Debian-based systems:
Lastly, instruct Git to use
gpg2 instead of
gpg as the signing program:
Everything else about this using Git with GPG and interacting with GPG is the same. However, instead of using
gpg as the terminal command, use