Retroactively sign git commits

后端 未结 3 535
既然无缘
既然无缘 2021-01-13 07:19

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

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

相关标签:
3条回答
  • 2021-01-13 07:43

    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.

    0 讨论(0)
  • 2021-01-13 07:48

    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.

    0 讨论(0)
  • 2021-01-13 08:06

    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.

    0 讨论(0)
提交回复
热议问题