Creating signed tags in Git: a “from scratch” tutorial
Finally, I decided to sign my “version tags” in Git. I knew about it in theory (hey, how much simpler it can be - just
git tag -s ..., right?), but never tried it in practice, and felt into a few pitfalls. So, here goes a
“newbie guide” to Git signed tags - from nothing to having a signed tag, which can be as well easily verified by
others. Stay tuned, there are a couple of tricks!
Creating a signed tag
As easy as it is, create a signed tag with a command:
$ git tag -s TAG_NAME [-m OPTIONAL_DETAILED_MESSAGE]
This will create a tag and will actually use gpg to sign it. So, first it means one should have gpg installed. Next, it means that gpg needs to have a secret key to sign with, or you need to specify the key some other way.
If you don’t have it yet - you will need to install a gnupg (gpg). On Linux - use whichever package manager you have. On Windows, if you use “msysGit” - it already comes with gpg; if you use “Cygwin” - get gnupg with the help of Cygwin setup.
A key to sign with
No matter how you will specify which key to use (there are several ways to do that), the key needs to be issued to the exact same user name and user email as those you use in Git (that is, those defined by user.name and user.email in Git config).
If you don’t have a personal key pair yet, you will need to generate the one. You can use gpg for it as well:
$ gpg --gen-key
This is an interactive command, where gpg will prompt user name, email and password for a private key. Use same user name and user email as those you use in Git here.
Once the key is generated, it is already installed into gpg keyring - that is it is automatically available for you whenever you (or git on behalf of you) will sign anything.
Finally, creating a signed tag
So, now is the time to do the
$ git tag -s TAG_NAME [-m OPTIONAL_DETAILED_MESSAGE]
which will actually create and sign a tag, if all goes well. Which looks like this:
$ git tag -s v2.5.1 -m "Fresh user interface. First public beta." You need a passphrase to unlock the secret key for user: "User Name " 2048-bit RSA key, ID FFFFFFFF, created 2001-01-01
What can go wrong? Most often gpg can miss the key or reject the one you have, which looks like this:
$ git tag -s v2.5.1 -m "Fresh user interface. First public beta." gpg: skipped "User Name ": secret key not available gpg: signing failed: secret key not available error: gpg failed to sign the data error: unable to sign the tag
This most likely means that either there is no key for this user in the gpg keyring, or, if you are certain there is, the user name or email is not the same as those configured in Git. To check both assumptions, use this:
$ gpg --list-keys ~/.gnupg/pubring.gpg ------------------------------------------ pub 2048R/FFFFFFFF 2001-01-01 uid User Name sub 2048R/E24B9143 2001-01-01
In the list of keys displayed you should normally see the key with same user name and email as if you do:
$ git config user.name User Name $ git config user.email firstname.lastname@example.org
Other ways to define the key to use
What if you don’t want to use the same user name in both Git configuration, and to sign the tag? Easy - there are two other ways to define which key to use to sign a tag: through Git config, or command line parameter to you can define the user name or email to look for a key in the keyring. For example:
$ git tag -u "email@example.com" [-m OPTIONAL_DETAILED_MESSAGE]
$ git config user.signingkey firstname.lastname@example.org
Both will instruct Git to use the defined key. Sure enough, the key needs to be in the gpg keyring (listed in
Sharing the signed tag
Git tags are not pushed to remote when you push other changes, so, you need to push them explicitly, like this:
$ git push origin v2.5.1
With this, you now have a signed tag, which is available to all users who has the access to the repository you pushed to. Now, we’ll see how one can verify the tag signature - this is the point of signing a tag, isn’t it?
Verifying tag signature
Now then, if you pulled a signed tag you may want to verify it. Again, as in
man git-tag, you use the following to
verify the signature:
$ git tag -v
If this you who have just created that tag as above, it runs fine.
$ git tag -v v2.5.1 object d123456789c52e50983e34cab917c0b625122d4a type commit tag v2.5.1 tagger User Name 1353867440 +0100 Fresh user interface. First public beta. gpg: Signature made Sun, Nov 25, 2012 7:17:21 PM CET using RSA key ID FFFFFFFF gpg: Good signature from "User Name"
What happens internally, is that Git actually uses gpg to verify the signature for the specified tag. So, this means that whoever wants to verify the tag signature - they need to have signer’s public key in your gpg keyring. Otherwise, if the signer’s public key is not available to gpg, you would see this message from Git:
gpg: Signature made Sun, Nov 25, 2012 7:17:21 PM CET using RSA key ID FFFFFFFF gpg: Can't check signature: public key not found error: could not verify the tag 'v2.5.1'
So, how the one gets signer’s key?
Sharing your public key
Let’s go one step back - we’ve missed one point. Once you’ve signed a tag, you may want to share your public key with others in order for them to be able to verify your signature. There is a plenty of ways to share the public key, but first, you need to extract the one as a sharable file:
$ gpg --armor --export email@example.com > username.pub
The command above will export your public key and, as long you redirect the output, save it to
Next, you may share the file actually. You can do so by mail, share a file in a wiki or on your personal web site. Then, it can be also stored in Git repository itself - hey, it is the closest place to where it will be used by others. This is why, I prefer this one.
So, you could put your public key to the Git repository as a regular file. There are few drawbacks to this solution - not so critical ones, but there are: having your public key in the source code may be not so nice - it isn’t really a source code; and then - you don’t really need version control for it - even if you will change the key, both versions need to be easily accessed to verify old and new signatures at the same time.
So, there is another smart solution here - you can store the key as a Git object, and share it on a remote. This object will only hold a key data, and not the file name, or a commit information - that is pure Git object, nothing else:
$ git hash-object -w username.pub f4a7478fb4543... $ git tag username-pub-rsa f4a7478fb4543... $ git push --tags
That’s it! You’ve stored a public key in a Git repository, assigned a tag to it, and shared it. It is not a part of a commit, or any tracked file - it only exists inside Git internal objects storage and can be easily accessed using a tag assigned to it. So, once a user pulled the remote with a signer’s public key already pushed to it, it can be easily seen in it:
$ git tag username-pub-rsa ... other tags if any
And one can now easily extract it and add to a keyring, in order to later use for tag verification:
$ git cat-file blob username-pub-rsa | gpg --import
That’s it! Back to verification, do
git tag -v v2.5.1 and this now should work as the signer’s key is in the keyring
All the information in this article can be found in
gpg man or Git Book all right, while this article
provides kind of a workflow, which I hope will be useful for those who never signed tags in Git before. Here are some
references where you can find much more detailed information about the steps and tricks described here: