зеркало из https://github.com/microsoft/git.git
Merge branch 'ab/trailers-extra-format'
The "--format=%(trailers)" mechanism gets enhanced to make it easier to design output for machine consumption. * ab/trailers-extra-format: pretty format %(trailers): add a "key_value_separator" pretty format %(trailers): add a "keyonly" pretty-format %(trailers): fix broken standalone "valueonly" pretty format %(trailers) doc: avoid repetition pretty format %(trailers) test: split a long line
This commit is contained in:
Коммит
b62bbd3580
|
@ -252,7 +252,15 @@ endif::git-rev-list[]
|
|||
interpreted by
|
||||
linkgit:git-interpret-trailers[1]. The
|
||||
`trailers` string may be followed by a colon
|
||||
and zero or more comma-separated options:
|
||||
and zero or more comma-separated options.
|
||||
If any option is provided multiple times the
|
||||
last occurance wins.
|
||||
+
|
||||
The boolean options accept an optional value `[=<BOOL>]`. The values
|
||||
`true`, `false`, `on`, `off` etc. are all accepted. See the "boolean"
|
||||
sub-section in "EXAMPLES" in linkgit:git-config[1]. If a boolean
|
||||
option is given with no value, it's enabled.
|
||||
+
|
||||
** 'key=<K>': only show trailers with specified key. Matching is done
|
||||
case-insensitively and trailing colon is optional. If option is
|
||||
given multiple times trailer lines matching any of the keys are
|
||||
|
@ -261,27 +269,25 @@ endif::git-rev-list[]
|
|||
desired it can be disabled with `only=false`. E.g.,
|
||||
`%(trailers:key=Reviewed-by)` shows trailer lines with key
|
||||
`Reviewed-by`.
|
||||
** 'only[=val]': select whether non-trailer lines from the trailer
|
||||
block should be included. The `only` keyword may optionally be
|
||||
followed by an equal sign and one of `true`, `on`, `yes` to omit or
|
||||
`false`, `off`, `no` to show the non-trailer lines. If option is
|
||||
given without value it is enabled. If given multiple times the last
|
||||
value is used.
|
||||
** 'only[=<BOOL>]': select whether non-trailer lines from the trailer
|
||||
block should be included.
|
||||
** 'separator=<SEP>': specify a separator inserted between trailer
|
||||
lines. When this option is not given each trailer line is
|
||||
terminated with a line feed character. The string SEP may contain
|
||||
the literal formatting codes described above. To use comma as
|
||||
separator one must use `%x2C` as it would otherwise be parsed as
|
||||
next option. If separator option is given multiple times only the
|
||||
last one is used. E.g., `%(trailers:key=Ticket,separator=%x2C )`
|
||||
next option. E.g., `%(trailers:key=Ticket,separator=%x2C )`
|
||||
shows all trailer lines whose key is "Ticket" separated by a comma
|
||||
and a space.
|
||||
** 'unfold[=val]': make it behave as if interpret-trailer's `--unfold`
|
||||
option was given. In same way as to for `only` it can be followed
|
||||
by an equal sign and explicit value. E.g.,
|
||||
** 'unfold[=<BOOL>]': make it behave as if interpret-trailer's `--unfold`
|
||||
option was given. E.g.,
|
||||
`%(trailers:only,unfold=true)` unfolds and shows all trailer lines.
|
||||
** 'valueonly[=val]': skip over the key part of the trailer line and only
|
||||
show the value part. Also this optionally allows explicit value.
|
||||
** 'keyonly[=<BOOL>]': only show the key part of the trailer.
|
||||
** 'valueonly[=<BOOL>]': only show the value part of the trailer.
|
||||
** 'key_value_separator=<SEP>': specify a separator inserted between
|
||||
trailer lines. When this option is not given each trailer key-value
|
||||
pair is separated by ": ". Otherwise it shares the same semantics
|
||||
as 'separator=<SEP>' above.
|
||||
|
||||
NOTE: Some placeholders may depend on other options given to the
|
||||
revision traversal engine. For example, the `%g*` reflog options will
|
||||
|
|
10
pretty.c
10
pretty.c
|
@ -1418,6 +1418,7 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
|
|||
struct process_trailer_options opts = PROCESS_TRAILER_OPTIONS_INIT;
|
||||
struct string_list filter_list = STRING_LIST_INIT_NODUP;
|
||||
struct strbuf sepbuf = STRBUF_INIT;
|
||||
struct strbuf kvsepbuf = STRBUF_INIT;
|
||||
size_t ret = 0;
|
||||
|
||||
opts.no_divider = 1;
|
||||
|
@ -1449,8 +1450,17 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
|
|||
strbuf_expand(&sepbuf, fmt, strbuf_expand_literal_cb, NULL);
|
||||
free(fmt);
|
||||
opts.separator = &sepbuf;
|
||||
} else if (match_placeholder_arg_value(arg, "key_value_separator", &arg, &argval, &arglen)) {
|
||||
char *fmt;
|
||||
|
||||
strbuf_reset(&kvsepbuf);
|
||||
fmt = xstrndup(argval, arglen);
|
||||
strbuf_expand(&kvsepbuf, fmt, strbuf_expand_literal_cb, NULL);
|
||||
free(fmt);
|
||||
opts.key_value_separator = &kvsepbuf;
|
||||
} else if (!match_placeholder_bool_arg(arg, "only", &arg, &opts.only_trailers) &&
|
||||
!match_placeholder_bool_arg(arg, "unfold", &arg, &opts.unfold) &&
|
||||
!match_placeholder_bool_arg(arg, "keyonly", &arg, &opts.key_only) &&
|
||||
!match_placeholder_bool_arg(arg, "valueonly", &arg, &opts.value_only))
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -605,6 +605,12 @@ test_expect_success 'pretty format %(trailers) shows trailers' '
|
|||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'pretty format %(trailers:) enables no options' '
|
||||
git log --no-walk --pretty="%(trailers:)" >actual &&
|
||||
# "expect" the same as the test above
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success '%(trailers:only) shows only "key: value" trailers' '
|
||||
git log --no-walk --pretty="%(trailers:only)" >actual &&
|
||||
{
|
||||
|
@ -709,19 +715,101 @@ test_expect_success '%(trailers:key) without value is error' '
|
|||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success '%(trailers:keyonly) shows only keys' '
|
||||
git log --no-walk --pretty="format:%(trailers:keyonly)" >actual &&
|
||||
test_write_lines \
|
||||
"Signed-off-by" \
|
||||
"Acked-by" \
|
||||
"[ v2 updated patch description ]" \
|
||||
"Signed-off-by" >expect &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success '%(trailers:key=foo,keyonly) shows only key' '
|
||||
git log --no-walk --pretty="format:%(trailers:key=Acked-by,keyonly)" >actual &&
|
||||
echo "Acked-by" >expect &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success '%(trailers:key=foo,valueonly) shows only value' '
|
||||
git log --no-walk --pretty="format:%(trailers:key=Acked-by,valueonly)" >actual &&
|
||||
echo "A U Thor <author@example.com>" >expect &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'pretty format %(trailers:separator) changes separator' '
|
||||
git log --no-walk --pretty=format:"X%(trailers:separator=%x00,unfold)X" >actual &&
|
||||
printf "XSigned-off-by: A U Thor <author@example.com>\0Acked-by: A U Thor <author@example.com>\0[ v2 updated patch description ]\0Signed-off-by: A U Thor <author@example.com>X" >expect &&
|
||||
test_expect_success '%(trailers:valueonly) shows only values' '
|
||||
git log --no-walk --pretty="format:%(trailers:valueonly)" >actual &&
|
||||
test_write_lines \
|
||||
"A U Thor <author@example.com>" \
|
||||
"A U Thor <author@example.com>" \
|
||||
"[ v2 updated patch description ]" \
|
||||
"A U Thor" \
|
||||
" <author@example.com>" >expect &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'pretty format %(trailers) combining separator/key/valueonly' '
|
||||
test_expect_success '%(trailers:key=foo,keyonly,valueonly) shows nothing' '
|
||||
git log --no-walk --pretty="format:%(trailers:key=Acked-by,keyonly,valueonly)" >actual &&
|
||||
echo >expect &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'pretty format %(trailers:separator) changes separator' '
|
||||
git log --no-walk --pretty=format:"X%(trailers:separator=%x00)X" >actual &&
|
||||
(
|
||||
printf "XSigned-off-by: A U Thor <author@example.com>\0" &&
|
||||
printf "Acked-by: A U Thor <author@example.com>\0" &&
|
||||
printf "[ v2 updated patch description ]\0" &&
|
||||
printf "Signed-off-by: A U Thor\n <author@example.com>X"
|
||||
) >expect &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'pretty format %(trailers:separator=X,unfold) changes separator' '
|
||||
git log --no-walk --pretty=format:"X%(trailers:separator=%x00,unfold)X" >actual &&
|
||||
(
|
||||
printf "XSigned-off-by: A U Thor <author@example.com>\0" &&
|
||||
printf "Acked-by: A U Thor <author@example.com>\0" &&
|
||||
printf "[ v2 updated patch description ]\0" &&
|
||||
printf "Signed-off-by: A U Thor <author@example.com>X"
|
||||
) >expect &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'pretty format %(trailers:key_value_separator) changes key-value separator' '
|
||||
git log --no-walk --pretty=format:"X%(trailers:key_value_separator=%x00)X" >actual &&
|
||||
(
|
||||
printf "XSigned-off-by\0A U Thor <author@example.com>\n" &&
|
||||
printf "Acked-by\0A U Thor <author@example.com>\n" &&
|
||||
printf "[ v2 updated patch description ]\n" &&
|
||||
printf "Signed-off-by\0A U Thor\n <author@example.com>\nX"
|
||||
) >expect &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'pretty format %(trailers:key_value_separator,unfold) changes key-value separator' '
|
||||
git log --no-walk --pretty=format:"X%(trailers:key_value_separator=%x00,unfold)X" >actual &&
|
||||
(
|
||||
printf "XSigned-off-by\0A U Thor <author@example.com>\n" &&
|
||||
printf "Acked-by\0A U Thor <author@example.com>\n" &&
|
||||
printf "[ v2 updated patch description ]\n" &&
|
||||
printf "Signed-off-by\0A U Thor <author@example.com>\nX"
|
||||
) >expect &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'pretty format %(trailers:separator,key_value_separator) changes both separators' '
|
||||
git log --no-walk --pretty=format:"%(trailers:separator=%x00,key_value_separator=%x00%x00,unfold)" >actual &&
|
||||
(
|
||||
printf "Signed-off-by\0\0A U Thor <author@example.com>\0" &&
|
||||
printf "Acked-by\0\0A U Thor <author@example.com>\0" &&
|
||||
printf "[ v2 updated patch description ]\0" &&
|
||||
printf "Signed-off-by\0\0A U Thor <author@example.com>"
|
||||
) >expect &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'pretty format %(trailers) combining separator/key/keyonly/valueonly' '
|
||||
git commit --allow-empty -F - <<-\EOF &&
|
||||
Important fix
|
||||
|
||||
|
@ -748,6 +836,13 @@ test_expect_success 'pretty format %(trailers) combining separator/key/valueonly
|
|||
"Does not close any tickets" \
|
||||
"Another fix #567, #890" \
|
||||
"Important fix #1234" >expect &&
|
||||
test_cmp expect actual &&
|
||||
|
||||
git log --pretty="%s% (trailers:separator=%x2c%x20,key=Closes,keyonly)" HEAD~3.. >actual &&
|
||||
test_write_lines \
|
||||
"Does not close any tickets" \
|
||||
"Another fix Closes, Closes" \
|
||||
"Important fix Closes" >expect &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
|
|
15
trailer.c
15
trailer.c
|
@ -1131,7 +1131,9 @@ static void format_trailer_info(struct strbuf *out,
|
|||
size_t i;
|
||||
|
||||
/* If we want the whole block untouched, we can take the fast path. */
|
||||
if (!opts->only_trailers && !opts->unfold && !opts->filter && !opts->separator) {
|
||||
if (!opts->only_trailers && !opts->unfold && !opts->filter &&
|
||||
!opts->separator && !opts->key_only && !opts->value_only &&
|
||||
!opts->key_value_separator) {
|
||||
strbuf_add(out, info->trailer_start,
|
||||
info->trailer_end - info->trailer_start);
|
||||
return;
|
||||
|
@ -1153,8 +1155,15 @@ static void format_trailer_info(struct strbuf *out,
|
|||
if (opts->separator && out->len != origlen)
|
||||
strbuf_addbuf(out, opts->separator);
|
||||
if (!opts->value_only)
|
||||
strbuf_addf(out, "%s: ", tok.buf);
|
||||
strbuf_addbuf(out, &val);
|
||||
strbuf_addbuf(out, &tok);
|
||||
if (!opts->key_only && !opts->value_only) {
|
||||
if (opts->key_value_separator)
|
||||
strbuf_addbuf(out, opts->key_value_separator);
|
||||
else
|
||||
strbuf_addstr(out, ": ");
|
||||
}
|
||||
if (!opts->key_only)
|
||||
strbuf_addbuf(out, &val);
|
||||
if (!opts->separator)
|
||||
strbuf_addch(out, '\n');
|
||||
}
|
||||
|
|
|
@ -71,8 +71,10 @@ struct process_trailer_options {
|
|||
int only_input;
|
||||
int unfold;
|
||||
int no_divider;
|
||||
int key_only;
|
||||
int value_only;
|
||||
const struct strbuf *separator;
|
||||
const struct strbuf *key_value_separator;
|
||||
int (*filter)(const struct strbuf *, void *);
|
||||
void *filter_data;
|
||||
};
|
||||
|
|
Загрузка…
Ссылка в новой задаче