Retroactively sign git commits

2019-02-18 02:42发布

问题:

Recent versions of git (>= 1.7.9) support signing individual commits with GPG.

Is it possible to retroactively sign all commits within a tree?

回答1:

retroactively sign all commits within a tree?

Yes: add a tag, that you would sign.
That is actually the preferred option when it comes to sign commits: sign a all set of them through a tag, rather than signing each one individually.
See "How to get pusher's Information in post-receive hooks?".


Note (update may 2017) that only Git 2.13.x/2.14 (Q3 2017) will completely fix the signing process, because "git cherry-pick" and other uses of the sequencer machinery and mishandled a trailer block whose last line is an incomplete line.
This has been fixed so that an additional sign-off etc. are added after completing the existing incomplete line.

See commit 44dc738 (26 Apr 2017) by Jonathan Tan (jhowtan).
(Merged by Junio C Hamano -- gitster -- in commit 6ebfa10, 16 May 2017)

sequencer: add newline before adding footers

When encountering a commit message that does not end in a newline, sequencer does not complete the line before determining if a blank line should be added.
This causes the "(cherry picked..." and sign-off lines to sometimes appear on the same line as the last line of the commit message.

This behavior was introduced by commit 967dfd4 ("sequencer: use trailer's trailer layout", 2016-11-29). However, a revert of that commit would not resolve this issue completely: prior to that commit, a conforming footer was deemed to be non-conforming by has_conforming_footer() if there was no terminating newline, resulting in both conforming and non-conforming footers being treated the same when they should not be.

Resolve this issue, both for conforming and non-conforming footers, and in both do_pick_commit() and append_signoff(), by always adding a newline to the commit message if it does not end in one before checking the footer for conformity.



回答2:

The signature from git commit's --gpg-sign (aka -S) option is part of the data that is used to generate the sha1 hash that identifies the commit. So retroactively signing commits would require changing the ID of every commit to which that was done.

If you really want to you could probably do something with git filter-branch, but it would be better to just sign new commits. Since the commit ID of all ancestors will influence the data that would be signed by any new commit this will still allow gpg verification of the old commits by way of the new, signed commits.



回答3:

You could try creating a new branch from the point where you want to start signing your commits. I recently did that for a branch that I created on a machine without access to my private key:

# git checkout -b new-branch <last-signed-commit>
# git cherry-pick <first-unsigned-commit>
# git checkout unsigned-branch
# git rebase new-branch

This requires that your Git is configured to automatically sign your commits, and there obviously shouldn’t be too many merge commits, other the rebase will look weird. If in doubt, cherry-pick your commits; each picked commit will then be signed.