Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Retroactively sign git commits

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

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

like image 444
more tension Avatar asked Nov 22 '12 02:11

more tension


People also ask

How do I sign an existing commit?

To configure your Git client to sign commits by default for a local repository, in Git versions 2.0. 0 and above, run git config commit. gpgsign true . To sign all commits by default in any local repository on your computer, run git config --global commit.

Should git commits be signed?

By signing your commits you can prove that you are the author. You can be sure the code has not been tampered with. And signed commits could act as a reliable source for an audit trail.

How can I get previous commit code?

To view the previous commits, use the git log –-oneline command. This provides the commit details.


2 Answers

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.

like image 181
qqx Avatar answered Sep 17 '22 21:09

qqx


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.


With Git 2.29 (Q4 2020), this will be more reliable.

See commit 842385b, commit 9dad073, commit 26e28fe, commit 75d3bee, commit 20f4b04, commit 5b9427e, commit 8d2aa8d, commit 424e28f, commit e885a84, commit 185e865 (30 Sep 2020) by Jeff King (peff).
(Merged by Junio C Hamano -- gitster -- in commit 19dd352, 05 Oct 2020)

sequencer: handle ignore_footer when parsing trailers

Signed-off-by: Jeff King

The append_signoff() function takes an "ignore_footer" argument, which specifies a number of bytes at the end of the message buffer which should not be considered (they cannot contain trailers, and the trailer is spliced in before them).

But to find the existing trailers, it calls into has_conforming_trailer(). That function takes an ignore_footer parameter, but since 967dfd4d56 ("sequencer: use trailer's trailer layout", 2016-11-02, Git v2.12.0-rc0 -- merge listed in batch #2) the parameter is completely ignored.

The trailer interface we're using takes a single string, with no option to tell it to use part of the string. However, since we have a mutable strbuf, we can work around this by simply overwriting (and later restoring) the boundary with a NUL.

I'm not sure if this can actually trigger a bug in practice. It's easy to get a non-zero ignore_footer by doing something like this:

git commit -F - --cleanup=verbatim <<-EOF
subject  

body  

Signed-off-by: me  

# this looks like a comment, but is actually in the
# message! That makes the earlier s-o-b fake.
EOF  

git commit --amend -s  

There git-commit calls ignore_non_trailer() to count up the "#" cruft, which becomes the ignore_footer header. But it works even without this patch! That's because the trailer code also calls ignore_non_trailer() and skips the cruft, too. So it happens to work because the only callers with a non-zero ignore_footer are using the exact same function that the trailer parser uses internally.

And that seems true for all of the current callers, but there's nothing guaranteeing it. We're better off only feeding the correct buffer to the trailer code in the first place.

like image 30
VonC Avatar answered Sep 19 '22 21:09

VonC