git/list[1] front-page[2] threads[3] people[4] search[5] about
 

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

From
Junio C Hamano <gitster@pobox.com>
Date
Nov 5, 2011, 06:01 UTC
Message-ID
<1320472900-6601-10-git-send-email-gitster@pobox.com>
In-Reply-To
<1320472900-6601-1-git-send-email-gitster@pobox.com>

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@pobox.com>
---
 * 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
Previous: Junio C HamanoNext: Johannes Sixt
Message 10 of 32 in “Pulling signed tag”
  1. 00/10 Pulling signed tagJunio C Hamano, Nov 5, 2011
  2. 01/10 Split GPG interface into its own helper libraryJunio C Hamano, Nov 5, 2011
  3. 02/10 fetch: do not store peeled tag object names in FETCH_HEADJunio C Hamano, Nov 5, 2011
  4. 03/10 merge: notice local merging of tags and keep it unwrappedJunio C Hamano, Nov 5, 2011
  5. 04/10 fetch: allow "git fetch $there v1.0" to fetch a tagJunio C Hamano, Nov 5, 2011
  6. 05/10 tests: distinguish merges of tags and commitsJunio C Hamano, Nov 5, 2011
  7. 06/10 refs DWIMmery: use the same rule for both "git fetch" and othersJunio C Hamano, Nov 5, 2011
  8. 07/10 fmt-merge-msg: avoid early returnsJunio C Hamano, Nov 5, 2011
  9. 08/10 fmt-merge-msg: package options into a structureJunio C Hamano, Nov 5, 2011
  10. 09/10 fmt-merge-msg: Add contents of merged tag in the merge messageJunio C Hamano, Nov 5, 2011
  11. Johannes SixtNov 5, 2011
  12. Junio C HamanoNov 6, 2011
  13. 10/10 merge: force edit mode when merging a tag objectJunio C Hamano, Nov 5, 2011
  14. Nguyen Thai Ngoc DuyNov 5, 2011
  15. 00/12 Pulling signed/annotated tagsJunio C Hamano, Nov 8, 2011
  16. 01/12 Split GPG interface into its own helper libraryJunio C Hamano, Nov 8, 2011
  17. 02/12 fetch: do not store peeled tag object names in FETCH_HEADJunio C Hamano, Nov 8, 2011
  18. 03/12 merge: notice local merging of tags and keep it unwrappedJunio C Hamano, Nov 8, 2011
  19. 04/12 fetch: allow "git fetch $there v1.0" to fetch a tagJunio C Hamano, Nov 8, 2011
  20. 05/12 refs DWIMmery: use the same rule for both "git fetch" and othersJunio C Hamano, Nov 8, 2011
  21. 06/12 fmt-merge-msg: avoid early returnsJunio C Hamano, Nov 8, 2011
  22. 07/12 fmt-merge-msg: package options into a structureJunio C Hamano, Nov 8, 2011
  23. 08/12 fmt-merge-msg: Add contents of merged tag in the merge messageJunio C Hamano, Nov 8, 2011
  24. 09/12 merge: make usage of commit->util more extensibleJunio C Hamano, Nov 8, 2011
  25. 10/12 merge: record tag objects without peeling in MERGE_HEADJunio C Hamano, Nov 8, 2011
  26. 11/12 commit: copy merged signed tags to headers of merge commitJunio C Hamano, Nov 8, 2011
  27. 12/12 merge: force edit mode when merging a tag objectJunio C Hamano, Nov 8, 2011
  28. Linus TorvaldsNov 8, 2011
  29. Junio C HamanoNov 8, 2011
  30. Linus TorvaldsNov 8, 2011
  31. Junio C HamanoNov 8, 2011
  32. Junio C HamanoNov 8, 2011

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.