commit --amend -S: strip existing gpgsig headers

Any existing commit signature was made against the contents of the old commit, including its committer date that is about to change, and will become invalid by amending it. Signed-off-by: Junio C Hamano <gitster@pobox.com>

Junio C Hamano committed Jan 5, 2012 at 10:54 UTC c871a1d17b8433d98df59b03da5538f10c4ae52c
4 files changed +36 -8
builtin/commit.c
+2 -1
@@ -1494,7 +1494,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
1494 }
1495
1496 if (amend) {
1497 - extra = read_commit_extra_headers(current_head);
1497 + const char *exclude_gpgsig[2] = { "gpgsig", NULL };
1498 + extra = read_commit_extra_headers(current_head, exclude_gpgsig);
1499 } else {
1500 struct commit_extra_header **tail = &extra;
1501 append_merge_tag_headers(parents, &tail);
commit.c
+22 -4
@@ -981,14 +981,15 @@ static void add_extra_header(struct strbuf *buffer,
981 strbuf_addch(buffer, '\n');
982 }
983
984 -struct commit_extra_header *read_commit_extra_headers(struct commit *commit)
984 +struct commit_extra_header *read_commit_extra_headers(struct commit *commit,
985 + const char **exclude)
986 {
987 struct commit_extra_header *extra = NULL;
988 unsigned long size;
989 enum object_type type;
990 char *buffer = read_sha1_file(commit->object.sha1, &type, &size);
991 if (buffer && type == OBJ_COMMIT)
991 - extra = read_commit_extra_header_lines(buffer, size);
992 + extra = read_commit_extra_header_lines(buffer, size, exclude);
993 free(buffer);
994 return extra;
995 }
@@ -1002,7 +1003,23 @@ static inline int standard_header_field(const char *field, size_t len)
1003 (len == 8 && !memcmp(field, "encoding ", 9)));
1004 }
1005
1005 -struct commit_extra_header *read_commit_extra_header_lines(const char *buffer, size_t size)
1006 +static int excluded_header_field(const char *field, size_t len, const char **exclude)
1007 +{
1008 + if (!exclude)
1009 + return 0;
1010 +
1011 + while (*exclude) {
1012 + size_t xlen = strlen(*exclude);
1013 + if (len == xlen &&
1014 + !memcmp(field, *exclude, xlen) && field[xlen] == ' ')
1015 + return 1;
1016 + exclude++;
1017 + }
1018 + return 0;
1019 +}
1020 +
1021 +struct commit_extra_header *read_commit_extra_header_lines(const char *buffer, size_t size,
1022 + const char **exclude)
1023 {
1024 struct commit_extra_header *extra = NULL, **tail = &extra, *it = NULL;
1025 const char *line, *next, *eof, *eob;
@@ -1028,7 +1045,8 @@ struct commit_extra_header *read_commit_extra_header_lines(const char *buffer, s
1045 if (next <= eof)
1046 eof = next;
1047
1031 - if (standard_header_field(line, eof - line))
1048 + if (standard_header_field(line, eof - line) ||
1049 + excluded_header_field(line, eof - line, exclude))
1050 continue;
1051
1052 it = xcalloc(1, sizeof(*it));
commit.h
+2 -2
@@ -200,8 +200,8 @@ extern int commit_tree_extended(const char *msg, unsigned char *tree,
200 const char *author, const char *sign_commit,
201 struct commit_extra_header *);
202
203 -extern struct commit_extra_header *read_commit_extra_headers(struct commit *);
204 -extern struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len);
203 +extern struct commit_extra_header *read_commit_extra_headers(struct commit *, const char **);
204 +extern struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **);
205
206 extern void free_commit_extra_headers(struct commit_extra_header *extra);
207
t/t7510-signed-commit.sh
+10 -1
@@ -24,7 +24,8 @@ test_expect_success GPG 'create signed commits' '
24 echo 4 >file && test_tick && git commit -a -m "fourth unsigned" &&
25 git tag fourth-unsigned &&
26
27 - test_tick && git commit --amend -S -m "fourth signed"
27 + test_tick && git commit --amend -S -m "fourth signed" &&
28 + git tag fourth-signed
29 '
30
31 test_expect_success GPG 'show signatures' '
@@ -68,4 +69,12 @@ test_expect_success GPG 'detect fudged signature with NUL' '
69 ! grep "Good signature from" actual2
70 '
71
72 +test_expect_success GPG 'amending already signed commit' '
73 + git checkout fourth-signed^0 &&
74 + git commit --amend -S --no-edit &&
75 + git show -s --show-signature HEAD >actual &&
76 + grep "Good signature from" actual &&
77 + ! grep "BAD signature from" actual
78 +'
79 +
80 test_done