Skip to content

Commit

Permalink
Merge branch 'jc/signed-commit' and 'jc/pull-signed-tag'
Browse files Browse the repository at this point in the history
They both use the extended headers in commit objects, and the former has
necessary infrastructure to show them that is useful to view the result of
the latter.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
Junio C Hamano committed Jan 5, 2012
2 parents 0074d18 + 0c5e70f commit 9d3d784
Show file tree
Hide file tree
Showing 15 changed files with 364 additions and 19 deletions.
11 changes: 11 additions & 0 deletions Documentation/config.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1094,6 +1094,17 @@ grep.lineNumber::
grep.extendedRegexp::
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::
Defines how wide the commit message window is in the
linkgit:git-gui[1]. "75" is the default.
Expand Down
8 changes: 5 additions & 3 deletions Documentation/git-tag.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ created (i.e. a lightweight tag).
A GnuPG signed tag object will be created when `-s` or `-u
<key-id>` is used. When `-u <key-id>` is not used, 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
-------
Expand All @@ -48,11 +50,11 @@ OPTIONS

-s::
--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>::
--local-user=<key-id>::
Make a GPG-signed tag, using the given key
Make a GPG-signed tag, using the given key.

-f::
--force::
Expand Down
25 changes: 22 additions & 3 deletions builtin/commit-tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@
#include "tree.h"
#include "builtin.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)
{
Expand All @@ -25,19 +26,31 @@ static void new_parent(struct commit *parent, struct commit_list **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 i, got_tree = 0;
struct commit_list *parents = NULL;
unsigned char tree_sha1[20];
unsigned char commit_sha1[20];
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"))
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++) {
const char *arg = argv[i];
if (!strcmp(arg, "-p")) {
Expand All @@ -51,6 +64,11 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
continue;
}

if (!memcmp(arg, "-S", 2)) {
sign_commit = arg + 2;
continue;
}

if (!strcmp(arg, "-m")) {
if (argc <= ++i)
usage(commit_tree_usage);
Expand Down Expand Up @@ -98,7 +116,8 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
die_errno("git commit-tree: failed to read");
}

if (commit_tree(buffer.buf, tree_sha1, parents, commit_sha1, NULL)) {
if (commit_tree(buffer.buf, tree_sha1, parents, commit_sha1,
NULL, sign_commit)) {
strbuf_release(&buffer);
return 1;
}
Expand Down
11 changes: 10 additions & 1 deletion builtin/commit.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "unpack-trees.h"
#include "quote.h"
#include "submodule.h"
#include "gpg-interface.h"

static const char * const builtin_commit_usage[] = {
"git commit [options] [--] <filepattern>...",
Expand Down Expand Up @@ -85,6 +86,8 @@ static int all, edit_flag, also, interactive, patch_interactive, only, amend, si
static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;
static int no_post_rewrite, allow_empty_message;
static char *untracked_files_arg, *force_date, *ignore_submodule_arg;
static char *sign_commit;

/*
* The default commit message cleanup mode will remove the lines
* beginning with # (shell comments) and leading and trailing
Expand Down Expand Up @@ -144,6 +147,8 @@ static struct option builtin_commit_options[] = {
OPT_BOOLEAN('e', "edit", &edit_flag, "force edit of commit"),
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"),
{ OPTION_STRING, 'S', "gpg-sign", &sign_commit, "key id",
"GPG sign commit", PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
/* end commit message options */

OPT_GROUP("Commit contents options"),
Expand Down Expand Up @@ -1324,6 +1329,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)
{
struct wt_status *s = cb;
int status;

if (!strcmp(k, "commit.template"))
return git_config_pathname(&template_file, k, v);
Expand All @@ -1332,6 +1338,9 @@ static int git_commit_config(const char *k, const char *v, void *cb)
return 0;
}

status = git_gpg_config(k, v, NULL);
if (status)
return status;
return git_status_config(k, v, s);
}

Expand Down Expand Up @@ -1492,7 +1501,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
}

if (commit_tree_extended(sb.buf, active_cache_tree->sha1, parents, sha1,
author_ident.buf, extra)) {
author_ident.buf, sign_commit, extra)) {
rollback_index_files();
die(_("failed to write commit object"));
}
Expand Down
16 changes: 14 additions & 2 deletions builtin/merge.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "merge-recursive.h"
#include "resolve-undo.h"
#include "remote.h"
#include "gpg-interface.h"

