Skip to content

Commit 250bea0

Browse files
wandersgitster
authored andcommitted
pretty: allow showing specific trailers
Adds a new "key=X" option to "%(trailers)" which will cause it to only print trailer lines which match any of the specified keys. Signed-off-by: Anders Waldenborg <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 3e3f347 commit 250bea0

File tree

5 files changed

+107
-6
lines changed

5 files changed

+107
-6
lines changed

Documentation/pretty-formats.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,14 @@ endif::git-rev-list[]
225225
linkgit:git-interpret-trailers[1]. The
226226
`trailers` string may be followed by a colon
227227
and zero or more comma-separated options:
228+
** 'key=<K>': only show trailers with specified key. Matching is done
229+
case-insensitively and trailing colon is optional. If option is
230+
given multiple times trailer lines matching any of the keys are
231+
shown. This option automatically enables the `only` option so that
232+
non-trailer lines in the trailer block are hidden. If that is not
233+
desired it can be disabled with `only=false`. E.g.,
234+
`%(trailers:key=Reviewed-by)` shows trailer lines with key
235+
`Reviewed-by`.
228236
** 'only[=val]': select whether non-trailer lines from the trailer
229237
block should be included. The `only` keyword may optionally be
230238
followed by an equal sign and one of `true`, `on`, `yes` to omit or

pretty.c

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1115,6 +1115,19 @@ static int match_placeholder_bool_arg(const char *to_parse, const char *candidat
11151115
return 1;
11161116
}
11171117

1118+
static int format_trailer_match_cb(const struct strbuf *key, void *ud)
1119+
{
1120+
const struct string_list *list = ud;
1121+
const struct string_list_item *item;
1122+
1123+
for_each_string_list_item (item, list) {
1124+
if (key->len == (uintptr_t)item->util &&
1125+
!strncasecmp(item->string, key->buf, key->len))
1126+
return 1;
1127+
}
1128+
return 0;
1129+
}
1130+
11181131
static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
11191132
const char *placeholder,
11201133
void *context)
@@ -1353,22 +1366,41 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
13531366

13541367
if (skip_prefix(placeholder, "(trailers", &arg)) {
13551368
struct process_trailer_options opts = PROCESS_TRAILER_OPTIONS_INIT;
1369+
struct string_list filter_list = STRING_LIST_INIT_NODUP;
13561370
size_t ret = 0;
13571371

13581372
opts.no_divider = 1;
13591373

13601374
if (*arg == ':') {
13611375
arg++;
13621376
for (;;) {
1363-
if (!match_placeholder_bool_arg(arg, "only", &arg, &opts.only_trailers) &&
1364-
!match_placeholder_bool_arg(arg, "unfold", &arg, &opts.unfold))
1377+
const char *argval;
1378+
size_t arglen;
1379+
1380+
if (match_placeholder_arg_value(arg, "key", &arg, &argval, &arglen)) {
1381+
uintptr_t len = arglen;
1382+
1383+
if (!argval)
1384+
goto trailer_out;
1385+
1386+
if (len && argval[len - 1] == ':')
1387+
len--;
1388+
string_list_append(&filter_list, argval)->util = (char *)len;
1389+
1390+
opts.filter = format_trailer_match_cb;
1391+
opts.filter_data = &filter_list;
1392+
opts.only_trailers = 1;
1393+
} else if (!match_placeholder_bool_arg(arg, "only", &arg, &opts.only_trailers) &&
1394+
!match_placeholder_bool_arg(arg, "unfold", &arg, &opts.unfold))
13651395
break;
13661396
}
13671397
}
13681398
if (*arg == ')') {
13691399
format_trailers_from_commit(sb, msg + c->subject_off, &opts);
13701400
ret = arg - placeholder + 1;
13711401
}
1402+
trailer_out:
1403+
string_list_clear(&filter_list, 0);
13721404
return ret;
13731405
}
13741406

t/t4205-log-pretty-formats.sh

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,63 @@ test_expect_success ':only and :unfold work together' '
616616
test_cmp expect actual
617617
'
618618

