[PATCH 09/10] fmt-merge-msg: Add contents of merged tag in the merge message

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



When a contributor asks the integrator to merge her history, a signed tag
can be a good vehicle to communicate the authenticity of the request while
conveying other information such as the purpose of the topic.

E.g. a signed tag "for-linus" can be created, and the integrator can run:

   $ git pull git://example.com/work.git/ for-linus

This would allow the integrator to run "git verify-tag FETCH_HEAD" to
validate the signed tag.

While we do not necessarily want to clutter the global tag namespace of
the project, we would want to leave enough information in the repository
to allow third party to later validate the resulting history.

Update fmt-merge-msg that prepares the merge message template, and store
the contents of the signed tag object and the message that comes from GPG
signature validation at the end of it. The integrator can choose to leave
the contents of the tag in the resulting merge commit, or can choose to
remove it. The GPG validation message is inserted as a comment only to
help the integrator to review the validation result but otherwise will not
be recorded in the resulting merge commit, because later validation by
third parties does not need it.

Signed-off-by: Junio C Hamano <gitster@xxxxxxxxx>
---

 * And this is the most interesting one.

 builtin/fmt-merge-msg.c |   79 +++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 79 insertions(+), 0 deletions(-)

diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c
index 3ff9564..f615fa5 100644
--- a/builtin/fmt-merge-msg.c
+++ b/builtin/fmt-merge-msg.c
@@ -5,6 +5,7 @@
 #include "revision.h"
 #include "tag.h"
 #include "string-list.h"
+#include "gpg-interface.h"
 
 static const char * const fmt_merge_msg_usage[] = {
 	"git fmt-merge-msg [-m <message>] [--log[=<n>]|--no-log] [--file <file>]",
@@ -262,6 +263,80 @@ static void fmt_merge_msg_title(struct strbuf *out,
 		strbuf_addf(out, " into %s\n", current_branch);
 }
 
+static void add_lines_with_prefix(struct strbuf *out, const char *prefix,
+				  const char *buf, size_t size)
+{
+	while (size) {
+		const char *next = memchr(buf, '\n', size);
+		next = next ? (next + 1) : (buf + size);
+		strbuf_addstr(out, prefix);
+		strbuf_add(out, buf, next - buf);
+		size -= next - buf;
+		buf = next;
+	}
+}
+
+static void fmt_tag_signature(struct strbuf *tagbuf,
+			      struct strbuf *sig,
+			      const char *buf,
+			      unsigned long size)
+{
+	add_lines_with_prefix(tagbuf, "tag:", buf, size);
+	add_lines_with_prefix(tagbuf, "# ", sig->buf, sig->len);
+	if (tagbuf->len && tagbuf->buf[tagbuf->len-1] != '\n')
+		strbuf_addch(tagbuf, '\n');
+}
+
+
+static void fmt_merge_msg_sigs(struct strbuf *out)
+{
+	int i, tag_number;
+	struct strbuf tagbuf = STRBUF_INIT;
+
+	for (i = tag_number = 0; i < origins.nr; i++) {
+		unsigned char *sha1 = origins.items[i].util;
+		enum object_type type;
+		unsigned long size, len;
+		char *buf = read_sha1_file(sha1, &type, &size);
+		struct strbuf sig = STRBUF_INIT;
+
+		if (!buf || type != OBJ_TAG)
+			goto next;
+		len = parse_signature(buf, size);
+		if (size == len)
+			goto next; /* not a signed tag */
+		if (verify_signed_buffer(buf, len, buf + len, size - len,
+					 &sig) ||
+		    !sig.len)
+			goto next;
+
+		if (!tag_number++)
+			fmt_tag_signature(&tagbuf, &sig, buf, size);
+		else {
+			if (tag_number == 2) {
+				static const char first_tag[] = "[Tag 1]\n";
+				strbuf_insert(&tagbuf, 0, first_tag,
+					      sizeof(first_tag) - 1);
+			}
+			strbuf_addf(&tagbuf, "\n[Tag %d]\n", tag_number);
+			fmt_tag_signature(&tagbuf, &sig, buf, size);
+		}
+		strbuf_release(&sig);
+	next:
+		free(buf);
+	}
+	if (tagbuf.len) {
+		strbuf_addch(out, '\n');
+		if (tag_number == 1)
+			strbuf_addstr(out, "Signature in merged tag\n");
+		else
+			strbuf_addstr(out, "Signatures in merged tags\n");
+		strbuf_addch(out, '\n');
+		strbuf_addbuf(out, &tagbuf);
+	}
+	strbuf_release(&tagbuf);
+}
+
 int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
 		  struct fmt_merge_msg_opts *opts)
 {
@@ -310,6 +385,10 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
 			shortlog(origins.items[i].string, origins.items[i].util,
 				 head, &rev, opts->shortlog_len, out);
 	}
+
+	if (origins.nr)
+		fmt_merge_msg_sigs(out);
+
 	if (out->len && out->buf[out->len-1] != '\n')
 		strbuf_addch(out, '\n');
 	return 0;
-- 
1.7.8.rc0.108.g71b5ec

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]