312

Is there an easy way to make Git always signs each commit or tag that is created?

I tried it with something like:

alias commit = commit -S

But that didn't do the trick.

I don't want to install a different program to make this happen. Is it doable with ease?

Just a side question, maybe commits shouldn't be signed, only tags, which I never create, as I submit single commits for a project like Homebrew, etc.

2

6 Answers 6

382

Note: if you don't want to add -S all the time to make sure your commits are signed, there is a proposal (branch 'pu' for now, December 2013, so no guarantee it will make it to a git release) to add a config which will take care of that option for you.
Update May 2014: it is in Git 2.0 (after being resend in this patch series)

See commit 2af2ef3 by Nicolas Vigier (boklm):

Add the commit.gpgsign option to sign all commits

If you want to GPG sign all your commits, you have to add the -S option all the time.
The commit.gpgsign config option allows to sign all commits automatically.

commit.gpgsign

A boolean to specify whether all commits should be GPG signed.
Use of this option when doing operations such as rebase can result in a large number of commits being signed. It may be convenient to use an agent to avoid typing your GPG passphrase several times.


That config is usually set per repo (you don't need to sign your private experimental local repos):

cd /path/to/repo/needing/gpg/signature
git config commit.gpgsign true

You would combine that with user.signingKey used as a global setting (unique key used for all repo where you want to sign commit)

git config --global user.signingkey F2C7AB29!
                                           ^^^

As ubombi suggests in the comments (and explain in "GPG Hardware Key and Git Signing", based on "How to Specify a User Id")

When using gpg an exclamation mark (!) may be appended to force using the specified primary or secondary key, and not to try and calculate which primary or secondary key to use.

Note that Rik adds in the comments:

If you're using something like a YubiKey (as recommended) you don't need to worry about the exclamation point because the only signing key(s) you should have available for a primary key-pair are:

  • the primary key itself, which should have a # after it indicating it's not available,
  • and the secret subkey with a > after it indicating it's a stub that points to the YubiKey as the only available signing key in its applet.

Only if you keep all your private keys available on your system (bad practice), then probably it would be a good idea to prevent auto-selection between available signing keys


user.signingKey was introduced in git 1.5.0 (Jan. 2007) with commit d67778e:

There shouldn't be a requirement that I use the same form of my name in my git repository and my gpg key.
Further I might have multiple keys in my keyring, and might want to use one that doesn't match up with the address I use in commit messages.

This patch adds a configuration entry "user.signingKey" which, if present, will be passed to the "-u" switch for gpg, allowing the tag signing key to be overridden.

This is enforced with commit aba9119 (git 1.5.3.2) in order to catch the case where If the user has misconfigured user.signingKey in their .git/config or just doesn't have any secret keys on their keyring.

Notes:

9
  • 1
    That's really cool. Is there an easy way on github do something like git describe without having to download the hole repo?
    – user1115652
    Commented Apr 28, 2014 at 20:09
  • 33
    You don't need to sign your private experimental repos... but why wouldn't you? Commented Apr 29, 2016 at 21:59
  • 2
    Don't forget ! after key id. Like git config --global user.signingKey 9E08524833CB3038FDE385C54C0AFCCFED5CDE14!
    – ubombi
    Commented Nov 22, 2021 at 12:53
  • 1
    @ubombi why? I am not familiar with that syntax (or do not see ! in stealthpuppy.com/signing-git-commits-for-sweet-verified-badges for instance)
    – VonC
    Commented Nov 22, 2021 at 13:14
  • 2
    @VonC, Here is why I use it. TL;DR: ! forces gpg to use exactly the key you specified, otherwise the behavior is quite undefined. (issue exists when you start using subkeys)
    – ubombi
    Commented Nov 22, 2021 at 14:34
275
git config --global user.signingKey 9E08524833CB3038FDE385C54C0AFCCFED5CDE14
git config --global commit.gpgSign true

Replace 9E08524833CB3038FDE385C54C0AFCCFED5CDE14 by your key ID. Remember: It's never a good idea to use the short ID.

UPDATE: Per a new git edict, all config keys should be in camelCase.

7
  • 27
    No. As you can see in the edition history someone has added my example in his answer. ED5CDE14 is my own personal key. But no problem.
    – Felipe
    Commented May 16, 2016 at 5:05
  • 8
    Bizarre. I will revert the change tomorrow as it looks bad for you
    – scrowler
    Commented May 16, 2016 at 5:06
  • 1
    This might help Linux users: In order to make it work in some occasions (for example on Vim, using a key stored in a smart card that requires PIN entry) I had to edit ~/.gnupg/gpg-agent.conf and add pinentry-program /usr/bin/pinentry-gtk-2 (following this guide wiki.archlinux.org/index.php/GnuPG#pinentry )
    – Iakovos
    Commented Feb 6, 2017 at 11:21
  • 3
    @MarcusJ gpg --list-keys --fingerprint will show you the long form of the keys (I suppose you have to remove the spaces by hand). Commented Aug 26, 2018 at 16:06
  • 1
    @SuzanneSoy gpg --list-keys --keyid-format long shows the long format with no spaces :)
    – Ictus
    Commented Mar 17, 2022 at 5:35
51

Edit: As of Git version 1.7.9, it is possible to sign Git commits (git commit -S). Updating the answer slightly to reflect this.

The question title is:

Is there a way to “autosign” commits in Git with a GPG key?

Short answer: yes, but don't do it.

Addressing the typo in the question: git commit -s does not sign the commit. Rather, from the man git-commit page:

-s, --signoff
Add Signed-off-by line by the committer at the end of the commit log message.

This gives a log output similar to the following:


± $ git log                                                                                 [0:43:31]
commit 155deeaef1896c63519320c7cbaf4691355143f5
Author: User Name 
Date:   Mon Apr 16 00:43:27 2012 +0200

    Added .gitignore

    Signed-off-by: User Name 

Note the "Signed-off-by: ..." bit; that was generated by the -s flag on the git-commit.

Quoting the release announcement email:

  • "git commit" learned "-S" to GPG-sign the commit; this can be shown with the "--show-signature" option to "git log".

So yes, you can sign commits. However, I personally urge caution with this option; automatically signing commits is next to pointless, see below:

Just a side question, maybe commits shouldn't be signed, only tags, which I never create, as I submit single commits.

That's correct. Commits are not signed; tags are. The reason for this can be found in this message by Linus Torvalds, the last paragraph of which says:

Signing each commit is totally stupid. It just means that you automate it, and you make the signature worth less. It also doesn't add any real value, since the way the git DAG-chain of SHA1's work, you only ever need one signature to make all the commits reachable from that one be effectively covered by that one. So signing each commit is simply missing the point.

I'd encourage a browse of the linked message, which clarifies why signing commits automatically is not a good idea in a far better way than I could.

However, if you want to automatically sign a tag, you would be able to do that by wrapping the git-tag -[s|u] in an alias; if you're going to do that, you probably want to setup your key id in ~/.gitconfig or the project-specific .git/config file. More information about that process can be seen in the git community book. Signing tags is infinitely more useful than signing each commit you make.

11
  • 90
    "Signing each commit is totally stupid." -> What is better way to secure commits when there is a "rat" developer who likes pushing commits with faked author and committer? Unless there is some hook magic on the server he can direct git blame to whoever he wants.
    – Vi.
    Commented Sep 16, 2012 at 16:39
  • 12
    0. an article, 1. "is sufficient to sign all of them" -> How to tell "I claim that this is really my diff (but unsure about any previous and further commits). I want to put a signature on my commit without asserting anything about commits I pulled from the central server/whatever. 2. In untrusted environment there still should be a reliable tool to find out who is guilty. If the server checks that all commits are signed with key of committer's email, it is hard to fake a commit (if you secure your computer well).
    – Vi.
    Commented Sep 18, 2012 at 13:22
  • 9
    Signing one commit is sufficient if code never changes. Once you add more commits, you'll need more signatures. Signing a tag is marking everything OLDER than that commit. If you need fine grained verification as the commits are coming, it makes sense to sign each commit. Otherwise you'd have to use a lot of tags, which would just clutter up the repo. On authenticated remote git repos, you have to give your password or ssh key every time you push a commit, not only when you push tags. This is a similar situation. Commented Sep 18, 2012 at 20:28
  • 32
    I feel like Linus is kind of missing the point. He seems to have an entirely different use case for signed commits in mind than the OP in that thread. (Verifying the integrity of the entire project, vs verifying the authorship of a single commit.)
    – Ajedi32
    Commented Jan 11, 2016 at 18:16
  • 15
    -1 for "Yes, but don't do it." The answer should just be a flat out "YES". Signing commits proves the author, something that otherwise can be lied about in the commit.
    – Urda
    Commented Jun 11, 2016 at 0:12
18

First setup the public key using which you want to sign all your commits , tags and push. To get the public key, use the following command

% gpg --list-keys --keyid-format=short
/home/blueray/.gnupg/pubring.kbx
-------------------------------
pub   rsa3072/F6EED39A 2021-12-25 [SC] [expires: 2023-12-25]

In this case the public key is F6EED39A. Now run the following commands.

git config --global user.signingkey F6EED39A
git config --global commit.gpgSign true // sign all commits
git config --global tag.gpgSign true // sign all tags
git config --global push.gpgSign true // sign all push

Please note that, If you use push.gpgSign true, the push will fail if the server does not support signed pushes. An alternative is to use:

git config --global push.gpgSign "if-asked" 

Which says, sign all push if the server supports it.

Now all your commits , tags and push will be signed by your given public key automatically.

Sometimes you may need to override these settings.

For commits, use git commit --no-gpg-sign -m "Unsigned commit"

For tags, use git tag --no-sign <tag-name>

For push, use git push --no-signed or, --signed=false.

3
  • 2
    Signing pushes is a good addition. This feature is easily forgotten. I should add that it can also be set to if-asked. This way pushes will only be signed when the server supports it.
    – Iizuki
    Commented Sep 2, 2022 at 9:04
  • How do i generate the public and secret key Commented Jan 25 at 22:43
  • 1
    @olawalejuwonm there some steps involved. Please check docs.github.com/en/authentication/… Commented Jan 26 at 11:33
16

To make auto signing work pre git version 2.0, you'll have to add git alias for commit.

# git config --global alias.commit "commit -S"
[alias]
    commit = commit -S
0

You need to make clear that if you sign a commit or tag, that you do not mean that you approve the whole history. In case of commits you only sign the change at hand, and in case of tag, well.. you need to define what you mean with it. You might have pulled a change which claims it is from you but was not (because somebody else pushed it to your remote). Or it is a change you dont want to be in, but you just signed the tag.

In typical OSS projects this might be less common, but in a enterprise scenario where you only touch code every now and then and you don't read the whole history it might get unnoticed.

Signing commits is a problem if they will get rebased or cherry-picked to other parents. But it would be good if a modified commit could point to the "original" commit which actually verifies.

9
  • 3
    Rebasing is like lying. It should be used exceedingly sparingly. The other thing is that committing with a signature is "signing off" code, so be double sure that it's a) not anti-CYA and b) not wasted effort.
    – user246672
    Commented Jan 13, 2014 at 1:18
  • 15
    @Barry “Rebasing is like lying. It should be used exceedingly sparingly” – this is just not true. Rebase-based workflows are just as valid as merge-based workflows. Rebasing is way too powerful to be used sparingly. Commented Oct 24, 2015 at 9:52
  • 2
    When using this exclusively with GitHub that's not a problem, the merge commits will not be signed by you, as GitHub does not support this. The advantage of signing every (non-merge) commit in this environment, is it makes it very obvious when a rogue commit was added via a PR as it will not be signed with your GPG key. Commented Nov 17, 2015 at 16:42
  • 3
    "It is dangerous if you sign a commit or tag (both will sign the whole history) that you might have pulled a change which claims it is from you" If you're only signing a commit though I wouldn't interpret that as an endorsement of every commit reachable from yours. You're not necessarily stating that those past changes are valid or endorsed by you, only that you created a commit based off of those changes. (Though with a tag, I agree you are indeed signing off on all commits reachable by the tag.)
    – Ajedi32
    Commented Jan 11, 2016 at 18:39
  • 1
    @ArranCudbard-Bell Just as an update, merge commits are signed by you if you set commit.gpgsign to true as suggested by @VonC
    – Jay
    Commented May 25, 2016 at 3:29

Not the answer you're looking for? Browse other questions tagged or ask your own question.