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

[PATCH 4/5] for-each-ref: handle multiline subjects like --pretty

From
Jeff King <peff@peff.net>
Date
Sep 7, 2011, 17:44 UTC
Message-ID
<20110907174456.GD11355@sigill.intra.peff.net>
In-Reply-To
<20110902175323.GA29761@sigill.intra.peff.net>
Generally the format of a git tag or commit message is:
  subject
  body body body
  body body body
However, we occasionally see multiline subjects like:
  subject
  with multiple
  lines
  body body body
  body body body

The rest of git treats these multiline subjects as something to be concatenated and shown as a single line (e.g., "git log --pretty=format:%s" will do so since f53bd74). For consistency, for-each-ref should do the same with its "%(subject)".

Signed-off-by: Jeff King <peff@peff.net>
---
I split this out from the signature patch to make it more obvious what's
going on.
 builtin/for-each-ref.c  |   29 ++++++++++++++++++++++++-----
 t/t6300-for-each-ref.sh |   21 +++++++++++++++++++++
 2 files changed, 45 insertions(+), 5 deletions(-)
diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c
index bcea027..ea2112b 100644
--- a/builtin/for-each-ref.c
+++ b/builtin/for-each-ref.c
@@ -361,6 +361,18 @@ static const char *copy_email(const char *buf)
 	return xmemdupz(email, eoemail + 1 - email);
 }
 
+static char *copy_subject(const char *buf, unsigned long len)
+{
+	char *r = xmemdupz(buf, len);
+	int i;
+
+	for (i = 0; i < len; i++)
+		if (r[i] == '\n')
+			r[i] = ' ';
+
+	return r;
+}
+
 static void grab_date(const char *buf, struct atom_value *v, const char *atomname)
 {
 	const char *eoemail = strstr(buf, "> ");
@@ -476,10 +488,17 @@ static void find_subpos(const char *buf, unsigned long sz,
 
 	/* subject is first non-empty line */
 	*sub = buf;
-	/* subject goes to end of line */
-	eol = strchrnul(buf, '\n');
-	*sublen = eol - buf;
-	buf = eol;
+	/* subject goes to first empty line */
+	while (*buf && *buf != '\n') {
+		eol = strchrnul(buf, '\n');
+		if (*eol)
+			eol++;
+		buf = eol;
+	}
+	*sublen = buf - *sub;
+	/* drop trailing newline, if present */
+	if (*sublen && (*sub)[*sublen - 1] == '\n')
+		*sublen -= 1;
 
 	/* skip any empty lines */
 	while (*buf == '\n')
@@ -512,7 +531,7 @@ static void grab_sub_body_contents(struct atom_value *val, int deref, struct obj
 				    &bodypos, &bodylen);
 
 		if (!strcmp(name, "subject"))
-			v->s = xmemdupz(subpos, sublen);
+			v->s = copy_subject(subpos, sublen);
 		else if (!strcmp(name, "body"))
 			v->s = xmemdupz(bodypos, bodylen);
 		else if (!strcmp(name, "contents"))
diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index 6fa4d52..0c9ff96 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -379,4 +379,25 @@ first body line
 second body line
 '
 
+test_expect_success 'create tag with multiline subject' '
+	cat >msg <<-\EOF &&
+		first subject line
+		second subject line
+
+		first body line
+		second body line
+	EOF
+	git tag -F msg multiline
+'
+test_atom refs/tags/multiline subject 'first subject line second subject line'
+test_atom refs/tags/multiline body 'first body line
+second body line
+'
+test_atom refs/tags/multiline contents 'first subject line
+second subject line
+
+first body line
+second body line
+'
+
 test_done
-- 
1.7.6.10.g62f04
Previous: Jeff KingNext: Jeff King
Message 29 of 32 in “More formatting with 'git tag -l'”
  1. Michał GórnyAug 29, 2011
  2. Jeff KingAug 29, 2011
  3. Michał GórnyAug 29, 2011
  4. Jeff KingAug 29, 2011
  5. Michał GórnyAug 29, 2011
  6. git-for-each-ref: move GPG sigs off %(body) to %(signature).Michał Górny, Aug 30, 2011
  7. Michael J GruberAug 30, 2011
  8. Michał GórnyAug 30, 2011
  9. Jeff KingAug 30, 2011
  10. for-each-ref: add split message parts to %(contents:*).Michał Górny, Aug 31, 2011
  11. Jeff KingAug 31, 2011
  12. 1/2 t7004: factor out gpg setupJeff King, Aug 31, 2011
  13. 2/2 t6300: test new content:* for-each-ref placeholdersJeff King, Aug 31, 2011
  14. Junio C HamanoAug 31, 2011
  15. Jeff KingAug 31, 2011
  16. Michał GórnySep 1, 2011
  17. Junio C HamanoSep 1, 2011
  18. Jeff KingSep 1, 2011
  19. Michał GórnySep 1, 2011
  20. for-each-ref: add split message parts to %(contents:*).Michał Górny, Sep 1, 2011
  21. Jeff KingSep 2, 2011
  22. Michał GórnySep 2, 2011
  23. Jeff KingSep 2, 2011
  24. Jeff KingSep 7, 2011
  25. Michał GórnySep 15, 2011
  26. 1/5 t7004: factor out gpg setupJeff King, Sep 7, 2011
  27. 2/5 t6300: add more body-parsing testsJeff King, Sep 7, 2011
  28. 3/5 for-each-ref: refactor subject and body placeholder parsingJeff King, Sep 7, 2011
  29. 4/5 for-each-ref: handle multiline subjects like --prettyJeff King, Sep 7, 2011
  30. 5/5 for-each-ref: add split message parts to %(contents:*).Jeff King, Sep 7, 2011
  31. Junio C HamanoSep 1, 2011
  32. Jeff KingSep 1, 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.