for-each-ref: handle multiline subjects like --pretty

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> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jeff King committed Sep 7, 2011 at 13:44 UTC 7f6e275bc003e04fca63ae1058bb665078f72d7e
2 files changed +45 -5
builtin/for-each-ref.c
+24 -5
@@ -361,6 +361,18 @@ static const char *copy_email(const char *buf)
361 return xmemdupz(email, eoemail + 1 - email);
362 }
363
364 +static char *copy_subject(const char *buf, unsigned long len)
365 +{
366 + char *r = xmemdupz(buf, len);
367 + int i;
368 +
369 + for (i = 0; i < len; i++)
370 + if (r[i] == '\n')
371 + r[i] = ' ';
372 +
373 + return r;
374 +}
375 +
376 static void grab_date(const char *buf, struct atom_value *v, const char *atomname)
377 {
378 const char *eoemail = strstr(buf, "> ");
@@ -476,10 +488,17 @@ static void find_subpos(const char *buf, unsigned long sz,
488
489 /* subject is first non-empty line */
490 *sub = buf;
479 - /* subject goes to end of line */
480 - eol = strchrnul(buf, '\n');
481 - *sublen = eol - buf;
482 - buf = eol;
491 + /* subject goes to first empty line */
492 + while (*buf && *buf != '\n') {
493 + eol = strchrnul(buf, '\n');
494 + if (*eol)
495 + eol++;
496 + buf = eol;
497 + }
498 + *sublen = buf - *sub;
499 + /* drop trailing newline, if present */
500 + if (*sublen && (*sub)[*sublen - 1] == '\n')
501 + *sublen -= 1;
502
503 /* skip any empty lines */
504 while (*buf == '\n')
@@ -512,7 +531,7 @@ static void grab_sub_body_contents(struct atom_value *val, int deref, struct obj
531 &bodypos, &bodylen);
532
533 if (!strcmp(name, "subject"))
515 - v->s = xmemdupz(subpos, sublen);
534 + v->s = copy_subject(subpos, sublen);
535 else if (!strcmp(name, "body"))
536 v->s = xmemdupz(bodypos, bodylen);
537 else if (!strcmp(name, "contents"))
t/t6300-for-each-ref.sh
+21
@@ -379,4 +379,25 @@ first body line
379 second body line
380 '
381
382 +test_expect_success 'create tag with multiline subject' '
383 + cat >msg <<-\EOF &&
384 + first subject line
385 + second subject line
386 +
387 + first body line
388 + second body line
389 + EOF
390 + git tag -F msg multiline
391 +'
392 +test_atom refs/tags/multiline subject 'first subject line second subject line'
393 +test_atom refs/tags/multiline body 'first body line
394 +second body line
395 +'
396 +test_atom refs/tags/multiline contents 'first subject line
397 +second subject line
398 +
399 +first body line
400 +second body line
401 +'
402 +
403 test_done