Allow restricting the tags used by the placeholder %(describe) with the options match and exclude. E.g. the following command describes the current commit using official version tags, without those for release candidates: $ git log -1 --format='%(describe:match=v[0-9]*,exclude=*rc*)' Signed-off-by: René Scharfe <l.s.r@xxxxxx> --- Documentation/pretty-formats.txt | 13 ++++++++-- pretty.c | 43 ++++++++++++++++++++++++++++++-- t/t4205-log-pretty-formats.sh | 16 ++++++++++++ 3 files changed, 68 insertions(+), 4 deletions(-) diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt index bb8c05bc21..231010e6ef 100644 --- a/Documentation/pretty-formats.txt +++ b/Documentation/pretty-formats.txt @@ -208,8 +208,17 @@ The placeholders are: '%cs':: committer date, short format (`YYYY-MM-DD`) '%d':: ref names, like the --decorate option of linkgit:git-log[1] '%D':: ref names without the " (", ")" wrapping. -'%(describe)':: human-readable name, like linkgit:git-describe[1]; - empty string for undescribable commits +'%(describe[:options])':: human-readable name, like + linkgit:git-describe[1]; empty string for + undescribable commits. The `describe` string + may be followed by a colon and zero or more + comma-separated options. ++ +** 'match=<pattern>': Only consider tags matching the given + `glob(7)` pattern, excluding the "refs/tags/" prefix. +** 'exclude=<pattern>': Do not consider tags matching the given + `glob(7)` pattern, excluding the "refs/tags/" prefix. + '%S':: ref name given on the command line by which the commit was reached (like `git log --source`), only works with `git log` '%e':: encoding diff --git a/pretty.c b/pretty.c index a0c427fb61..c612d2ac9b 100644 --- a/pretty.c +++ b/pretty.c @@ -1150,6 +1150,34 @@ static int format_trailer_match_cb(const struct strbuf *key, void *ud) return 0; } +static size_t parse_describe_args(const char *start, struct strvec *args) +{ + const char *options[] = { "match", "exclude" }; + const char *arg = start; + + for (;;) { + const char *matched = NULL; + const char *argval; + size_t arglen = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(options); i++) { + if (match_placeholder_arg_value(arg, options[i], &arg, + &argval, &arglen)) { + matched = options[i]; + break; + } + } + if (!matched) + break; + + if (!arglen) + return 0; + strvec_pushf(args, "--%s=%.*s", matched, (int)arglen, argval); + } + return arg - start; +} + static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */ const char *placeholder, void *context) @@ -1215,20 +1243,31 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */ return parse_padding_placeholder(placeholder, c); } - if (skip_prefix(placeholder, "(describe)", &arg)) { + if (skip_prefix(placeholder, "(describe", &arg)) { struct child_process cmd = CHILD_PROCESS_INIT; struct strbuf out = STRBUF_INIT; struct strbuf err = STRBUF_INIT; cmd.git_cmd = 1; strvec_push(&cmd.args, "describe"); + + if (*arg == ':') { + arg++; + arg += parse_describe_args(arg, &cmd.args); + } + + if (*arg != ')') { + child_process_clear(&cmd); + return 0; + } + strvec_push(&cmd.args, oid_to_hex(&commit->object.oid)); pipe_command(&cmd, NULL, 0, &out, 0, &err, 0); strbuf_rtrim(&out); strbuf_addbuf(sb, &out); strbuf_release(&out); strbuf_release(&err); - return arg - placeholder; + return arg - placeholder + 1; } /* these depend on the commit */ diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh index 5a44fa447d..7e36706212 100755 --- a/t/t4205-log-pretty-formats.sh +++ b/t/t4205-log-pretty-formats.sh @@ -972,4 +972,20 @@ test_expect_success '%(describe) vs git describe' ' test_must_be_empty err ' +test_expect_success '%(describe:match=...) vs git describe --match ...' ' + test_when_finished "git tag -d tag-match" && + git tag -a -m tagged tag-match&& + git describe --match "*-match" >expect && + git log -1 --format="%(describe:match=*-match)" >actual && + test_cmp expect actual +' + +test_expect_success '%(describe:exclude=...) vs git describe --exclude ...' ' + test_when_finished "git tag -d tag-exclude" && + git tag -a -m tagged tag-exclude && + git describe --exclude "*-exclude" >expect && + git log -1 --format="%(describe:exclude=*-exclude)" >actual && + test_cmp expect actual +' + test_done -- 2.30.1