From: Michael J Gruber <git@drmicha.warpmail.net>
To: Junio C Hamano <gitster@pobox.com>
Cc: git@vger.kernel.org
Subject: Re: [PATCH] commit: teach --gpg-sign option
Date: Sun, 09 Oct 2011 22:00:23 +0200 [thread overview]
Message-ID: <4E91FD57.7050808@drmicha.warpmail.net> (raw)
In-Reply-To: <7vaa9f3pk8.fsf@alter.siamese.dyndns.org>
Junio C Hamano venit, vidit, dixit 06.10.2011 02:56:
> And this uses the gpg-interface.[ch] to allow signing the commit, i.e.
>
> $ git commit --gpg-sign -m foo
> You need a passphrase to unlock the secret key for
> user: "Junio C Hamano <gitster@pobox.com>"
> 4096-bit RSA key, ID 96AFE6CB, created 2011-10-03 (main key ID 713660A7)
>
> [master 8457d13] foo
> 1 files changed, 1 insertions(+), 0 deletions(-)
>
> The lines of GPG detached signature are placed in new header lines, after
> the standard tree/parent/author/committer headers, instead of tucking the
> signature block at the end of the commit log message text (similar to how
> signed tag is done), for multiple reasons:
>
> - The signature won't clutter output from "git log" and friends if it is
> in the extra header. If we place it at the end of the log message, we
> would need to teach "git log" and friends to strip the signature block
> with an option.
>
> - Teaching new versions of "git log" and "gitk" to optionally verify and
> show signatures is cleaner if we structurally know where the signature
> block is (instead of scanning in the commit log message).
>
> - The signature needs to be stripped upon various commit rewriting
> operations, e.g. rebase, filter-branch, etc. They all already ignore
> unknown headers, but if we place signature in the log message, all of
> these tools (and third-party tools) also need to learn how a signature
> block would look like.
>
> - When we added the optional encoding header, all the tools (both in tree
> and third-party) that acts on the raw commit object should have been
> fixed to ignore headers they do not understand, so it is not like that
> new header would be more likely to break than extra text in the commit.
>
> A commit made with the above sample sequence would look like this:
>
> $ git cat-file commit HEAD
> tree 3cd71d90e3db4136e5260ab54599791c4f883b9d
> parent b87755351a47b09cb27d6913e6e0e17e6254a4d4
> author Junio C Hamano <gitster@pobox.com> 1317862251 -0700
> committer Junio C Hamano <gitster@pobox.com> 1317862251 -0700
> sig -----BEGIN PGP SIGNATURE-----
> sig Version: GnuPG v1.4.10 (GNU/Linux)
> sig
> sig iQIcBAABAgAGBQJOjPtrAAoJELC16IaWr+bL4TMP/RSe2Y/jYnCkds9unO5JEnfG
> sig ...
> sig =dt98
> sig -----END PGP SIGNATURE-----
>
> foo
>
I just noticed that this format differs from the one of signed tags.
What special reason is there for the "sig " indentation?
BTW: commit --amend --gpg-sign strips an existing signature rather than
adding one. We might want the user to have a say here.
> but "git log" (unless you ask for it with --pretty=raw) output is not
> cluttered with the signature information.
>
> Signed-off-by: Junio C Hamano <gitster@pobox.com>
> ---
>
> Cf.
> Message-ID: <7vfwjgui8s.fsf_-_@alter.siamese.dyndns.org>
> http://thread.gmane.org/gmane.comp.version-control.git/182297/focus=182384
>
> builtin/commit-tree.c | 24 +++++++++++++++++++++---
> builtin/commit.c | 12 ++++++++++--
> builtin/merge.c | 16 ++++++++++++++--
> commit.c | 41 ++++++++++++++++++++++++++++++++++++++++-
> commit.h | 2 +-
> notes-cache.c | 2 +-
> notes-merge.c | 2 +-
> 7 files changed, 88 insertions(+), 11 deletions(-)
>
> diff --git a/builtin/commit-tree.c b/builtin/commit-tree.c
> index d083795..a17811f 100644
> --- a/builtin/commit-tree.c
> +++ b/builtin/commit-tree.c
> @@ -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 <sha1> [(-p <sha1>)...] < changelog";
> +static const char commit_tree_usage[] = "git commit-tree [-S<signer>] <sha1> [(-p <sha1>)...] < changelog";
>
> 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);
> }
>
> +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;
> @@ -32,11 +41,19 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
> 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 (!memcmp(argv[1], "-S", 2)) {
> + sign_commit = argv[1] + 2;
> + argv++;
> + argc--;
> + }
> +
> if (get_sha1(argv[1], tree_sha1))
> die("Not a valid object name %s", argv[1]);
>
> @@ -56,7 +73,8 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
> if (strbuf_read(&buffer, 0, 0) < 0)
> 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;
> }
> diff --git a/builtin/commit.c b/builtin/commit.c
> index cbc9613..90cf7e8 100644
> --- a/builtin/commit.c
> +++ b/builtin/commit.c
> @@ -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>...",
> @@ -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
> @@ -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"),
> @@ -1323,6 +1328,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);
> @@ -1330,7 +1336,9 @@ static int git_commit_config(const char *k, const char *v, void *cb)
> include_status = git_config_bool(k, v);
> return 0;
> }
> -
> + status = git_gpg_config(k, v, NULL);
> + if (status)
> + return status;
> return git_status_config(k, v, s);
> }
>
> @@ -1481,7 +1489,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
> }
>
> if (commit_tree(sb.buf, active_cache_tree->sha1, parents, sha1,
> - author_ident.buf)) {
> + author_ident.buf, sign_commit)) {
> rollback_index_files();
> die(_("failed to write commit object"));
> }
> diff --git a/builtin/merge.c b/builtin/merge.c
> index ab4077f..53cff02 100644
> --- a/builtin/merge.c
> +++ b/builtin/merge.c
> @@ -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)
> @@ -63,6 +64,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 },
> @@ -206,6 +208,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()
> };
>
> @@ -525,6 +529,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")) {
> @@ -562,6 +568,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);
> }
>
> @@ -870,7 +880,8 @@ static int merge_trivial(void)
> parent->next->item = remoteheads->item;
> parent->next->next = NULL;
> run_prepare_commit_msg();
> - 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(result_commit, "In-index merge");
> drop_save();
> return 0;
> @@ -900,7 +911,8 @@ static int finish_automerge(struct commit_list *common,
> free_commit_list(remoteheads);
> strbuf_addch(&merge_msg, '\n');
> run_prepare_commit_msg();
> - 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(result_commit, buf.buf);
> strbuf_release(&buf);
> diff --git a/commit.c b/commit.c
> index 97b4327..969435d 100644
> --- a/commit.c
> +++ b/commit.c
> @@ -6,6 +6,7 @@
> #include "diff.h"
> #include "revision.h"
> #include "notes.h"
> +#include "gpg-interface.h"
>
> int save_commit_buffer = 1;
>
> @@ -814,6 +815,41 @@ struct commit_list *reduce_heads(struct commit_list *heads)
> return result;
> }
>
> +static int do_sign_commit(struct strbuf *buf, const char *keyid)
> +{
> + struct strbuf sig = STRBUF_INIT;
> + int inspos, copypos;
> + const char gpg_sig[] = "sig ";
> + const int header_len = sizeof(gpg_sig) - 1;
> +
> + /* find the end of the header */
> + inspos = strstr(buf->buf, "\n\n") - buf->buf + 1;
> + copypos = buf->len;
> +
> + strbuf_addbuf(&sig, buf);
> +
> + if (!keyid || !*keyid)
> + keyid = get_signing_key();
> + if (sign_buffer(&sig, keyid)) {
> + strbuf_release(&sig);
> + return -1;
> + }
> +
> + while (sig.buf[copypos]) {
> + const char *bol = sig.buf + copypos;
> + const char *eol = strchrnul(bol, '\n');
> + int len = (eol - bol) + !!*eol;
> + strbuf_insert(buf, inspos, gpg_sig, header_len);
> + inspos += header_len;
> + strbuf_insert(buf, inspos, bol, len);
> + inspos += len;
> + copypos += len;
> + }
> + strbuf_release(&sig);
> + return 0;
> +}
> +
> +
> static const char commit_utf8_warn[] =
> "Warning: commit message does not conform to UTF-8.\n"
> "You may want to amend it after fixing the message, or set the config\n"
> @@ -821,7 +857,7 @@ static const char commit_utf8_warn[] =
>
> 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)
> {
> int result;
> int encoding_is_utf8;
> @@ -864,6 +900,9 @@ int commit_tree(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;
> diff --git a/commit.h b/commit.h
> index 12d100b8..8c2419b 100644
> --- a/commit.h
> +++ b/commit.h
> @@ -175,6 +175,6 @@ struct commit_list *reduce_heads(struct commit_list *heads);
>
> 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);
>
> #endif /* COMMIT_H */
> diff --git a/notes-cache.c b/notes-cache.c
> index 4c8984e..c36a960 100644
> --- a/notes-cache.c
> +++ b/notes-cache.c
> @@ -56,7 +56,7 @@ int notes_cache_write(struct notes_cache *c)
>
> if (write_notes_tree(&c->tree, tree_sha1))
> return -1;
> - if (commit_tree(c->validity, tree_sha1, NULL, commit_sha1, NULL) < 0)
> + if (commit_tree(c->validity, tree_sha1, NULL, commit_sha1, NULL, NULL) < 0)
> return -1;
> if (update_ref("update notes cache", c->tree.ref, commit_sha1, NULL,
> 0, QUIET_ON_ERR) < 0)
> diff --git a/notes-merge.c b/notes-merge.c
> index e1aaf43..c29c434 100644
> --- a/notes-merge.c
> +++ b/notes-merge.c
> @@ -546,7 +546,7 @@ void create_notes_commit(struct notes_tree *t, struct commit_list *parents,
> /* 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");
> }
>
next prev parent reply other threads:[~2011-10-09 20:00 UTC|newest]
Thread overview: 35+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-10-06 0:56 [PATCH] commit: teach --gpg-sign option Junio C Hamano
2011-10-06 15:50 ` Shawn Pearce
2011-10-06 17:11 ` Jonathan Nieder
2011-10-06 17:22 ` Matthieu Moy
2011-10-06 18:44 ` Michael J Gruber
2011-10-06 21:29 ` Junio C Hamano
2011-10-06 22:24 ` Robin H. Johnson
2011-10-07 8:40 ` Michael J Gruber
2011-10-07 11:18 ` Nguyen Thai Ngoc Duy
2011-10-09 16:32 ` Michael J Gruber
2011-10-09 22:57 ` Robin H. Johnson
2011-10-09 23:18 ` Junio C Hamano
2011-10-11 0:38 ` Robin H. Johnson
2011-10-09 20:00 ` Michael J Gruber [this message]
2011-10-09 21:22 ` Junio C Hamano
2011-10-10 6:33 ` Michael J Gruber
2011-10-10 16:35 ` Junio C Hamano
2011-10-09 22:27 ` Junio C Hamano
2011-10-10 6:33 ` Michael J Gruber
2011-10-10 16:45 ` Junio C Hamano
2011-10-11 6:39 ` Michael J Gruber
[not found] ` <CACBZZX6xsnAv4S8zAqi08bcqrghZ8nKdzFP=UNCqZOqrEeLFnA@mail.gmail.com>
2011-10-10 4:58 ` Junio C Hamano
2011-10-19 0:20 ` [PATCH v3 0/3] Signed-commit Junio C Hamano
2011-10-19 0:20 ` [PATCH v3 1/3] Split GPG interface into its own helper library Junio C Hamano
2011-10-19 0:20 ` [PATCH v3 2/3] commit: teach --gpg-sign option Junio C Hamano
2011-10-19 0:20 ` [PATCH v3 3/3] log: --show-signature Junio C Hamano
2011-10-20 0:36 ` [PATCH v4 0/5] Signed-commit Junio C Hamano
2011-10-20 0:36 ` [PATCH v4 1/5] Split GPG interface into its own helper library Junio C Hamano
2011-10-20 0:37 ` [PATCH v4 2/5] commit: teach --gpg-sign option Junio C Hamano
2011-10-20 0:37 ` [PATCH v4 3/5] log: --show-signature Junio C Hamano
2011-10-20 0:37 ` [PATCH v4 4/5] t7004: extract generic "GPG testing" bits Junio C Hamano
2011-10-20 0:37 ` [PATCH v4 5/5] test "commit -S" and "log --show-signature" Junio C Hamano
2011-10-22 5:01 ` [PATCH 7/5] pretty: %G[?GS] placeholders Junio C Hamano
2011-10-22 10:47 ` Elia Pinto
2011-10-22 17:55 ` Junio C Hamano
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4E91FD57.7050808@drmicha.warpmail.net \
--to=git@drmicha.warpmail.net \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).