619+
test_expect_success 'pretty format %(trailers:key=foo) shows that trailer' '
620+
git log --no-walk --pretty="format:%(trailers:key=Acked-by)" >actual &&
621+
echo "Acked-by: A U Thor <[email protected]>" >expect &&
622+
test_cmp expect actual
623+
'
624+
625+
test_expect_success 'pretty format %(trailers:key=foo) is case insensitive' '
626+
git log --no-walk --pretty="format:%(trailers:key=AcKed-bY)" >actual &&
627+
echo "Acked-by: A U Thor <[email protected]>" >expect &&
628+
test_cmp expect actual
629+
'
630+
631+
test_expect_success 'pretty format %(trailers:key=foo:) trailing colon also works' '
632+
git log --no-walk --pretty="format:%(trailers:key=Acked-by:)" >actual &&
633+
echo "Acked-by: A U Thor <[email protected]>" >expect &&
634+
test_cmp expect actual
635+
'
636+
637+
test_expect_success 'pretty format %(trailers:key=foo) multiple keys' '
638+
git log --no-walk --pretty="format:%(trailers:key=Acked-by:,key=Signed-off-By)" >actual &&
639+
grep -v patch.description <trailers >expect &&
640+
test_cmp expect actual
641+
'
642+
643+
test_expect_success '%(trailers:key=nonexistant) becomes empty' '
644+
git log --no-walk --pretty="x%(trailers:key=Nacked-by)x" >actual &&
645+
echo "xx" >expect &&
646+
test_cmp expect actual
647+
'
648+
649+
test_expect_success '%(trailers:key=foo) handles multiple lines even if folded' '
650+
git log --no-walk --pretty="format:%(trailers:key=Signed-Off-by)" >actual &&
651+
grep -v patch.description <trailers | grep -v Acked-by >expect &&
652+
test_cmp expect actual
653+
'
654+
655+
test_expect_success '%(trailers:key=foo,unfold) properly unfolds' '
656+
git log --no-walk --pretty="format:%(trailers:key=Signed-Off-by,unfold)" >actual &&
657+
unfold <trailers | grep Signed-off-by >expect &&
658+
test_cmp expect actual
659+
'
660+
661+
test_expect_success 'pretty format %(trailers:key=foo,only=no) also includes nontrailer lines' '
662+
git log --no-walk --pretty="format:%(trailers:key=Acked-by,only=no)" >actual &&
663+
{
664+
echo "Acked-by: A U Thor <[email protected]>" &&
665+
grep patch.description <trailers
666+
} >expect &&
667+
test_cmp expect actual
668+
'
669+
670+
test_expect_success '%(trailers:key) without value is error' '
671+
git log --no-walk --pretty="tformat:%(trailers:key)" >actual &&
672+
echo "%(trailers:key)" >expect &&
673+
test_cmp expect actual
674+
'
675+
619676
test_expect_success 'trailer parsing not fooled by --- line' '
620677
git commit --allow-empty -F - <<-\EOF &&
621678
this is the subject

trailer.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1132,7 +1132,7 @@ static void format_trailer_info(struct strbuf *out,
11321132
size_t i;
11331133

11341134
/* If we want the whole block untouched, we can take the fast path. */
1135-
if (!opts->only_trailers && !opts->unfold) {
1135+
if (!opts->only_trailers && !opts->unfold && !opts->filter) {
11361136
strbuf_add(out, info->trailer_start,
11371137
info->trailer_end - info->trailer_start);
11381138
return;
@@ -1147,10 +1147,12 @@ static void format_trailer_info(struct strbuf *out,
11471147
struct strbuf val = STRBUF_INIT;
11481148

11491149
parse_trailer(&tok, &val, NULL, trailer, separator_pos);
1150-
if (opts->unfold)
1151-
unfold_value(&val);
1150+
if (!opts->filter || opts->filter(&tok, opts->filter_data)) {
1151+
if (opts->unfold)
1152+
unfold_value(&val);
11521153

1153-
strbuf_addf(out, "%s: %s\n", tok.buf, val.buf);
1154+
strbuf_addf(out, "%s: %s\n", tok.buf, val.buf);
1155+
}
11541156
strbuf_release(&tok);
11551157
strbuf_release(&val);
11561158

trailer.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ struct process_trailer_options {
7272
int only_input;
7373
int unfold;
7474
int no_divider;
75+
int (*filter)(const struct strbuf *, void *);
76+
void *filter_data;
7577
};
7678

7779
#define PROCESS_TRAILER_OPTIONS_INIT {0}

0 commit comments

Comments
 (0)