#define DEFAULT_TWOHEAD (1<<0)
#define DEFAULT_OCTOPUS (1<<1)
Expand Down Expand Up @@ -62,6 +63,7 @@ static int allow_rerere_auto;
static int abort_current_merge;
static int show_progress = -1;
static int default_to_upstream;
static const char *sign_commit;

static struct strategy all_strategy[] = {
{ "recursive", DEFAULT_TWOHEAD | NO_TRIVIAL },
Expand Down Expand Up @@ -207,6 +209,8 @@ static struct option builtin_merge_options[] = {
OPT_BOOLEAN(0, "abort", &abort_current_merge,
"abort the current in-progress merge"),
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_END()
};

Expand Down Expand Up @@ -533,6 +537,8 @@ static void parse_branch_merge_options(char *bmo)

static int git_merge_config(const char *k, const char *v, void *cb)
{
int status;

if (branch && !prefixcmp(k, "branch.") &&
!prefixcmp(k + 7, branch) &&
!strcmp(k + 7 + strlen(branch), ".mergeoptions")) {
Expand Down Expand Up @@ -570,6 +576,10 @@ static int git_merge_config(const char *k, const char *v, void *cb)
default_to_upstream = git_config_bool(k, v);
return 0;
}

status = git_gpg_config(k, v, NULL);
if (status)
return status;
return git_diff_ui_config(k, v, cb);
}

Expand Down Expand Up @@ -902,7 +912,8 @@ static int merge_trivial(struct commit *head)
parent->next->item = remoteheads->item;
parent->next->next = NULL;
prepare_to_commit();
commit_tree(merge_msg.buf, result_tree, parent, result_commit, NULL);
commit_tree(merge_msg.buf, result_tree, parent, result_commit, NULL,
sign_commit);
finish(head, result_commit, "In-index merge");
drop_save();
return 0;
Expand Down Expand Up @@ -933,7 +944,8 @@ static int finish_automerge(struct commit *head,
strbuf_addch(&merge_msg, '\n');
prepare_to_commit();
free_commit_list(remoteheads);
commit_tree(merge_msg.buf, result_tree, parents, result_commit, NULL);
commit_tree(merge_msg.buf, result_tree, parents, result_commit,
NULL, sign_commit);
strbuf_addf(&buf, "Merge made by the '%s' strategy.", wt_strategy);
finish(head, result_commit, buf.buf);
strbuf_release(&buf);
Expand Down
92 changes: 89 additions & 3 deletions commit.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "diff.h"
#include "revision.h"
#include "notes.h"
#include "gpg-interface.h"

int save_commit_buffer = 1;

Expand Down Expand Up @@ -840,6 +841,86 @@ struct commit_list *reduce_heads(struct commit_list *heads)
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)
{
struct merge_remote_desc *desc;
Expand Down Expand Up @@ -975,13 +1056,14 @@ void free_commit_extra_headers(struct commit_extra_header *extra)

int commit_tree(const char *msg, unsigned char *tree,
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;
int result;

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);
return result;
}
Expand All @@ -993,7 +1075,8 @@ static const char commit_utf8_warn[] =

int commit_tree_extended(const char *msg, unsigned char *tree,
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 encoding_is_utf8;
Expand Down Expand Up @@ -1043,6 +1126,9 @@ int commit_tree_extended(const char *msg, unsigned char *tree,
if (encoding_is_utf8 && !is_utf8(buffer.buf))
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);
strbuf_release(&buffer);
return result;
Expand Down
6 changes: 4 additions & 2 deletions commit.h
Original file line number Diff line number Diff line change
Expand Up @@ -193,11 +193,11 @@ extern void append_merge_tag_headers(struct commit_list *parents,

extern int commit_tree(const char *msg, unsigned char *tree,
struct commit_list *parents, unsigned char *ret,
const char *author);
const char *author, const char *sign_commit);

extern int commit_tree_extended(const char *msg, unsigned char *tree,
struct commit_list *parents, unsigned char *ret,
const char *author,
const char *author, const char *sign_commit,
struct commit_extra_header *);

extern struct commit_extra_header *read_commit_extra_headers(struct commit *);
Expand All @@ -218,4 +218,6 @@ struct merge_remote_desc {
*/
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 */
Loading

0 comments on commit 9d3d784

Please sign in to comment.