This lists refs similarly to the %D decoration format, but separates the refs with spaces only and omits "tag:" annotations. It's intended primarily for color output, where tags are already distinguished by color. Refactor format_decorations() to take an enum decoration_format argument that determines the prefix, separator and suffix as well as the tag annotation. For %d and %D, wrap the "tag:" annotation and the actual tag in separate color controls, because otherwise the tag ends up uncolored when %w width formatting breaks a line between the annotation and tag. Amend t4207-log-decoration-colors.sh to reflect the added color controls, and t4202-log.sh to test the %r format. Signed-off-by: Andy Koppe <andy.koppe@xxxxxxxxx> --- CI: https://github.com/ak2/git/actions/runs/5535093717 All passed apart from unrelated errors for MacOS. Documentation/pretty-formats.txt | 3 +- log-tree.c | 53 ++++++++++++++++++++++---------- log-tree.h | 15 ++++----- pretty.c | 7 +++-- t/t4202-log.sh | 7 ++++- t/t4207-log-decoration-colors.sh | 32 +++++++++++-------- 6 files changed, 76 insertions(+), 41 deletions(-) diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt index 3b71334459..d2ae898c79 100644 --- a/Documentation/pretty-formats.txt +++ b/Documentation/pretty-formats.txt @@ -221,7 +221,8 @@ The placeholders are: '%ch':: committer date, human style (like the `--date=human` option of linkgit:git-rev-list[1]) '%d':: ref names, like the --decorate option of linkgit:git-log[1] -'%D':: ref names without the " (", ")" wrapping. +'%D':: ref names without the " (", ")" wrapping +'%r':: ref names only, separated by spaces '%(describe[:options])':: human-readable name, like linkgit:git-describe[1]; empty string for undescribable commits. The `describe` string diff --git a/log-tree.c b/log-tree.c index f4b22a60cc..33dcb31858 100644 --- a/log-tree.c +++ b/log-tree.c @@ -301,14 +301,12 @@ static void show_name(struct strbuf *sb, const struct name_decoration *decoratio /* * The caller makes sure there is no funny color before calling. - * format_decorations_extended makes sure the same after return. + * format_decorations makes sure the same after return. */ -void format_decorations_extended(struct strbuf *sb, +void format_decorations(struct strbuf *sb, const struct commit *commit, int use_color, - const char *prefix, - const char *separator, - const char *suffix) + enum decoration_format format) { const struct name_decoration *decoration; const struct name_decoration *current_and_HEAD; @@ -316,11 +314,18 @@ void format_decorations_extended(struct strbuf *sb, diff_get_color(use_color, DIFF_COMMIT); const char *color_reset = decorate_get_color(use_color, DECORATION_NONE); + int first = 1; decoration = get_name_decoration(&commit->object); if (!decoration) return; + if (format == DECO_FMT_WRAPPED) { + strbuf_addstr(sb, color_commit); + strbuf_addstr(sb, " ("); + strbuf_addstr(sb, color_reset); + } + current_and_HEAD = current_pointed_by_HEAD(decoration); while (decoration) { /* @@ -329,13 +334,26 @@ void format_decorations_extended(struct strbuf *sb, * appeared, skipping the entry for current. */ if (decoration != current_and_HEAD) { - strbuf_addstr(sb, color_commit); - strbuf_addstr(sb, prefix); - strbuf_addstr(sb, color_reset); - strbuf_addstr(sb, decorate_get_color(use_color, decoration->type)); - if (decoration->type == DECORATION_REF_TAG) - strbuf_addstr(sb, "tag: "); + const char *color = decorate_get_color(use_color, decoration->type); + if (!first) { + if (format == DECO_FMT_BARE) + strbuf_addstr(sb, " "); + else { + strbuf_addstr(sb, color_commit); + strbuf_addstr(sb, ", "); + strbuf_addstr(sb, color_reset); + } + } + first = 0; + + if (format != DECO_FMT_BARE && + decoration->type == DECORATION_REF_TAG) { + strbuf_addstr(sb, color); + strbuf_addstr(sb, "tag: "); + strbuf_addstr(sb, color_reset); + } + strbuf_addstr(sb, color); show_name(sb, decoration); if (current_and_HEAD && @@ -346,14 +364,15 @@ void format_decorations_extended(struct strbuf *sb, show_name(sb, current_and_HEAD); } strbuf_addstr(sb, color_reset); - - prefix = separator; } decoration = decoration->next; } - strbuf_addstr(sb, color_commit); - strbuf_addstr(sb, suffix); - strbuf_addstr(sb, color_reset); + + if (format == DECO_FMT_WRAPPED) { + strbuf_addstr(sb, color_commit); + strbuf_addstr(sb, ")"); + strbuf_addstr(sb, color_reset); + } } void show_decorations(struct rev_info *opt, struct commit *commit) @@ -368,7 +387,7 @@ void show_decorations(struct rev_info *opt, struct commit *commit) } if (!opt->show_decorations) return; - format_decorations(&sb, commit, opt->diffopt.use_color); + format_decorations(&sb, commit, opt->diffopt.use_color, DECO_FMT_WRAPPED); fputs(sb.buf, opt->diffopt.file); strbuf_release(&sb); } diff --git a/log-tree.h b/log-tree.h index e7e4641cf8..345d1e80dc 100644 --- a/log-tree.h +++ b/log-tree.h @@ -13,17 +13,18 @@ struct decoration_filter { struct string_list *exclude_ref_config_pattern; }; +enum decoration_format { + DECO_FMT_BARE = 0, + DECO_FMT_UNWRAPPED, + DECO_FMT_WRAPPED, +}; + int parse_decorate_color_config(const char *var, const char *slot_name, const char *value); int log_tree_diff_flush(struct rev_info *); int log_tree_commit(struct rev_info *, struct commit *); void show_log(struct rev_info *opt); -void format_decorations_extended(struct strbuf *sb, const struct commit *commit, - int use_color, - const char *prefix, - const char *separator, - const char *suffix); -#define format_decorations(strbuf, commit, color) \ - format_decorations_extended((strbuf), (commit), (color), " (", ", ", ")") +void format_decorations(struct strbuf *sb, const struct commit *commit, + int use_color, enum decoration_format format); void show_decorations(struct rev_info *opt, struct commit *commit); void log_write_email_headers(struct rev_info *opt, struct commit *commit, const char **extra_headers_p, diff --git a/pretty.c b/pretty.c index 0bb938021b..88b041df85 100644 --- a/pretty.c +++ b/pretty.c @@ -1526,10 +1526,13 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */ strbuf_addstr(sb, get_revision_mark(NULL, commit)); return 1; case 'd': - format_decorations(sb, commit, c->auto_color); + format_decorations(sb, commit, c->auto_color, DECO_FMT_WRAPPED); return 1; case 'D': - format_decorations_extended(sb, commit, c->auto_color, "", ", ", ""); + format_decorations(sb, commit, c->auto_color, DECO_FMT_UNWRAPPED); + return 1; + case 'r': + format_decorations(sb, commit, c->auto_color, DECO_FMT_BARE); return 1; case 'S': /* tag/branch like --source */ if (!(c->pretty_ctx->rev && c->pretty_ctx->rev->sources)) diff --git a/t/t4202-log.sh b/t/t4202-log.sh index ae73aef922..9e0871df24 100755 --- a/t/t4202-log.sh +++ b/t/t4202-log.sh @@ -2325,7 +2325,12 @@ test_expect_success 'log --decorate includes all levels of tag annotated tags' ' HEAD -> branch, tag: lightweight, tag: double-1, tag: double-0, tag: annotated EOF git log -1 --format="%D" >actual && - test_cmp expect actual + test_cmp expect actual && + cat >expect2 <<-\EOF && + HEAD -> branch lightweight double-1 double-0 annotated + EOF + git log -1 --format="%r" >actual2 && + test_cmp expect2 actual2 ' test_expect_success 'log --decorate does not include things outside filter' ' diff --git a/t/t4207-log-decoration-colors.sh b/t/t4207-log-decoration-colors.sh index ded33a82e2..3a4eedc494 100755 --- a/t/t4207-log-decoration-colors.sh +++ b/t/t4207-log-decoration-colors.sh @@ -55,13 +55,15 @@ test_expect_success 'commit decorations colored correctly' ' cat >expect <<-EOF && ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_HEAD}HEAD -> \ ${c_reset}${c_branch}main${c_reset}${c_commit}, \ -${c_reset}${c_tag}tag: v1.0${c_reset}${c_commit}, \ -${c_reset}${c_tag}tag: B${c_reset}${c_commit})${c_reset} B -${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_tag}tag: A1${c_reset}${c_commit}, \ +${c_reset}${c_tag}tag: ${c_reset}${c_tag}v1.0${c_reset}${c_commit}, \ +${c_reset}${c_tag}tag: ${c_reset}${c_tag}B${c_reset}${c_commit})${c_reset} B +${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\ +${c_tag}tag: ${c_reset}${c_tag}A1${c_reset}${c_commit}, \ ${c_reset}${c_remoteBranch}other/main${c_reset}${c_commit})${c_reset} A1 - ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_stash}refs/stash${c_reset}${c_commit})${c_reset} \ -On main: Changes to A.t - ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_tag}tag: A${c_reset}${c_commit})${c_reset} A + ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\ +${c_stash}refs/stash${c_reset}${c_commit})${c_reset} On main: Changes to A.t + ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\ +${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_commit})${c_reset} A EOF git log --first-parent --no-abbrev --decorate --oneline --color=always --all >actual && @@ -78,10 +80,12 @@ test_expect_success 'test coloring with replace-objects' ' cat >expect <<-EOF && ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_HEAD}HEAD -> \ ${c_reset}${c_branch}main${c_reset}${c_commit}, \ -${c_reset}${c_tag}tag: D${c_reset}${c_commit})${c_reset} D - ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_tag}tag: C${c_reset}${c_commit}, \ +${c_reset}${c_tag}tag: ${c_reset}${c_tag}D${c_reset}${c_commit})${c_reset} D + ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\ +${c_tag}tag: ${c_reset}${c_tag}C${c_reset}${c_commit}, \ ${c_reset}${c_grafted}replaced${c_reset}${c_commit})${c_reset} B - ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_tag}tag: A${c_reset}${c_commit})${c_reset} A + ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\ +${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_commit})${c_reset} A EOF git log --first-parent --no-abbrev --decorate --oneline --color=always HEAD >actual && @@ -102,11 +106,13 @@ test_expect_success 'test coloring with grafted commit' ' cat >expect <<-EOF && ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_HEAD}HEAD -> \ ${c_reset}${c_branch}main${c_reset}${c_commit}, \ -${c_reset}${c_tag}tag: D${c_reset}${c_commit}, \ +${c_reset}${c_tag}tag: ${c_reset}${c_tag}D${c_reset}${c_commit}, \ ${c_reset}${c_grafted}replaced${c_reset}${c_commit})${c_reset} D - ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_tag}tag: v1.0${c_reset}${c_commit}, \ -${c_reset}${c_tag}tag: B${c_reset}${c_commit})${c_reset} B - ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_tag}tag: A${c_reset}${c_commit})${c_reset} A + ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\ +${c_tag}tag: ${c_reset}${c_tag}v1.0${c_reset}${c_commit}, \ +${c_reset}${c_tag}tag: ${c_reset}${c_tag}B${c_reset}${c_commit})${c_reset} B + ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\ +${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_commit})${c_reset} A EOF git log --first-parent --no-abbrev --decorate --oneline --color=always HEAD >actual && -- 2.41.0