Merge branch 'jc/show-sig'
* jc/show-sig: log --show-signature: reword the common two-head merge case log-tree: show mergetag in log --show-signature output log-tree.c: small refactor in show_signature() commit --amend -S: strip existing gpgsig headers verify_signed_buffer: fix stale comment gpg-interface: allow use of a custom GPG binary pretty: %G[?GS] placeholders test "commit -S" and "log --show-signature" log: --show-signature commit: teach --gpg-sign option Conflicts: builtin/commit-tree.c builtin/commit.c builtin/merge.c notes-cache.c pretty.c
This commit is contained in:
commit
5de89d3abf
@ -99,10 +99,6 @@ Unless otherwise noted, all the fixes since v1.7.8 in the maintenance
|
|||||||
releases are contained in this release (see release notes to them for
|
releases are contained in this release (see release notes to them for
|
||||||
details).
|
details).
|
||||||
|
|
||||||
* gitweb did not correctly fall back to configured $fallback_encoding
|
|
||||||
that is not 'latin1'.
|
|
||||||
(merge b13e3ea jn/maint-gitweb-utf8-fix later to maint).
|
|
||||||
|
|
||||||
--
|
--
|
||||||
exec >/var/tmp/1
|
exec >/var/tmp/1
|
||||||
O=v1.7.8.2-301-g48de656
|
O=v1.7.8.2-301-g48de656
|
||||||
|
@ -1123,6 +1123,17 @@ grep.lineNumber::
|
|||||||
grep.extendedRegexp::
|
grep.extendedRegexp::
|
||||||
If set to true, enable '--extended-regexp' option by default.
|
If set to true, enable '--extended-regexp' option by default.
|
||||||
|
|
||||||
|
gpg.program::
|
||||||
|
Use this custom program instead of "gpg" found on $PATH when
|
||||||
|
making or verifying a PGP signature. The program must support the
|
||||||
|
same command line interface as GPG, namely, to verify a detached
|
||||||
|
signature, "gpg --verify $file - <$signature" is run, and the
|
||||||
|
program is expected to signal a good signature by exiting with
|
||||||
|
code 0, and to generate an ascii-armored detached signature, the
|
||||||
|
standard input of "gpg -bsau $key" is fed with the contents to be
|
||||||
|
signed, and the program is expected to send the result to its
|
||||||
|
standard output.
|
||||||
|
|
||||||
gui.commitmsgwidth::
|
gui.commitmsgwidth::
|
||||||
Defines how wide the commit message window is in the
|
Defines how wide the commit message window is in the
|
||||||
linkgit:git-gui[1]. "75" is the default.
|
linkgit:git-gui[1]. "75" is the default.
|
||||||
|
@ -38,7 +38,9 @@ created (i.e. a lightweight tag).
|
|||||||
A GnuPG signed tag object will be created when `-s` or `-u
|
A GnuPG signed tag object will be created when `-s` or `-u
|
||||||
<key-id>` is used. When `-u <key-id>` is not used, the
|
<key-id>` is used. When `-u <key-id>` is not used, the
|
||||||
committer identity for the current user is used to find the
|
committer identity for the current user is used to find the
|
||||||
GnuPG key for signing.
|
GnuPG key for signing. The configuration variable `gpg.program`
|
||||||
|
is used to specify custom GnuPG binary.
|
||||||
|
|
||||||
|
|
||||||
OPTIONS
|
OPTIONS
|
||||||
-------
|
-------
|
||||||
@ -48,11 +50,11 @@ OPTIONS
|
|||||||
|
|
||||||
-s::
|
-s::
|
||||||
--sign::
|
--sign::
|
||||||
Make a GPG-signed tag, using the default e-mail address's key
|
Make a GPG-signed tag, using the default e-mail address's key.
|
||||||
|
|
||||||
-u <key-id>::
|
-u <key-id>::
|
||||||
--local-user=<key-id>::
|
--local-user=<key-id>::
|
||||||
Make a GPG-signed tag, using the given key
|
Make a GPG-signed tag, using the given key.
|
||||||
|
|
||||||
-f::
|
-f::
|
||||||
--force::
|
--force::
|
||||||
|
@ -8,8 +8,9 @@
|
|||||||
#include "tree.h"
|
#include "tree.h"
|
||||||
#include "builtin.h"
|
#include "builtin.h"
|
||||||
#include "utf8.h"
|
#include "utf8.h"
|
||||||
|
#include "gpg-interface.h"
|
||||||
|
|
||||||
static const char commit_tree_usage[] = "git commit-tree [(-p <sha1>)...] [-m <message>] [-F <file>] <sha1> <changelog";
|
static const char commit_tree_usage[] = "git commit-tree [(-p <sha1>)...] [-S<signer>] [-m <message>] [-F <file>] <sha1> <changelog";
|
||||||
|
|
||||||
static void new_parent(struct commit *parent, struct commit_list **parents_p)
|
static void new_parent(struct commit *parent, struct commit_list **parents_p)
|
||||||
{
|
{
|
||||||
@ -25,6 +26,14 @@ static void new_parent(struct commit *parent, struct commit_list **parents_p)
|
|||||||
commit_list_insert(parent, parents_p);
|
commit_list_insert(parent, parents_p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int commit_tree_config(const char *var, const char *value, void *cb)
|
||||||
|
{
|
||||||
|
int status = git_gpg_config(var, value, NULL);
|
||||||
|
if (status)
|
||||||
|
return status;
|
||||||
|
return git_default_config(var, value, cb);
|
||||||
|
}
|
||||||
|
|
||||||
int cmd_commit_tree(int argc, const char **argv, const char *prefix)
|
int cmd_commit_tree(int argc, const char **argv, const char *prefix)
|
||||||
{
|
{
|
||||||
int i, got_tree = 0;
|
int i, got_tree = 0;
|
||||||
@ -32,12 +41,16 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
|
|||||||
unsigned char tree_sha1[20];
|
unsigned char tree_sha1[20];
|
||||||
unsigned char commit_sha1[20];
|
unsigned char commit_sha1[20];
|
||||||
struct strbuf buffer = STRBUF_INIT;
|
struct strbuf buffer = STRBUF_INIT;
|
||||||
|
const char *sign_commit = NULL;
|
||||||
|
|
||||||
git_config(git_default_config, NULL);
|
git_config(commit_tree_config, NULL);
|
||||||
|
|
||||||
if (argc < 2 || !strcmp(argv[1], "-h"))
|
if (argc < 2 || !strcmp(argv[1], "-h"))
|
||||||
usage(commit_tree_usage);
|
usage(commit_tree_usage);
|
||||||
|
|
||||||
|
if (get_sha1(argv[1], tree_sha1))
|
||||||
|
die("Not a valid object name %s", argv[1]);
|
||||||
|
|
||||||
for (i = 1; i < argc; i++) {
|
for (i = 1; i < argc; i++) {
|
||||||
const char *arg = argv[i];
|
const char *arg = argv[i];
|
||||||
if (!strcmp(arg, "-p")) {
|
if (!strcmp(arg, "-p")) {
|
||||||
@ -51,6 +64,11 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!memcmp(arg, "-S", 2)) {
|
||||||
|
sign_commit = arg + 2;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (!strcmp(arg, "-m")) {
|
if (!strcmp(arg, "-m")) {
|
||||||
if (argc <= ++i)
|
if (argc <= ++i)
|
||||||
usage(commit_tree_usage);
|
usage(commit_tree_usage);
|
||||||
@ -98,7 +116,8 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
|
|||||||
die_errno("git commit-tree: failed to read");
|
die_errno("git commit-tree: failed to read");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (commit_tree(&buffer, tree_sha1, parents, commit_sha1, NULL)) {
|
if (commit_tree(&buffer, tree_sha1, parents, commit_sha1,
|
||||||
|
NULL, sign_commit)) {
|
||||||
strbuf_release(&buffer);
|
strbuf_release(&buffer);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include "unpack-trees.h"
|
#include "unpack-trees.h"
|
||||||
#include "quote.h"
|
#include "quote.h"
|
||||||
#include "submodule.h"
|
#include "submodule.h"
|
||||||
|
#include "gpg-interface.h"
|
||||||
|
|
||||||
static const char * const builtin_commit_usage[] = {
|
static const char * const builtin_commit_usage[] = {
|
||||||
"git commit [options] [--] <filepattern>...",
|
"git commit [options] [--] <filepattern>...",
|
||||||
@ -86,6 +87,8 @@ static int edit_flag = -1; /* unspecified */
|
|||||||
static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;
|
static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;
|
||||||
static int no_post_rewrite, allow_empty_message;
|
static int no_post_rewrite, allow_empty_message;
|
||||||
static char *untracked_files_arg, *force_date, *ignore_submodule_arg;
|
static char *untracked_files_arg, *force_date, *ignore_submodule_arg;
|
||||||
|
static char *sign_commit;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The default commit message cleanup mode will remove the lines
|
* The default commit message cleanup mode will remove the lines
|
||||||
* beginning with # (shell comments) and leading and trailing
|
* beginning with # (shell comments) and leading and trailing
|
||||||
@ -145,6 +148,8 @@ static struct option builtin_commit_options[] = {
|
|||||||
OPT_BOOL('e', "edit", &edit_flag, "force edit of commit"),
|
OPT_BOOL('e', "edit", &edit_flag, "force edit of commit"),
|
||||||
OPT_STRING(0, "cleanup", &cleanup_arg, "default", "how to strip spaces and #comments from message"),
|
OPT_STRING(0, "cleanup", &cleanup_arg, "default", "how to strip spaces and #comments from message"),
|
||||||
OPT_BOOLEAN(0, "status", &include_status, "include status in commit message template"),
|
OPT_BOOLEAN(0, "status", &include_status, "include status in commit message template"),
|
||||||
|
{ OPTION_STRING, 'S', "gpg-sign", &sign_commit, "key id",
|
||||||
|
"GPG sign commit", PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
|
||||||
/* end commit message options */
|
/* end commit message options */
|
||||||
|
|
||||||
OPT_GROUP("Commit contents options"),
|
OPT_GROUP("Commit contents options"),
|
||||||
@ -1325,6 +1330,7 @@ static void print_summary(const char *prefix, const unsigned char *sha1,
|
|||||||
static int git_commit_config(const char *k, const char *v, void *cb)
|
static int git_commit_config(const char *k, const char *v, void *cb)
|
||||||
{
|
{
|
||||||
struct wt_status *s = cb;
|
struct wt_status *s = cb;
|
||||||
|
int status;
|
||||||
|
|
||||||
if (!strcmp(k, "commit.template"))
|
if (!strcmp(k, "commit.template"))
|
||||||
return git_config_pathname(&template_file, k, v);
|
return git_config_pathname(&template_file, k, v);
|
||||||
@ -1333,6 +1339,9 @@ static int git_commit_config(const char *k, const char *v, void *cb)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
status = git_gpg_config(k, v, NULL);
|
||||||
|
if (status)
|
||||||
|
return status;
|
||||||
return git_status_config(k, v, s);
|
return git_status_config(k, v, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1486,14 +1495,15 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (amend) {
|
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 {
|
} else {
|
||||||
struct commit_extra_header **tail = &extra;
|
struct commit_extra_header **tail = &extra;
|
||||||
append_merge_tag_headers(parents, &tail);
|
append_merge_tag_headers(parents, &tail);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (commit_tree_extended(&sb, active_cache_tree->sha1, parents, sha1,
|
if (commit_tree_extended(&sb, active_cache_tree->sha1, parents, sha1,
|
||||||
author_ident.buf, extra)) {
|
author_ident.buf, sign_commit, extra)) {
|
||||||
rollback_index_files();
|
rollback_index_files();
|
||||||
die(_("failed to write commit object"));
|
die(_("failed to write commit object"));
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include "resolve-undo.h"
|
#include "resolve-undo.h"
|
||||||
#include "remote.h"
|
#include "remote.h"
|
||||||
#include "fmt-merge-msg.h"
|
#include "fmt-merge-msg.h"
|
||||||
|
#include "gpg-interface.h"
|
||||||
|
|
||||||
#define DEFAULT_TWOHEAD (1<<0)
|
#define DEFAULT_TWOHEAD (1<<0)
|
||||||
#define DEFAULT_OCTOPUS (1<<1)
|
#define DEFAULT_OCTOPUS (1<<1)
|
||||||
@ -64,6 +65,7 @@ static int allow_rerere_auto;
|
|||||||
static int abort_current_merge;
|
static int abort_current_merge;
|
||||||
static int show_progress = -1;
|
static int show_progress = -1;
|
||||||
static int default_to_upstream;
|
static int default_to_upstream;
|
||||||
|
static const char *sign_commit;
|
||||||
|
|
||||||
static struct strategy all_strategy[] = {
|
static struct strategy all_strategy[] = {
|
||||||
{ "recursive", DEFAULT_TWOHEAD | NO_TRIVIAL },
|
{ "recursive", DEFAULT_TWOHEAD | NO_TRIVIAL },
|
||||||
@ -209,6 +211,8 @@ static struct option builtin_merge_options[] = {
|
|||||||
OPT_BOOLEAN(0, "abort", &abort_current_merge,
|
OPT_BOOLEAN(0, "abort", &abort_current_merge,
|
||||||
"abort the current in-progress merge"),
|
"abort the current in-progress merge"),
|
||||||
OPT_SET_INT(0, "progress", &show_progress, "force progress reporting", 1),
|
OPT_SET_INT(0, "progress", &show_progress, "force progress reporting", 1),
|
||||||
|
{ OPTION_STRING, 'S', "gpg-sign", &sign_commit, "key id",
|
||||||
|
"GPG sign commit", PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
|
||||||
OPT_BOOLEAN(0, "overwrite-ignore", &overwrite_ignore, "update ignored files (default)"),
|
OPT_BOOLEAN(0, "overwrite-ignore", &overwrite_ignore, "update ignored files (default)"),
|
||||||
OPT_END()
|
OPT_END()
|
||||||
};
|
};
|
||||||
@ -571,7 +575,11 @@ static int git_merge_config(const char *k, const char *v, void *cb)
|
|||||||
default_to_upstream = git_config_bool(k, v);
|
default_to_upstream = git_config_bool(k, v);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = fmt_merge_msg_config(k, v, cb);
|
status = fmt_merge_msg_config(k, v, cb);
|
||||||
|
if (status)
|
||||||
|
return status;
|
||||||
|
status = git_gpg_config(k, v, NULL);
|
||||||
if (status)
|
if (status)
|
||||||
return status;
|
return status;
|
||||||
return git_diff_ui_config(k, v, cb);
|
return git_diff_ui_config(k, v, cb);
|
||||||
@ -910,7 +918,8 @@ static int merge_trivial(struct commit *head)
|
|||||||
parent->next->item = remoteheads->item;
|
parent->next->item = remoteheads->item;
|
||||||
parent->next->next = NULL;
|
parent->next->next = NULL;
|
||||||
prepare_to_commit();
|
prepare_to_commit();
|
||||||
if (commit_tree(&merge_msg, result_tree, parent, result_commit, NULL))
|
if (commit_tree(&merge_msg, result_tree, parent, result_commit, NULL,
|
||||||
|
sign_commit))
|
||||||
die(_("failed to write commit object"));
|
die(_("failed to write commit object"));
|
||||||
finish(head, result_commit, "In-index merge");
|
finish(head, result_commit, "In-index merge");
|
||||||
drop_save();
|
drop_save();
|
||||||
@ -942,7 +951,8 @@ static int finish_automerge(struct commit *head,
|
|||||||
strbuf_addch(&merge_msg, '\n');
|
strbuf_addch(&merge_msg, '\n');
|
||||||
prepare_to_commit();
|
prepare_to_commit();
|
||||||
free_commit_list(remoteheads);
|
free_commit_list(remoteheads);
|
||||||
if (commit_tree(&merge_msg, result_tree, parents, result_commit, NULL))
|
if (commit_tree(&merge_msg, result_tree, parents, result_commit,
|
||||||
|
NULL, sign_commit))
|
||||||
die(_("failed to write commit object"));
|
die(_("failed to write commit object"));
|
||||||
strbuf_addf(&buf, "Merge made by the '%s' strategy.", wt_strategy);
|
strbuf_addf(&buf, "Merge made by the '%s' strategy.", wt_strategy);
|
||||||
finish(head, result_commit, buf.buf);
|
finish(head, result_commit, buf.buf);
|
||||||
|
118
commit.c
118
commit.c
@ -6,6 +6,7 @@
|
|||||||
#include "diff.h"
|
#include "diff.h"
|
||||||
#include "revision.h"
|
#include "revision.h"
|
||||||
#include "notes.h"
|
#include "notes.h"
|
||||||
|
#include "gpg-interface.h"
|
||||||
|
|
||||||
int save_commit_buffer = 1;
|
int save_commit_buffer = 1;
|
||||||
|
|
||||||
@ -840,6 +841,86 @@ struct commit_list *reduce_heads(struct commit_list *heads)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char gpg_sig_header[] = "gpgsig";
|
||||||
|
static const int gpg_sig_header_len = sizeof(gpg_sig_header) - 1;
|
||||||
|
|
||||||
|
static int do_sign_commit(struct strbuf *buf, const char *keyid)
|
||||||
|
{
|
||||||
|
struct strbuf sig = STRBUF_INIT;
|
||||||
|
int inspos, copypos;
|
||||||
|
|
||||||
|
/* find the end of the header */
|
||||||
|
inspos = strstr(buf->buf, "\n\n") - buf->buf + 1;
|
||||||
|
|
||||||
|
if (!keyid || !*keyid)
|
||||||
|
keyid = get_signing_key();
|
||||||
|
if (sign_buffer(buf, &sig, keyid)) {
|
||||||
|
strbuf_release(&sig);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (copypos = 0; sig.buf[copypos]; ) {
|
||||||
|
const char *bol = sig.buf + copypos;
|
||||||
|
const char *eol = strchrnul(bol, '\n');
|
||||||
|
int len = (eol - bol) + !!*eol;
|
||||||
|
|
||||||
|
if (!copypos) {
|
||||||
|
strbuf_insert(buf, inspos, gpg_sig_header, gpg_sig_header_len);
|
||||||
|
inspos += gpg_sig_header_len;
|
||||||
|
}
|
||||||
|
strbuf_insert(buf, inspos++, " ", 1);
|
||||||
|
strbuf_insert(buf, inspos, bol, len);
|
||||||
|
inspos += len;
|
||||||
|
copypos += len;
|
||||||
|
}
|
||||||
|
strbuf_release(&sig);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int parse_signed_commit(const unsigned char *sha1,
|
||||||
|
struct strbuf *payload, struct strbuf *signature)
|
||||||
|
{
|
||||||
|
unsigned long size;
|
||||||
|
enum object_type type;
|
||||||
|
char *buffer = read_sha1_file(sha1, &type, &size);
|
||||||
|
int in_signature, saw_signature = -1;
|
||||||
|
char *line, *tail;
|
||||||
|
|
||||||
|
if (!buffer || type != OBJ_COMMIT)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
line = buffer;
|
||||||
|
tail = buffer + size;
|
||||||
|
in_signature = 0;
|
||||||
|
saw_signature = 0;
|
||||||
|
while (line < tail) {
|
||||||
|
const char *sig = NULL;
|
||||||
|
char *next = memchr(line, '\n', tail - line);
|
||||||
|
|
||||||
|
next = next ? next + 1 : tail;
|
||||||
|
if (in_signature && line[0] == ' ')
|
||||||
|
sig = line + 1;
|
||||||
|
else if (!prefixcmp(line, gpg_sig_header) &&
|
||||||
|
line[gpg_sig_header_len] == ' ')
|
||||||
|
sig = line + gpg_sig_header_len + 1;
|
||||||
|
if (sig) {
|
||||||
|
strbuf_add(signature, sig, next - sig);
|
||||||
|
saw_signature = 1;
|
||||||
|
in_signature = 1;
|
||||||
|
} else {
|
||||||
|
if (*line == '\n')
|
||||||
|
/* dump the whole remainder of the buffer */
|
||||||
|
next = tail;
|
||||||
|
strbuf_add(payload, line, next - line);
|
||||||
|
in_signature = 0;
|
||||||
|
}
|
||||||
|
line = next;
|
||||||
|
}
|
||||||
|
cleanup:
|
||||||
|
free(buffer);
|
||||||
|
return saw_signature;
|
||||||
|
}
|
||||||
|
|
||||||
static void handle_signed_tag(struct commit *parent, struct commit_extra_header ***tail)
|
static void handle_signed_tag(struct commit *parent, struct commit_extra_header ***tail)
|
||||||
{
|
{
|
||||||
struct merge_remote_desc *desc;
|
struct merge_remote_desc *desc;
|
||||||
@ -900,14 +981,15 @@ static void add_extra_header(struct strbuf *buffer,
|
|||||||
strbuf_addch(buffer, '\n');
|
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;
|
struct commit_extra_header *extra = NULL;
|
||||||
unsigned long size;
|
unsigned long size;
|
||||||
enum object_type type;
|
enum object_type type;
|
||||||
char *buffer = read_sha1_file(commit->object.sha1, &type, &size);
|
char *buffer = read_sha1_file(commit->object.sha1, &type, &size);
|
||||||
if (buffer && type == OBJ_COMMIT)
|
if (buffer && type == OBJ_COMMIT)
|
||||||
extra = read_commit_extra_header_lines(buffer, size);
|
extra = read_commit_extra_header_lines(buffer, size, exclude);
|
||||||
free(buffer);
|
free(buffer);
|
||||||
return extra;
|
return extra;
|
||||||
}
|
}
|
||||||
@ -921,7 +1003,23 @@ static inline int standard_header_field(const char *field, size_t len)
|
|||||||
(len == 8 && !memcmp(field, "encoding ", 9)));
|
(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;
|
struct commit_extra_header *extra = NULL, **tail = &extra, *it = NULL;
|
||||||
const char *line, *next, *eof, *eob;
|
const char *line, *next, *eof, *eob;
|
||||||
@ -947,7 +1045,8 @@ struct commit_extra_header *read_commit_extra_header_lines(const char *buffer, s
|
|||||||
if (next <= eof)
|
if (next <= eof)
|
||||||
eof = next;
|
eof = next;
|
||||||
|
|
||||||
if (standard_header_field(line, eof - line))
|
if (standard_header_field(line, eof - line) ||
|
||||||
|
excluded_header_field(line, eof - line, exclude))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
it = xcalloc(1, sizeof(*it));
|
it = xcalloc(1, sizeof(*it));
|
||||||
@ -975,13 +1074,14 @@ void free_commit_extra_headers(struct commit_extra_header *extra)
|
|||||||
|
|
||||||
int commit_tree(const struct strbuf *msg, unsigned char *tree,
|
int commit_tree(const struct strbuf *msg, unsigned char *tree,
|
||||||
struct commit_list *parents, unsigned char *ret,
|
struct commit_list *parents, unsigned char *ret,
|
||||||
const char *author)
|
const char *author, const char *sign_commit)
|
||||||
{
|
{
|
||||||
struct commit_extra_header *extra = NULL, **tail = &extra;
|
struct commit_extra_header *extra = NULL, **tail = &extra;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
append_merge_tag_headers(parents, &tail);
|
append_merge_tag_headers(parents, &tail);
|
||||||
result = commit_tree_extended(msg, tree, parents, ret, author, extra);
|
result = commit_tree_extended(msg, tree, parents, ret,
|
||||||
|
author, sign_commit, extra);
|
||||||
free_commit_extra_headers(extra);
|
free_commit_extra_headers(extra);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -993,7 +1093,8 @@ static const char commit_utf8_warn[] =
|
|||||||
|
|
||||||
int commit_tree_extended(const struct strbuf *msg, unsigned char *tree,
|
int commit_tree_extended(const struct strbuf *msg, unsigned char *tree,
|
||||||
struct commit_list *parents, unsigned char *ret,
|
struct commit_list *parents, unsigned char *ret,
|
||||||
const char *author, struct commit_extra_header *extra)
|
const char *author, const char *sign_commit,
|
||||||
|
struct commit_extra_header *extra)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
int encoding_is_utf8;
|
int encoding_is_utf8;
|
||||||
@ -1046,6 +1147,9 @@ int commit_tree_extended(const struct strbuf *msg, unsigned char *tree,
|
|||||||
if (encoding_is_utf8 && !is_utf8(buffer.buf))
|
if (encoding_is_utf8 && !is_utf8(buffer.buf))
|
||||||
fprintf(stderr, commit_utf8_warn);
|
fprintf(stderr, commit_utf8_warn);
|
||||||
|
|
||||||
|
if (sign_commit && do_sign_commit(&buffer, sign_commit))
|
||||||
|
return -1;
|
||||||
|
|
||||||
result = write_sha1_file(buffer.buf, buffer.len, commit_type, ret);
|
result = write_sha1_file(buffer.buf, buffer.len, commit_type, ret);
|
||||||
strbuf_release(&buffer);
|
strbuf_release(&buffer);
|
||||||
return result;
|
return result;
|
||||||
|
10
commit.h
10
commit.h
@ -193,15 +193,15 @@ extern void append_merge_tag_headers(struct commit_list *parents,
|
|||||||
|
|
||||||
extern int commit_tree(const struct strbuf *msg, unsigned char *tree,
|
extern int commit_tree(const struct strbuf *msg, unsigned char *tree,
|
||||||
struct commit_list *parents, unsigned char *ret,
|
struct commit_list *parents, unsigned char *ret,
|
||||||
const char *author);
|
const char *author, const char *sign_commit);
|
||||||
|
|
||||||
extern int commit_tree_extended(const struct strbuf *msg, unsigned char *tree,
|
extern int commit_tree_extended(const struct strbuf *msg, unsigned char *tree,
|
||||||
struct commit_list *parents, unsigned char *ret,
|
struct commit_list *parents, unsigned char *ret,
|
||||||
const char *author,
|
const char *author, const char *sign_commit,
|
||||||
struct commit_extra_header *);
|
struct commit_extra_header *);
|
||||||
|
|
||||||
extern struct commit_extra_header *read_commit_extra_headers(struct commit *);
|
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);
|
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);
|
extern void free_commit_extra_headers(struct commit_extra_header *extra);
|
||||||
|
|
||||||
@ -218,4 +218,6 @@ struct merge_remote_desc {
|
|||||||
*/
|
*/
|
||||||
struct commit *get_merge_parent(const char *name);
|
struct commit *get_merge_parent(const char *name);
|
||||||
|
|
||||||
|
extern int parse_signed_commit(const unsigned char *sha1,
|
||||||
|
struct strbuf *message, struct strbuf *signature);
|
||||||
#endif /* COMMIT_H */
|
#endif /* COMMIT_H */
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include "sigchain.h"
|
#include "sigchain.h"
|
||||||
|
|
||||||
static char *configured_signing_key;
|
static char *configured_signing_key;
|
||||||
|
static const char *gpg_program = "gpg";
|
||||||
|
|
||||||
void set_signing_key(const char *key)
|
void set_signing_key(const char *key)
|
||||||
{
|
{
|
||||||
@ -15,9 +16,12 @@ void set_signing_key(const char *key)
|
|||||||
int git_gpg_config(const char *var, const char *value, void *cb)
|
int git_gpg_config(const char *var, const char *value, void *cb)
|
||||||
{
|
{
|
||||||
if (!strcmp(var, "user.signingkey")) {
|
if (!strcmp(var, "user.signingkey")) {
|
||||||
|
set_signing_key(value);
|
||||||
|
}
|
||||||
|
if (!strcmp(var, "gpg.program")) {
|
||||||
if (!value)
|
if (!value)
|
||||||
return config_error_nonbool(var);
|
return config_error_nonbool(var);
|
||||||
set_signing_key(value);
|
gpg_program = xstrdup(value);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -46,7 +50,7 @@ int sign_buffer(struct strbuf *buffer, struct strbuf *signature, const char *sig
|
|||||||
gpg.argv = args;
|
gpg.argv = args;
|
||||||
gpg.in = -1;
|
gpg.in = -1;
|
||||||
gpg.out = -1;
|
gpg.out = -1;
|
||||||
args[0] = "gpg";
|
args[0] = gpg_program;
|
||||||
args[1] = "-bsau";
|
args[1] = "-bsau";
|
||||||
args[2] = signing_key;
|
args[2] = signing_key;
|
||||||
args[3] = NULL;
|
args[3] = NULL;
|
||||||
@ -91,20 +95,18 @@ int sign_buffer(struct strbuf *buffer, struct strbuf *signature, const char *sig
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Run "gpg" to see if the payload matches the detached signature.
|
* Run "gpg" to see if the payload matches the detached signature.
|
||||||
* gpg_output_to tells where the output from "gpg" should go:
|
* gpg_output, when set, receives the diagnostic output from GPG.
|
||||||
* < 0: /dev/null
|
|
||||||
* = 0: standard error of the calling process
|
|
||||||
* > 0: the specified file descriptor
|
|
||||||
*/
|
*/
|
||||||
int verify_signed_buffer(const char *payload, size_t payload_size,
|
int verify_signed_buffer(const char *payload, size_t payload_size,
|
||||||
const char *signature, size_t signature_size,
|
const char *signature, size_t signature_size,
|
||||||
struct strbuf *gpg_output)
|
struct strbuf *gpg_output)
|
||||||
{
|
{
|
||||||
struct child_process gpg;
|
struct child_process gpg;
|
||||||
const char *args_gpg[] = {"gpg", "--verify", "FILE", "-", NULL};
|
const char *args_gpg[] = {NULL, "--verify", "FILE", "-", NULL};
|
||||||
char path[PATH_MAX];
|
char path[PATH_MAX];
|
||||||
int fd, ret;
|
int fd, ret;
|
||||||
|
|
||||||
|
args_gpg[0] = gpg_program;
|
||||||
fd = git_mkstemp(path, PATH_MAX, ".git_vtag_tmpXXXXXX");
|
fd = git_mkstemp(path, PATH_MAX, ".git_vtag_tmpXXXXXX");
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return error("could not create temporary file '%s': %s",
|
return error("could not create temporary file '%s': %s",
|
||||||
|
129
log-tree.c
129
log-tree.c
@ -8,6 +8,7 @@
|
|||||||
#include "refs.h"
|
#include "refs.h"
|
||||||
#include "string-list.h"
|
#include "string-list.h"
|
||||||
#include "color.h"
|
#include "color.h"
|
||||||
|
#include "gpg-interface.h"
|
||||||
|
|
||||||
struct decoration name_decoration = { "object names" };
|
struct decoration name_decoration = { "object names" };
|
||||||
|
|
||||||
@ -403,6 +404,129 @@ void log_write_email_headers(struct rev_info *opt, struct commit *commit,
|
|||||||
*extra_headers_p = extra_headers;
|
*extra_headers_p = extra_headers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void show_sig_lines(struct rev_info *opt, int status, const char *bol)
|
||||||
|
{
|
||||||
|
const char *color, *reset, *eol;
|
||||||
|
|
||||||
|
color = diff_get_color_opt(&opt->diffopt,
|
||||||
|
status ? DIFF_WHITESPACE : DIFF_FRAGINFO);
|
||||||
|
reset = diff_get_color_opt(&opt->diffopt, DIFF_RESET);
|
||||||
|
while (*bol) {
|
||||||
|
eol = strchrnul(bol, '\n');
|
||||||
|
printf("%s%.*s%s%s", color, (int)(eol - bol), bol, reset,
|
||||||
|
*eol ? "\n" : "");
|
||||||
|
bol = (*eol) ? (eol + 1) : eol;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void show_signature(struct rev_info *opt, struct commit *commit)
|
||||||
|
{
|
||||||
|
struct strbuf payload = STRBUF_INIT;
|
||||||
|
struct strbuf signature = STRBUF_INIT;
|
||||||
|
struct strbuf gpg_output = STRBUF_INIT;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
if (parse_signed_commit(commit->object.sha1, &payload, &signature) <= 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
status = verify_signed_buffer(payload.buf, payload.len,
|
||||||
|
signature.buf, signature.len,
|
||||||
|
&gpg_output);
|
||||||
|
if (status && !gpg_output.len)
|
||||||
|
strbuf_addstr(&gpg_output, "No signature\n");
|
||||||
|
|
||||||
|
show_sig_lines(opt, status, gpg_output.buf);
|
||||||
|
|
||||||
|
out:
|
||||||
|
strbuf_release(&gpg_output);
|
||||||
|
strbuf_release(&payload);
|
||||||
|
strbuf_release(&signature);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int which_parent(const unsigned char *sha1, const struct commit *commit)
|
||||||
|
{
|
||||||
|
int nth;
|
||||||
|
const struct commit_list *parent;
|
||||||
|
|
||||||
|
for (nth = 0, parent = commit->parents; parent; parent = parent->next) {
|
||||||
|
if (!hashcmp(parent->item->object.sha1, sha1))
|
||||||
|
return nth;
|
||||||
|
nth++;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int is_common_merge(const struct commit *commit)
|
||||||
|
{
|
||||||
|
return (commit->parents
|
||||||
|
&& commit->parents->next
|
||||||
|
&& !commit->parents->next->next);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void show_one_mergetag(struct rev_info *opt,
|
||||||
|
struct commit_extra_header *extra,
|
||||||
|
struct commit *commit)
|
||||||
|
{
|
||||||
|
unsigned char sha1[20];
|
||||||
|
struct tag *tag;
|
||||||
|
struct strbuf verify_message;
|
||||||
|
int status, nth;
|
||||||
|
size_t payload_size, gpg_message_offset;
|
||||||
|
|
||||||
|
hash_sha1_file(extra->value, extra->len, typename(OBJ_TAG), sha1);
|
||||||
|
tag = lookup_tag(sha1);
|
||||||
|
if (!tag)
|
||||||
|
return; /* error message already given */
|
||||||
|
|
||||||
|
strbuf_init(&verify_message, 256);
|
||||||
|
if (parse_tag_buffer(tag, extra->value, extra->len))
|
||||||
|
strbuf_addstr(&verify_message, "malformed mergetag\n");
|
||||||
|
else if (is_common_merge(commit) &&
|
||||||
|
!hashcmp(tag->tagged->sha1,
|
||||||
|
commit->parents->next->item->object.sha1))
|
||||||
|
strbuf_addf(&verify_message,
|
||||||
|
"merged tag '%s'\n", tag->tag);
|
||||||
|
else if ((nth = which_parent(tag->tagged->sha1, commit)) < 0)
|
||||||
|
strbuf_addf(&verify_message, "tag %s names a non-parent %s\n",
|
||||||
|
tag->tag, tag->tagged->sha1);
|
||||||
|
else
|
||||||
|
strbuf_addf(&verify_message,
|
||||||
|
"parent #%d, tagged '%s'\n", nth + 1, tag->tag);
|
||||||
|
gpg_message_offset = verify_message.len;
|
||||||
|
|
||||||
|
payload_size = parse_signature(extra->value, extra->len);
|
||||||
|
if ((extra->len <= payload_size) ||
|
||||||
|
(verify_signed_buffer(extra->value, payload_size,
|
||||||
|
extra->value + payload_size,
|
||||||
|
extra->len - payload_size,
|
||||||
|
&verify_message) &&
|
||||||
|
verify_message.len <= gpg_message_offset)) {
|
||||||
|
strbuf_addstr(&verify_message, "No signature\n");
|
||||||
|
status = -1;
|
||||||
|
}
|
||||||
|
else if (strstr(verify_message.buf + gpg_message_offset,
|
||||||
|
": Good signature from "))
|
||||||
|
status = 0;
|
||||||
|
else
|
||||||
|
status = -1;
|
||||||
|
|
||||||
|
show_sig_lines(opt, status, verify_message.buf);
|
||||||
|
strbuf_release(&verify_message);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void show_mergetag(struct rev_info *opt, struct commit *commit)
|
||||||
|
{
|
||||||
|
struct commit_extra_header *extra, *to_free;
|
||||||
|
|
||||||
|
to_free = read_commit_extra_headers(commit, NULL);
|
||||||
|
for (extra = to_free; extra; extra = extra->next) {
|
||||||
|
if (strcmp(extra->key, "mergetag"))
|
||||||
|
continue; /* not a merge tag */
|
||||||
|
show_one_mergetag(opt, extra, commit);
|
||||||
|
}
|
||||||
|
free_commit_extra_headers(to_free);
|
||||||
|
}
|
||||||
|
|
||||||
void show_log(struct rev_info *opt)
|
void show_log(struct rev_info *opt)
|
||||||
{
|
{
|
||||||
struct strbuf msgbuf = STRBUF_INIT;
|
struct strbuf msgbuf = STRBUF_INIT;
|
||||||
@ -514,6 +638,11 @@ void show_log(struct rev_info *opt)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (opt->show_signature) {
|
||||||
|
show_signature(opt, commit);
|
||||||
|
show_mergetag(opt, commit);
|
||||||
|
}
|
||||||
|
|
||||||
if (!commit->buffer)
|
if (!commit->buffer)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ int notes_cache_write(struct notes_cache *c)
|
|||||||
return -1;
|
return -1;
|
||||||
strbuf_attach(&msg, c->validity,
|
strbuf_attach(&msg, c->validity,
|
||||||
strlen(c->validity), strlen(c->validity) + 1);
|
strlen(c->validity), strlen(c->validity) + 1);
|
||||||
if (commit_tree(&msg, tree_sha1, NULL, commit_sha1, NULL) < 0)
|
if (commit_tree(&msg, tree_sha1, NULL, commit_sha1, NULL, NULL) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
if (update_ref("update notes cache", c->tree.ref, commit_sha1, NULL,
|
if (update_ref("update notes cache", c->tree.ref, commit_sha1, NULL,
|
||||||
0, QUIET_ON_ERR) < 0)
|
0, QUIET_ON_ERR) < 0)
|
||||||
|
@ -551,7 +551,7 @@ void create_notes_commit(struct notes_tree *t, struct commit_list *parents,
|
|||||||
/* else: t->ref points to nothing, assume root/orphan commit */
|
/* else: t->ref points to nothing, assume root/orphan commit */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (commit_tree(msg, tree_sha1, parents, result_sha1, NULL))
|
if (commit_tree(msg, tree_sha1, parents, result_sha1, NULL, NULL))
|
||||||
die("Failed to commit notes tree to database");
|
die("Failed to commit notes tree to database");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
86
pretty.c
86
pretty.c
@ -9,6 +9,7 @@
|
|||||||
#include "notes.h"
|
#include "notes.h"
|
||||||
#include "color.h"
|
#include "color.h"
|
||||||
#include "reflog-walk.h"
|
#include "reflog-walk.h"
|
||||||
|
#include "gpg-interface.h"
|
||||||
|
|
||||||
static char *user_format;
|
static char *user_format;
|
||||||
static struct cmt_fmt_map {
|
static struct cmt_fmt_map {
|
||||||
@ -640,6 +641,12 @@ struct format_commit_context {
|
|||||||
const struct pretty_print_context *pretty_ctx;
|
const struct pretty_print_context *pretty_ctx;
|
||||||
unsigned commit_header_parsed:1;
|
unsigned commit_header_parsed:1;
|
||||||
unsigned commit_message_parsed:1;
|
unsigned commit_message_parsed:1;
|
||||||
|
unsigned commit_signature_parsed:1;
|
||||||
|
struct {
|
||||||
|
char *gpg_output;
|
||||||
|
char good_bad;
|
||||||
|
char *signer;
|
||||||
|
} signature;
|
||||||
char *message;
|
char *message;
|
||||||
size_t width, indent1, indent2;
|
size_t width, indent1, indent2;
|
||||||
|
|
||||||
@ -822,6 +829,59 @@ static void rewrap_message_tail(struct strbuf *sb,
|
|||||||
c->indent2 = new_indent2;
|
c->indent2 = new_indent2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
char result;
|
||||||
|
const char *check;
|
||||||
|
} signature_check[] = {
|
||||||
|
{ 'G', ": Good signature from " },
|
||||||
|
{ 'B', ": BAD signature from " },
|
||||||
|
};
|
||||||
|
|
||||||
|
static void parse_signature_lines(struct format_commit_context *ctx)
|
||||||
|
{
|
||||||
|
const char *buf = ctx->signature.gpg_output;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(signature_check); i++) {
|
||||||
|
const char *found = strstr(buf, signature_check[i].check);
|
||||||
|
const char *next;
|
||||||
|
if (!found)
|
||||||
|
continue;
|
||||||
|
ctx->signature.good_bad = signature_check[i].result;
|
||||||
|
found += strlen(signature_check[i].check);
|
||||||
|
next = strchrnul(found, '\n');
|
||||||
|
ctx->signature.signer = xmemdupz(found, next - found);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_commit_signature(struct format_commit_context *ctx)
|
||||||
|
{
|
||||||
|
struct strbuf payload = STRBUF_INIT;
|
||||||
|
struct strbuf signature = STRBUF_INIT;
|
||||||
|
struct strbuf gpg_output = STRBUF_INIT;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
ctx->commit_signature_parsed = 1;
|
||||||
|
|
||||||
|
if (parse_signed_commit(ctx->commit->object.sha1,
|
||||||
|
&payload, &signature) <= 0)
|
||||||
|
goto out;
|
||||||
|
status = verify_signed_buffer(payload.buf, payload.len,
|
||||||
|
signature.buf, signature.len,
|
||||||
|
&gpg_output);
|
||||||
|
if (status && !gpg_output.len)
|
||||||
|
goto out;
|
||||||
|
ctx->signature.gpg_output = strbuf_detach(&gpg_output, NULL);
|
||||||
|
parse_signature_lines(ctx);
|
||||||
|
|
||||||
|
out:
|
||||||
|
strbuf_release(&gpg_output);
|
||||||
|
strbuf_release(&payload);
|
||||||
|
strbuf_release(&signature);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int format_reflog_person(struct strbuf *sb,
|
static int format_reflog_person(struct strbuf *sb,
|
||||||
char part,
|
char part,
|
||||||
struct reflog_walk_info *log,
|
struct reflog_walk_info *log,
|
||||||
@ -999,6 +1059,30 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (placeholder[0] == 'G') {
|
||||||
|
if (!c->commit_signature_parsed)
|
||||||
|
parse_commit_signature(c);
|
||||||
|
switch (placeholder[1]) {
|
||||||
|
case 'G':
|
||||||
|
if (c->signature.gpg_output)
|
||||||
|
strbuf_addstr(sb, c->signature.gpg_output);
|
||||||
|
break;
|
||||||
|
case '?':
|
||||||
|
switch (c->signature.good_bad) {
|
||||||
|
case 'G':
|
||||||
|
case 'B':
|
||||||
|
strbuf_addch(sb, c->signature.good_bad);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'S':
|
||||||
|
if (c->signature.signer)
|
||||||
|
strbuf_addstr(sb, c->signature.signer);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* For the rest we have to parse the commit header. */
|
/* For the rest we have to parse the commit header. */
|
||||||
if (!c->commit_header_parsed)
|
if (!c->commit_header_parsed)
|
||||||
parse_commit_header(c);
|
parse_commit_header(c);
|
||||||
@ -1141,6 +1225,8 @@ void format_commit_message(const struct commit *commit,
|
|||||||
|
|
||||||
if (context.message != commit->buffer)
|
if (context.message != commit->buffer)
|
||||||
free(context.message);
|
free(context.message);
|
||||||
|
free(context.signature.gpg_output);
|
||||||
|
free(context.signature.signer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pp_header(const struct pretty_print_context *pp,
|
static void pp_header(const struct pretty_print_context *pp,
|
||||||
|
@ -1469,6 +1469,8 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
|
|||||||
revs->show_notes = 1;
|
revs->show_notes = 1;
|
||||||
revs->show_notes_given = 1;
|
revs->show_notes_given = 1;
|
||||||
revs->notes_opt.use_default_notes = 1;
|
revs->notes_opt.use_default_notes = 1;
|
||||||
|
} else if (!strcmp(arg, "--show-signature")) {
|
||||||
|
revs->show_signature = 1;
|
||||||
} else if (!prefixcmp(arg, "--show-notes=") ||
|
} else if (!prefixcmp(arg, "--show-notes=") ||
|
||||||
!prefixcmp(arg, "--notes=")) {
|
!prefixcmp(arg, "--notes=")) {
|
||||||
struct strbuf buf = STRBUF_INIT;
|
struct strbuf buf = STRBUF_INIT;
|
||||||
|
@ -110,6 +110,7 @@ struct rev_info {
|
|||||||
show_merge:1,
|
show_merge:1,
|
||||||
show_notes:1,
|
show_notes:1,
|
||||||
show_notes_given:1,
|
show_notes_given:1,
|
||||||
|
show_signature:1,
|
||||||
pretty_given:1,
|
pretty_given:1,
|
||||||
abbrev_commit:1,
|
abbrev_commit:1,
|
||||||
abbrev_commit_given:1,
|
abbrev_commit_given:1,
|
||||||
|
80
t/t7510-signed-commit.sh
Executable file
80
t/t7510-signed-commit.sh
Executable file
@ -0,0 +1,80 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
test_description='signed commit tests'
|
||||||
|
. ./test-lib.sh
|
||||||
|
. "$TEST_DIRECTORY/lib-gpg.sh"
|
||||||
|
|
||||||
|
test_expect_success GPG 'create signed commits' '
|
||||||
|
echo 1 >file && git add file &&
|
||||||
|
test_tick && git commit -S -m initial &&
|
||||||
|
git tag initial &&
|
||||||
|
git branch side &&
|
||||||
|
|
||||||
|
echo 2 >file && test_tick && git commit -a -S -m second &&
|
||||||
|
git tag second &&
|
||||||
|
|
||||||
|
git checkout side &&
|
||||||
|
echo 3 >elif && git add elif &&
|
||||||
|
test_tick && git commit -m "third on side" &&
|
||||||
|
|
||||||
|
git checkout master &&
|
||||||
|
test_tick && git merge -S side &&
|
||||||
|
git tag merge &&
|
||||||
|
|
||||||
|
echo 4 >file && test_tick && git commit -a -m "fourth unsigned" &&
|
||||||
|
git tag fourth-unsigned &&
|
||||||
|
|
||||||
|
test_tick && git commit --amend -S -m "fourth signed" &&
|
||||||
|
git tag fourth-signed
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success GPG 'show signatures' '
|
||||||
|
(
|
||||||
|
for commit in initial second merge master
|
||||||
|
do
|
||||||
|
git show --pretty=short --show-signature $commit >actual &&
|
||||||
|
grep "Good signature from" actual || exit 1
|
||||||
|
! grep "BAD signature from" actual || exit 1
|
||||||
|
echo $commit OK
|
||||||
|
done
|
||||||
|
) &&
|
||||||
|
(
|
||||||
|
for commit in merge^2 fourth-unsigned
|
||||||
|
do
|
||||||
|
git show --pretty=short --show-signature $commit >actual &&
|
||||||
|
grep "Good signature from" actual && exit 1
|
||||||
|
! grep "BAD signature from" actual || exit 1
|
||||||
|
echo $commit OK
|
||||||
|
done
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success GPG 'detect fudged signature' '
|
||||||
|
git cat-file commit master >raw &&
|
||||||
|
|
||||||
|
sed -e "s/fourth signed/4th forged/" raw >forged1 &&
|
||||||
|
git hash-object -w -t commit forged1 >forged1.commit &&
|
||||||
|
git show --pretty=short --show-signature $(cat forged1.commit) >actual1 &&
|
||||||
|
grep "BAD signature from" actual1 &&
|
||||||
|
! grep "Good signature from" actual1
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success GPG 'detect fudged signature with NUL' '
|
||||||
|
git cat-file commit master >raw &&
|
||||||
|
cat raw >forged2 &&
|
||||||
|
echo Qwik | tr "Q" "\000" >>forged2 &&
|
||||||
|
git hash-object -w -t commit forged2 >forged2.commit &&
|
||||||
|
git show --pretty=short --show-signature $(cat forged2.commit) >actual2 &&
|
||||||
|
grep "BAD signature from" actual2 &&
|
||||||
|
! 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
|
Loading…
Reference in New Issue
Block a user