commit --amend -S: strip existing gpgsig headers
authorJunio C Hamano <gitster@pobox.com>
Thu, 5 Jan 2012 18:54:14 +0000 (10:54 -0800)
committerJunio C Hamano <gitster@pobox.com>
Thu, 5 Jan 2012 21:02:26 +0000 (13:02 -0800)
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>
builtin/commit.c
commit.c
commit.h
t/t7510-signed-commit.sh

index fa41ec8c878a6af63e17b79996148be85dcfccef..970a83662a67a8f1c6cb8a67fd2e6636a5260948 100644 (file)
@@ -1494,7 +1494,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
        }
 
        if (amend) {
-               extra = read_commit_extra_headers(current_head);
+               const char *exclude_gpgsig[2] = { "gpgsig", NULL };
+               extra = read_commit_extra_headers(current_head, exclude_gpgsig);
        } else {
                struct commit_extra_header **tail = &extra;
                append_merge_tag_headers(parents, &tail);
index 27c7226abbfd95251bc2831a8a6447a8e35f264b..2162a7c5724c1dcdd42b249c11d1995e66abcd6f 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -981,14 +981,15 @@ static void add_extra_header(struct strbuf *buffer,
                strbuf_addch(buffer, '\n');
 }
 
-struct commit_extra_header *read_commit_extra_headers(struct commit *commit)
+struct commit_extra_header *read_commit_extra_headers(struct commit *commit,
+                                                     const char **exclude)
 {
        struct commit_extra_header *extra = NULL;
        unsigned long size;
        enum object_type type;
        char *buffer = read_sha1_file(commit->object.sha1, &type, &size);
        if (buffer && type == OBJ_COMMIT)
-               extra = read_commit_extra_header_lines(buffer, size);
+               extra = read_commit_extra_header_lines(buffer, size, exclude);
        free(buffer);
        return extra;
 }
@@ -1002,7 +1003,23 @@ static inline int standard_header_field(const char *field, size_t len)
                (len == 8 && !memcmp(field, "encoding ", 9)));
 }
 
-struct commit_extra_header *read_commit_extra_header_lines(const char *buffer, size_t size)
+static int excluded_header_field(const char *field, size_t len, const char **exclude)
+{
+       if (!exclude)
+               return 0;
+
+       while (*exclude) {
+               size_t xlen = strlen(*exclude);
+               if (len == xlen &&
+                   !memcmp(field, *exclude, xlen) && field[xlen] == ' ')
+                       return 1;
+               exclude++;
+       }
+       return 0;
+}
+
+struct commit_extra_header *read_commit_extra_header_lines(const char *buffer, size_t size,
+                                                          const char **exclude)
 {
        struct commit_extra_header *extra = NULL, **tail = &extra, *it = NULL;
        const char *line, *next, *eof, *eob;
@@ -1028,7 +1045,8 @@ struct commit_extra_header *read_commit_extra_header_lines(const char *buffer, s
                if (next <= eof)
                        eof = next;
 
-               if (standard_header_field(line, eof - line))
+               if (standard_header_field(line, eof - line) ||
+                   excluded_header_field(line, eof - line, exclude))
                        continue;
 
                it = xcalloc(1, sizeof(*it));
index 61076486df7de2502344039b62ad60f534807cf6..123aea3a7ccf95821d4b4eb5eff9cf7f384d881d 100644 (file)
--- a/commit.h
+++ b/commit.h
@@ -200,8 +200,8 @@ extern int commit_tree_extended(const char *msg, unsigned char *tree,
                                const char *author, const char *sign_commit,
                                struct commit_extra_header *);
 
-extern struct commit_extra_header *read_commit_extra_headers(struct commit *);
-extern struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len);
+extern struct commit_extra_header *read_commit_extra_headers(struct commit *, const char **);
+extern struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **);
 
 extern void free_commit_extra_headers(struct commit_extra_header *extra);
 
index 30401ced071c24aed5071442da1a9674bc7b7c7e..1d3c56fe61fa995e9bfe2d3a1e4a9fef2c211387 100755 (executable)
@@ -24,7 +24,8 @@ test_expect_success GPG 'create signed commits' '
        echo 4 >file && test_tick && git commit -a -m "fourth unsigned" &&
        git tag fourth-unsigned &&
 
-       test_tick && git commit --amend -S -m "fourth signed"
+       test_tick && git commit --amend -S -m "fourth signed" &&
+       git tag fourth-signed
 '
 
 test_expect_success GPG 'show signatures' '
@@ -68,4 +69,12 @@ test_expect_success GPG 'detect fudged signature with NUL' '
        ! grep "Good signature from" actual2
 '
 
+test_expect_success GPG 'amending already signed commit' '
+       git checkout fourth-signed^0 &&
+       git commit --amend -S --no-edit &&
+       git show -s --show-signature HEAD >actual &&
+       grep "Good signature from" actual &&
+       ! grep "BAD signature from" actual
+'
+
 test_done