jshthornton
jshthornton

Reputation: 1314

Git - Detect if commit is signed off

Is there any git command or easier format to determine if a commit is or isn't signed off?

Upvotes: 7

Views: 8300

Answers (3)

VonC
VonC

Reputation: 1329692

With Git 1.7.9, Oct. 2011, you how git log --show-signature (mentioned in Kris' answer), but with 2.10 (Q3 2016), you can simply set git config log.showSignature true, which will work with git-log, git-show, git-whatchanged and git-reflog.


To facilitate grepping "Signed-off-By", you now (Git 2.12, Q1 2017) can log with only the "trailer" part of the commit message. (The trailer includes the "Signed-off-By" and other "Acknowledged By" messages)

See commit b1d31c8, commit d9f31fb (19 Nov 2016) by Jacob Keller (jacob-keller). (Merged by Junio C Hamano -- gitster -- in commit f008159, 19 Dec 2016, Git 2.12.0-rc0)

pretty: add %(trailers) format for displaying trailers of a commit message

In addition to %(subject), %(body), "git log --pretty=format:..." learned a new placeholder %(trailers) and %(contents:trailers).


You also have git interpret-trailers, which has just evolved in Git 2.14.x/2.15 (Q3 2017)

See commit 5a0d0c0 (20 Aug 2017) by Martin Ågren (``).
See commit 58311c6, commit cc1735c, commit a388b10, commit 99e09da, commit 0000239, commit fdbdb64, commit 56c493e (15 Aug 2017), and commit 8abc898 (10 Aug 2017) by Jeff King (peff).
(Merged by Junio C Hamano -- gitster -- in commit 06cf4f2, 27 Aug 2017)

"git interpret-trailers" has been taught a "--parse" and a few other options to make it easier for scripts to grab existing trailer lines from a commit log message.

git log --pretty=format:%(trailers:only:unfold)

Actually:

git log --pretty=format:%(trailers:only,unfold)
                                     ^^^^^

See commit 84ff053 (01 Oct 2017) by Taylor Blau (ttaylorr).
(Merged by Junio C Hamano -- gitster -- in commit 436b359, 07 Oct 2017)

pretty.c: delimit "%(trailers)" arguments with ","

In preparation for adding consistent "%(trailers)" atom options to git-for-each-ref(1)'s "--format" argument, change "%(trailers)" in pretty.c to separate sub-arguments with a ",", instead of a ":".

Multiple sub-arguments are given either as "%(trailers:unfold,only)" or "%(trailers:only,unfold)".

This change disambiguates between "top-level" arguments, and arguments given to the trailers atom itself. It is consistent with the behavior of "%(upstream)" and "%(push)" atoms.


Note: this is more robust with Git 2.20 (Q4 2018), since "git interpret-trailers" and its underlying machinery had a buggy code that attempted to ignore patch text after commit log message, which triggered in various codepaths that will always get the log message alone and never get such an input.

See commit 66e83d9, commit ffce7f5, commit e5fba5d, commit 1688c9a, commit c188668, commit 00a21f5, commit a3b636e, commit 0d2db00 (23 Aug 2018) by Jeff King (peff).
(Merged by Junio C Hamano -- gitster -- in commit fba9654, 17 Sep 2018)

sequencer: ignore "---" divider when parsing trailers

When the sequencer code appends a signoff or cherry-pick origin, it uses the default trailer-parsing options, which treat "---" as the end of the commit message.
As a result, it may be fooled by a commit message that contains that string and fail to find the existing trailer block. Even more confusing, the actual append code does not know about "---", and always appends to the end of the string.
This can lead to bizarre results.

E.g., appending a signoff to a commit message like this:

 subject

 body
 ---
 these dashes confuse the parser!

 Signed-off-by: A

results in output with a final block like:

 Signed-off-by: A

 Signed-off-by: A

The parser thinks the final line of the message is "body", and ignores everything else, claiming there are no trailers.
So we output an extra newline separator (wrong) and add a duplicate signoff (also wrong).

Since we know we are feeding a pure commit message, we can simply tell the parser to ignore the "---" divider.


Git 2.22 (Q2 2019) adds several options:

See commit 0b691d8, commit fd2015b, commit d9b936d, commit 250bea0, commit 3e3f347 (28 Jan 2019), commit 4f732e0 (29 Jan 2019), and commit 4261775 (08 Dec 2018) by Anders Waldenborg (wanders).
(Merged by Junio C Hamano -- gitster -- in commit 42977bf, 07 Mar 2019)

pretty: add support for separator option in %(trailers)

By default trailer lines are terminated by linebreaks ('\n').
By specifying the new 'separator' option they will instead be separated by user provided string and have separator semantics rather than terminator semantics.
The separator string can contain the literal formatting codes %n and %xNN allowing it to be things that are otherwise hard to type such as %x00, or comma and end-parenthesis which would break parsing.

E.g:

$ git log --pretty='%(trailers:key=Reviewed-by,valueonly,separator=%x00)'

And:

pretty: add support for "valueonly" option in %(trailers)

With the new "key=" option to %(trailers) it often makes little sense to show the key, as it by definition already is knows which trailer is printed there.
This new "valueonly" option makes it omit the key when printing trailers.

E.g.:

$ git show -s --pretty='%s%n%(trailers:key=Signed-off-by,valueonly)' aaaa881

will show:

upload-pack: fix broken if/else chain in config callback
Jeff King <[email protected]>
Junio C Hamano <[email protected]>

The parser for "git for-each-ref --format=...(man)" was too loose when parsing the "%(trailers...)" atom, and forgot that "trailers" and "trailers:<modifiers>" are the only two allowed forms, which has been corrected with Git 2.29 (Q4 2020).

See commit 2c22e10, commit a8e0f50 (21 Aug 2020) by Hariom Verma (harry-hov).
(Merged by Junio C Hamano -- gitster -- in commit e177238, 31 Aug 2020)

ref-filter: 'contents:trailers' show error if : is missing

Mentored-by: Christian Couder
Mentored-by: Heba Waly
Helped-by: Eric Sunshine
Signed-off-by: Hariom Verma

The 'contents' atom does not show any error if used with 'trailers' atom and colon is missing before trailers arguments.

e.g %(contents:trailersonly) works, while it shouldn't.

It is definitely not an expected behavior.

Let's fix this bug.


With Git 2.31 (Q1 2021), the "--format=%(trailers)" mechanism gets enhanced to make it easier to design output for machine consumption.

See commit 058761f, commit 9d87d5a, commit 8b966a0, commit 2762e17 (09 Dec 2020), and commit 7c1f79f (06 Dec 2020) by Ævar Arnfjörð Bjarmason (avar).
(Merged by Junio C Hamano -- gitster -- in commit b62bbd3, 06 Jan 2021)

pretty format %(trailers): add a "keyonly"

Signed-off-by: Ævar Arnfjörð Bjarmason

Add support for a "keyonly". This allows for easier parsing out of the key and value. Before if you didn't want to make assumptions about how the key was formatted. You'd need to parse it out as e.g.:

--pretty=format:'%H%x00%(trailers:separator=%x00%x00)' \
                   '%x00%(trailers:separator=%x00%x00,valueonly)'

And then proceed to deduce keys by looking at those two and subtracting the value plus the hardcoded ": " separator from the non-valueonly %(trailers) line. Now it's possible to simply do:

--pretty=format:'%H%x00%(trailers:separator=%x00%x00,keyonly)' \
                '%x00%(trailers:separator=%x00%x00,valueonly)'

Which at least reduces it to a state machine where you get N keys and correlate them with N values. Even better would be to have a way to change the ": " delimiter to something easily machine-readable (a key might contain ": " too). A follow-up change will add support for that.

I don't really have a use-case for just "keyonly" myself. I suppose it would be useful in some cases as "key=*" matches case-insensitively, so a plain "keyonly" will give you the variants of the keys you matched. I'm mainly adding it to fix the inconsistency with "valueonly".

pretty-formats now includes in its man page:

  • 'keyonly[=<BOOL>]': only show the key part of the trailer.
  • 'valueonly[=<BOOL>]': only show the value part of the trailer.

And:

See commit 058761f, commit 9d87d5a, commit 8b966a0, commit 2762e17 (09 Dec 2020), and commit 7c1f79f (06 Dec 2020) by Ævar Arnfjörð Bjarmason (avar).
(Merged by Junio C Hamano -- gitster -- in commit b62bbd3, 06 Jan 2021)

pretty format %(trailers): add a "key_value_separator"

Signed-off-by: Ævar Arnfjörð Bjarmason

Add a "key_value_separator" option to the "%(trailers)" pretty format, to go along with the existing "separator" argument.
In combination these two options make it trivial to produce machine-readable (e.g. \0 and \0\0-delimited) format output.

As elaborated on in a previous commit which added "keyonly" it was needlessly tedious to extract structured data from "%(trailers)" before the addition of this "key_value_separator" option.
As seen by the test being added here extracting this data now becomes trivial.

pretty-formats now includes in its man page:

  • 'key_value_separator=<SEP>': specify a separator inserted between trailer lines. When this option is not given each trailer key-value pair is separated by ": ".
    Otherwise it shares the same semantics as 'separator=<SEP>' above.

With Git 2.38 (Q3 2022), doc update.

See commit b46dd17 (30 Aug 2022) by Christian Couder (chriscool).
(Merged by Junio C Hamano -- gitster -- in commit 00b0199, 09 Sep 2022)

Documentation: clarify whitespace rules for trailers

Signed-off-by: Christian Couder

Commit e431956 ("trailer: be stricter in parsing separators", 2016-11-02, Git v2.12.0-rc0 -- merge listed in batch #2) restricted whitespaces allowed by git interpret-trailers(man) in the "token" part of the trailers it reads.

Also commit 60ef86a ("trailer: support values folded to multiple lines", 2016-10-21, Git v2.11.0-rc0 -- merge) updated the documentation, but didn't make it clear how many whitespace characters are allowed at the beginning of new lines in folded values.

git interpret-trailers now includes in its man page:

When reading trailers, there can be no whitespace before or inside the token, but any number of regular space and tab characters are allowed between the token and the separator.

There can be whitespaces before, inside or after the value.

The value may be split over multiple lines with each subsequent line starting with at least one whitespace, like the "folding" in RFC 822.


When "git commit --trailer=..."(man) invokes the interpret-trailers machinery, it knows what it feeds to interpret-trailers is a full log message without any patch, but failed to express that by passing the "--no-divider" option: that has been corrected with Git 2.42 (Q3 2023).

See commit be3d654 (17 Jun 2023) by Jeff King (peff).
(Merged by Junio C Hamano -- gitster -- in commit 8d5c5a0, 26 Jun 2023)

commit: pass --no-divider to interpret-trailers

Reported-by: [email protected]
Signed-off-by: Jeff King

When git-commit(man) sees any --trailer options, it passes the COMMIT_EDITMSG file through git-interpret-trailers.
But it does so without passing --no-divider, which means that interpret-trailers will look for a "---" divider to signal the end of the commit message.

That behavior doesn't make any sense in this context; we know we have a complete and solitary commit message, not something we have to further parse.
And as a result, we'll do the wrong thing if the commit message contains a "---" marker (which otherwise is not syntactically significant), inserting any new trailers at the wrong spot.

We can fix this by passing --no-divider.

This is the exact situation for which it was added in 1688c9a (interpret-trailers: allow suppressing , 2018-08-22, Git v2.20.0-rc0 -- merge listed in batch #1) (interpret-trailers: allow suppressing "---" divider, 2018-08-22).
As noted in the message for that commit, it just adds the mechanism, and further patches were needed to trigger it from various callers.
We did that back then in a few spots, like ffce7f5 (sequencer: ignore , 2018-08-22, Git v2.20.0-rc0 -- merge listed in batch #1) (sequencer: ignore "---" divider when parsing trailers, 2018-08-22), but obviously missed this one.

Upvotes: 22

Kris
Kris

Reputation: 19958

git log --show-signature
git show --show-signature

--show-signature

Check the validity of a signed commit object by passing the signature to gpg --verify and show the output.

Upvotes: 0

AlBlue
AlBlue

Reputation: 24060

You can use git log --invert-grep --grep="Signed-off-By" in Git 2.4 and above. (The --invert-grep option was added in 2.4.)

Upvotes: 3

Related Questions