{"thread":{"id":"60303","subject":"[PATCH] decorate: add color.decorate.symbols config option","startedAt":"2023-10-03T20:55:48Z","lastAt":"2024-02-07T22:03:02Z","messageCount":31,"participants":["Andy Koppe","Junio C Hamano","Kousik Sanagavarapu"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"482617","messageId":"20231003205442.22963-1-andy.koppe@gmail.com","threadId":"60303","inReplyTo":null,"subject":"[PATCH] decorate: add color.decorate.symbols config option","fromName":"Andy Koppe","fromEmail":"andy.koppe@gmail.com","sentAt":"2023-10-03T20:54:42Z","receivedAt":"2023-10-03T20:55:48Z","isPatch":true,"sender":{"key":"andy.koppe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/223411?v=4"},"body":"Add new 'color.decorate.symbols' config option for determining the color\nof the prefix, suffix, separator and arrow symbols used in --decorate\noutput and related log format placeholders, to allow them to be colored\ndifferently from commit hashes.\n\nFor backward compatibility, fall back to the commit hash color that can\nbe specified with the 'color.diff.commit' option if the new option is\nnot provided.\n\nAdd the setting to the color.decorate.<slot> documentation, rewording\nthat a bit to try to improve readability.\n\nAmend t4207-log-decoration-colors.sh to test the option.\n\nSigned-off-by: Andy Koppe <andy.koppe@gmail.com>\n---\n Documentation/config/color.txt   |  7 ++--\n commit.h                         |  1 +\n log-tree.c                       | 15 ++++++---\n t/t4207-log-decoration-colors.sh | 58 +++++++++++++++++---------------\n 4 files changed, 45 insertions(+), 36 deletions(-)\n\ndiff --git a/Documentation/config/color.txt b/Documentation/config/color.txt\nindex 1795b2d16b..5d3612ff09 100644\n--- a/Documentation/config/color.txt\n+++ b/Documentation/config/color.txt\n@@ -75,9 +75,10 @@ color.diff.<slot>::\n \n color.decorate.<slot>::\n \tUse customized color for 'git log --decorate' output.  `<slot>` is one\n-\tof `branch`, `remoteBranch`, `tag`, `stash` or `HEAD` for local\n-\tbranches, remote-tracking branches, tags, stash and HEAD, respectively\n-\tand `grafted` for grafted commits.\n+\tof `HEAD` for the current HEAD ref, `branch` for local branches,\n+\t`remoteBranch` for remote-tracking branches, `tag` for tags, `stash`\n+\tfor the top stash entry, `grafted` for grafted commits, and `symbols`\n+\tfor the punctuation surrounding the other elements.\n \n color.grep::\n \tWhen set to `always`, always highlight matches.  When `false` (or\ndiff --git a/commit.h b/commit.h\nindex 28928833c5..cefcb7c490 100644\n--- a/commit.h\n+++ b/commit.h\n@@ -56,6 +56,7 @@ enum decoration_type {\n \tDECORATION_REF_STASH,\n \tDECORATION_REF_HEAD,\n \tDECORATION_GRAFTED,\n+\tDECORATION_SYMBOLS,\n };\n \n void add_name_decoration(enum decoration_type type, const char *name, struct object *obj);\ndiff --git a/log-tree.c b/log-tree.c\nindex 504da6b519..a5dd4292fc 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -41,6 +41,7 @@ static char decoration_colors[][COLOR_MAXLEN] = {\n \tGIT_COLOR_BOLD_MAGENTA,\t/* REF_STASH */\n \tGIT_COLOR_BOLD_CYAN,\t/* REF_HEAD */\n \tGIT_COLOR_BOLD_BLUE,\t/* GRAFTED */\n+\tGIT_COLOR_NIL,\t\t/* SYMBOLS */\n };\n \n static const char *color_decorate_slots[] = {\n@@ -50,6 +51,7 @@ static const char *color_decorate_slots[] = {\n \t[DECORATION_REF_STASH]\t= \"stash\",\n \t[DECORATION_REF_HEAD]\t= \"HEAD\",\n \t[DECORATION_GRAFTED]\t= \"grafted\",\n+\t[DECORATION_SYMBOLS]\t= \"symbols\",\n };\n \n static const char *decorate_get_color(int decorate_use_color, enum decoration_type ix)\n@@ -312,7 +314,7 @@ void format_decorations(struct strbuf *sb,\n {\n \tconst struct name_decoration *decoration;\n \tconst struct name_decoration *current_and_HEAD;\n-\tconst char *color_commit, *color_reset;\n+\tconst char *color_symbols, *color_reset;\n \n \tconst char *prefix = \" (\";\n \tconst char *suffix = \")\";\n@@ -337,7 +339,10 @@ void format_decorations(struct strbuf *sb,\n \t\t\ttag = opts->tag;\n \t}\n \n-\tcolor_commit = diff_get_color(use_color, DIFF_COMMIT);\n+\tcolor_symbols = decorate_get_color(use_color, DECORATION_SYMBOLS);\n+\tif (color_is_nil(color_symbols))\n+\t\tcolor_symbols = diff_get_color(use_color, DIFF_COMMIT);\n+\n \tcolor_reset = decorate_get_color(use_color, DECORATION_NONE);\n \n \tcurrent_and_HEAD = current_pointed_by_HEAD(decoration);\n@@ -352,7 +357,7 @@ void format_decorations(struct strbuf *sb,\n \t\t\t\tdecorate_get_color(use_color, decoration->type);\n \n \t\t\tif (*prefix) {\n-\t\t\t\tstrbuf_addstr(sb, color_commit);\n+\t\t\t\tstrbuf_addstr(sb, color_symbols);\n \t\t\t\tstrbuf_addstr(sb, prefix);\n \t\t\t\tstrbuf_addstr(sb, color_reset);\n \t\t\t}\n@@ -369,7 +374,7 @@ void format_decorations(struct strbuf *sb,\n \n \t\t\tif (current_and_HEAD &&\n \t\t\t    decoration->type == DECORATION_REF_HEAD) {\n-\t\t\t\tstrbuf_addstr(sb, color_commit);\n+\t\t\t\tstrbuf_addstr(sb, color_symbols);\n \t\t\t\tstrbuf_addstr(sb, pointer);\n \t\t\t\tstrbuf_addstr(sb, color_reset);\n \t\t\t\tstrbuf_addstr(sb, decorate_get_color(use_color, current_and_HEAD->type));\n@@ -382,7 +387,7 @@ void format_decorations(struct strbuf *sb,\n \t\tdecoration = decoration->next;\n \t}\n \tif (*suffix) {\n-\t\tstrbuf_addstr(sb, color_commit);\n+\t\tstrbuf_addstr(sb, color_symbols);\n \t\tstrbuf_addstr(sb, suffix);\n \t\tstrbuf_addstr(sb, color_reset);\n \t}\ndiff --git a/t/t4207-log-decoration-colors.sh b/t/t4207-log-decoration-colors.sh\nindex 21986a866d..663ae49d34 100755\n--- a/t/t4207-log-decoration-colors.sh\n+++ b/t/t4207-log-decoration-colors.sh\n@@ -18,6 +18,7 @@ test_expect_success setup '\n \tgit config color.decorate.tag \"reverse bold yellow\" &&\n \tgit config color.decorate.stash magenta &&\n \tgit config color.decorate.grafted black &&\n+\tgit config color.decorate.symbols white &&\n \tgit config color.decorate.HEAD cyan &&\n \n \tc_reset=\"<RESET>\" &&\n@@ -29,6 +30,7 @@ test_expect_success setup '\n \tc_stash=\"<MAGENTA>\" &&\n \tc_HEAD=\"<CYAN>\" &&\n \tc_grafted=\"<BLACK>\" &&\n+\tc_symbols=\"<WHITE>\" &&\n \n \ttest_commit A &&\n \tgit clone . other &&\n@@ -53,17 +55,17 @@ cmp_filtered_decorations () {\n # to this test since it does not contain any decoration, hence --first-parent\n test_expect_success 'commit decorations colored correctly' '\n \tcat >expect <<-EOF &&\n-\t${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_HEAD}HEAD${c_reset}\\\n-${c_commit} -> ${c_reset}${c_branch}main${c_reset}${c_commit}, \\\n-${c_reset}${c_tag}tag: ${c_reset}${c_tag}v1.0${c_reset}${c_commit}, \\\n-${c_reset}${c_tag}tag: ${c_reset}${c_tag}B${c_reset}${c_commit})${c_reset} B\n-${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\\\n-${c_tag}tag: ${c_reset}${c_tag}A1${c_reset}${c_commit}, \\\n-${c_reset}${c_remoteBranch}other/main${c_reset}${c_commit})${c_reset} A1\n-\t${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\\\n-${c_stash}refs/stash${c_reset}${c_commit})${c_reset} On main: Changes to A.t\n-\t${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\\\n-${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_commit})${c_reset} A\n+\t${c_commit}COMMIT_ID${c_reset}${c_symbols} (${c_reset}${c_HEAD}HEAD${c_reset}\\\n+${c_symbols} -> ${c_reset}${c_branch}main${c_reset}${c_symbols}, \\\n+${c_reset}${c_tag}tag: ${c_reset}${c_tag}v1.0${c_reset}${c_symbols}, \\\n+${c_reset}${c_tag}tag: ${c_reset}${c_tag}B${c_reset}${c_symbols})${c_reset} B\n+${c_commit}COMMIT_ID${c_reset}${c_symbols} (${c_reset}\\\n+${c_tag}tag: ${c_reset}${c_tag}A1${c_reset}${c_symbols}, \\\n+${c_reset}${c_remoteBranch}other/main${c_reset}${c_symbols})${c_reset} A1\n+\t${c_commit}COMMIT_ID${c_reset}${c_symbols} (${c_reset}\\\n+${c_stash}refs/stash${c_reset}${c_symbols})${c_reset} On main: Changes to A.t\n+\t${c_commit}COMMIT_ID${c_reset}${c_symbols} (${c_reset}\\\n+${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_symbols})${c_reset} A\n \tEOF\n \n \tgit log --first-parent --no-abbrev --decorate --oneline --color=always --all >actual &&\n@@ -78,14 +80,14 @@ test_expect_success 'test coloring with replace-objects' '\n \tgit replace HEAD~1 HEAD~2 &&\n \n \tcat >expect <<-EOF &&\n-\t${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_HEAD}HEAD${c_reset}\\\n-${c_commit} -> ${c_reset}${c_branch}main${c_reset}${c_commit}, \\\n-${c_reset}${c_tag}tag: ${c_reset}${c_tag}D${c_reset}${c_commit})${c_reset} D\n-\t${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\\\n-${c_tag}tag: ${c_reset}${c_tag}C${c_reset}${c_commit}, \\\n-${c_reset}${c_grafted}replaced${c_reset}${c_commit})${c_reset} B\n-\t${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\\\n-${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_commit})${c_reset} A\n+\t${c_commit}COMMIT_ID${c_reset}${c_symbols} (${c_reset}${c_HEAD}HEAD${c_reset}\\\n+${c_symbols} -> ${c_reset}${c_branch}main${c_reset}${c_symbols}, \\\n+${c_reset}${c_tag}tag: ${c_reset}${c_tag}D${c_reset}${c_symbols})${c_reset} D\n+\t${c_commit}COMMIT_ID${c_reset}${c_symbols} (${c_reset}\\\n+${c_tag}tag: ${c_reset}${c_tag}C${c_reset}${c_symbols}, \\\n+${c_reset}${c_grafted}replaced${c_reset}${c_symbols})${c_reset} B\n+\t${c_commit}COMMIT_ID${c_reset}${c_symbols} (${c_reset}\\\n+${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_symbols})${c_reset} A\n EOF\n \n \tgit log --first-parent --no-abbrev --decorate --oneline --color=always HEAD >actual &&\n@@ -104,15 +106,15 @@ test_expect_success 'test coloring with grafted commit' '\n \tgit replace --graft HEAD HEAD~2 &&\n \n \tcat >expect <<-EOF &&\n-\t${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_HEAD}HEAD${c_reset}\\\n-${c_commit} -> ${c_reset}${c_branch}main${c_reset}${c_commit}, \\\n-${c_reset}${c_tag}tag: ${c_reset}${c_tag}D${c_reset}${c_commit}, \\\n-${c_reset}${c_grafted}replaced${c_reset}${c_commit})${c_reset} D\n-\t${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\\\n-${c_tag}tag: ${c_reset}${c_tag}v1.0${c_reset}${c_commit}, \\\n-${c_reset}${c_tag}tag: ${c_reset}${c_tag}B${c_reset}${c_commit})${c_reset} B\n-\t${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\\\n-${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_commit})${c_reset} A\n+\t${c_commit}COMMIT_ID${c_reset}${c_symbols} (${c_reset}${c_HEAD}HEAD${c_reset}\\\n+${c_symbols} -> ${c_reset}${c_branch}main${c_reset}${c_symbols}, \\\n+${c_reset}${c_tag}tag: ${c_reset}${c_tag}D${c_reset}${c_symbols}, \\\n+${c_reset}${c_grafted}replaced${c_reset}${c_symbols})${c_reset} D\n+\t${c_commit}COMMIT_ID${c_reset}${c_symbols} (${c_reset}\\\n+${c_tag}tag: ${c_reset}${c_tag}v1.0${c_reset}${c_symbols}, \\\n+${c_reset}${c_tag}tag: ${c_reset}${c_tag}B${c_reset}${c_symbols})${c_reset} B\n+\t${c_commit}COMMIT_ID${c_reset}${c_symbols} (${c_reset}\\\n+${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_symbols})${c_reset} A\n \tEOF\n \n \tgit log --first-parent --no-abbrev --decorate --oneline --color=always HEAD >actual &&\n-- \n2.42.GIT\n\n"},{"id":"483519","messageId":"20231019193911.1669705-1-andy.koppe@gmail.com","threadId":"60303","inReplyTo":"20231003205442.22963-1-andy.koppe@gmail.com","subject":"[PATCH 0/7] log: decorate pseudorefs and other refs","fromName":"Andy Koppe","fromEmail":"andy.koppe@gmail.com","sentAt":"2023-10-19T19:39:04Z","receivedAt":"2023-10-19T19:39:35Z","isPatch":true,"sender":{"key":"andy.koppe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/223411?v=4"},"body":"This patch series adds three slots to the color.decorate.<slot> config\noption:\n- 'symbol' for coloring the punctuation symbols used around the refs in\n  decorations, which currently use the same color as the commit hash.\n- 'ref' for coloring refs other than branches, remote-tracking branches,\n  tags and the stash, which currently are not colored when included in\n  decorations through custom decoration filter options.\n- 'pseudoref' for coloring pseudorefs such as ORIG_HEAD or MERGE_HEAD.\n  Include them in decorations by default.\n\nThis series is to replace the 'decorate: add color.decorate.symbols\nconfig option' patch proposed at:\nhttps://lore.kernel.org/git/20231003205442.22963-1-andy.koppe@gmail.com\n\nAndy Koppe (7):\n  config: restructure color.decorate documentation\n  log: use designated inits for decoration_colors\n  log: add color.decorate.symbol config option\n  refs: separate decoration type from default filter\n  log: add color.decorate.ref option for other refs\n  refs: exempt pseudoref patterns from prefixing\n  log: show pseudorefs in decorations\n\n Documentation/config/color.txt                | 30 +++++++-\n Documentation/git-log.txt                     |  7 +-\n builtin/log.c                                 |  6 +-\n commit.h                                      |  3 +\n log-tree.c                                    | 60 ++++++++++++---\n refs.c                                        | 62 ++++++++++++++--\n refs.h                                        | 14 ++++\n t/t4013/diff.log_--decorate=full_--all        |  2 +-\n ..._--decorate=full_--clear-decorations_--all |  4 +-\n t/t4013/diff.log_--decorate_--all             |  2 +-\n ...f.log_--decorate_--clear-decorations_--all |  4 +-\n t/t4202-log.sh                                | 23 +++---\n t/t4207-log-decoration-colors.sh              | 74 +++++++++++--------\n 13 files changed, 216 insertions(+), 75 deletions(-)\n\n-- \n2.42.GIT\n\n"},{"id":"483520","messageId":"20231019193911.1669705-2-andy.koppe@gmail.com","threadId":"60303","inReplyTo":"20231003205442.22963-1-andy.koppe@gmail.com","subject":"[PATCH 1/7] config: restructure color.decorate documentation","fromName":"Andy Koppe","fromEmail":"andy.koppe@gmail.com","sentAt":"2023-10-19T19:39:05Z","receivedAt":"2023-10-19T19:39:43Z","isPatch":true,"sender":{"key":"andy.koppe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/223411?v=4"},"body":"List color.decorate slots in git-config documentation one-by-one in the\nsame way as color.grep slots, to aid readability and make it easier to\nadd slots.\n\nSigned-off-by: Andy Koppe <andy.koppe@gmail.com>\n---\n Documentation/config/color.txt | 23 +++++++++++++++++++----\n 1 file changed, 19 insertions(+), 4 deletions(-)\n\ndiff --git a/Documentation/config/color.txt b/Documentation/config/color.txt\nindex 1795b2d16be..b0e2eccad95 100644\n--- a/Documentation/config/color.txt\n+++ b/Documentation/config/color.txt\n@@ -74,10 +74,25 @@ color.diff.<slot>::\n \t`oldBold`, and `newBold` (see linkgit:git-range-diff[1] for details).\n \n color.decorate.<slot>::\n-\tUse customized color for 'git log --decorate' output.  `<slot>` is one\n-\tof `branch`, `remoteBranch`, `tag`, `stash` or `HEAD` for local\n-\tbranches, remote-tracking branches, tags, stash and HEAD, respectively\n-\tand `grafted` for grafted commits.\n+\tUse customized color for the output of `git log --decorate` as well as\n+\tthe `%d`, `%D` and `%(decorate)` placeholders in custom log formats,\n+\twhereby `<slot>` specifies which decoration elements the color applies\n+\tto:\n++\n+--\n+`HEAD`;;\n+\tthe current HEAD\n+`branch`;;\n+\tlocal branches\n+`remoteBranch`;;\n+\tremote-tracking branches\n+`tag`;;\n+\tlightweight and annotated tags\n+`stash`;;\n+\tthe stash ref\n+`grafted`;;\n+\tgrafted commits (used to implement shallow clones)\n+--\n \n color.grep::\n \tWhen set to `always`, always highlight matches.  When `false` (or\n-- \n2.42.GIT\n\n"},{"id":"483521","messageId":"20231019193911.1669705-3-andy.koppe@gmail.com","threadId":"60303","inReplyTo":"20231003205442.22963-1-andy.koppe@gmail.com","subject":"[PATCH 2/7] log: use designated inits for decoration_colors","fromName":"Andy Koppe","fromEmail":"andy.koppe@gmail.com","sentAt":"2023-10-19T19:39:06Z","receivedAt":"2023-10-19T19:39:47Z","isPatch":true,"sender":{"key":"andy.koppe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/223411?v=4"},"body":"Use designated initializers instead of comments to denote the slots in\nthe decoration_colors array for holding color settings, to reduce the\nlikelihood of mistakes when extending the array.\n\nSigned-off-by: Andy Koppe <andy.koppe@gmail.com>\n---\n log-tree.c | 14 +++++++-------\n 1 file changed, 7 insertions(+), 7 deletions(-)\n\ndiff --git a/log-tree.c b/log-tree.c\nindex 504da6b519e..8bdf889f022 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -34,13 +34,13 @@ static int decoration_loaded;\n static int decoration_flags;\n \n static char decoration_colors[][COLOR_MAXLEN] = {\n-\tGIT_COLOR_RESET,\n-\tGIT_COLOR_BOLD_GREEN,\t/* REF_LOCAL */\n-\tGIT_COLOR_BOLD_RED,\t/* REF_REMOTE */\n-\tGIT_COLOR_BOLD_YELLOW,\t/* REF_TAG */\n-\tGIT_COLOR_BOLD_MAGENTA,\t/* REF_STASH */\n-\tGIT_COLOR_BOLD_CYAN,\t/* REF_HEAD */\n-\tGIT_COLOR_BOLD_BLUE,\t/* GRAFTED */\n+\t[DECORATION_NONE]\t= GIT_COLOR_RESET,\n+\t[DECORATION_REF_LOCAL]\t= GIT_COLOR_BOLD_GREEN,\n+\t[DECORATION_REF_REMOTE]\t= GIT_COLOR_BOLD_RED,\n+\t[DECORATION_REF_TAG]\t= GIT_COLOR_BOLD_YELLOW,\n+\t[DECORATION_REF_STASH]\t= GIT_COLOR_BOLD_MAGENTA,\n+\t[DECORATION_REF_HEAD]\t= GIT_COLOR_BOLD_CYAN,\n+\t[DECORATION_GRAFTED]\t= GIT_COLOR_BOLD_BLUE,\n };\n \n static const char *color_decorate_slots[] = {\n-- \n2.42.GIT\n\n"},{"id":"483522","messageId":"20231019193911.1669705-4-andy.koppe@gmail.com","threadId":"60303","inReplyTo":"20231003205442.22963-1-andy.koppe@gmail.com","subject":"[PATCH 3/7] log: add color.decorate.symbol config option","fromName":"Andy Koppe","fromEmail":"andy.koppe@gmail.com","sentAt":"2023-10-19T19:39:07Z","receivedAt":"2023-10-19T19:39:50Z","isPatch":true,"sender":{"key":"andy.koppe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/223411?v=4"},"body":"Add new 'color.decorate.symbol' config option for determining the color\nof the prefix, suffix, separator and arrow symbols used in --decorate\noutput and related log format placeholders, to allow them to be colored\ndifferently from commit hashes.\n\nFor backward compatibility, fall back to the commit hash color that can\nbe specified with the 'color.diff.commit' option if the new option is\nnot provided.\n\nAdd the setting to the color.decorate.<slot> documentation.\n\nAmend t4207-log-decoration-colors.sh to test it. Put ${c_reset} elements\nin the expected output at the end of lines for consistency.\n\nSigned-off-by: Andy Koppe <andy.koppe@gmail.com>\n---\n Documentation/config/color.txt   |  2 ++\n commit.h                         |  1 +\n log-tree.c                       | 15 ++++++---\n t/t4207-log-decoration-colors.sh | 58 +++++++++++++++++---------------\n 4 files changed, 43 insertions(+), 33 deletions(-)\n\ndiff --git a/Documentation/config/color.txt b/Documentation/config/color.txt\nindex b0e2eccad95..ba9f56885e3 100644\n--- a/Documentation/config/color.txt\n+++ b/Documentation/config/color.txt\n@@ -92,6 +92,8 @@ color.decorate.<slot>::\n \tthe stash ref\n `grafted`;;\n \tgrafted commits (used to implement shallow clones)\n+`symbol`;;\n+\tpunctuation surrounding the other elements\n --\n \n color.grep::\ndiff --git a/commit.h b/commit.h\nindex 28928833c54..cb13e4d5baa 100644\n--- a/commit.h\n+++ b/commit.h\n@@ -56,6 +56,7 @@ enum decoration_type {\n \tDECORATION_REF_STASH,\n \tDECORATION_REF_HEAD,\n \tDECORATION_GRAFTED,\n+\tDECORATION_SYMBOL,\n };\n \n void add_name_decoration(enum decoration_type type, const char *name, struct object *obj);\ndiff --git a/log-tree.c b/log-tree.c\nindex 8bdf889f022..890024f205b 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -41,6 +41,7 @@ static char decoration_colors[][COLOR_MAXLEN] = {\n \t[DECORATION_REF_STASH]\t= GIT_COLOR_BOLD_MAGENTA,\n \t[DECORATION_REF_HEAD]\t= GIT_COLOR_BOLD_CYAN,\n \t[DECORATION_GRAFTED]\t= GIT_COLOR_BOLD_BLUE,\n+\t[DECORATION_SYMBOL]\t= GIT_COLOR_NIL,\n };\n \n static const char *color_decorate_slots[] = {\n@@ -50,6 +51,7 @@ static const char *color_decorate_slots[] = {\n \t[DECORATION_REF_STASH]\t= \"stash\",\n \t[DECORATION_REF_HEAD]\t= \"HEAD\",\n \t[DECORATION_GRAFTED]\t= \"grafted\",\n+\t[DECORATION_SYMBOL]\t= \"symbol\",\n };\n \n static const char *decorate_get_color(int decorate_use_color, enum decoration_type ix)\n@@ -312,7 +314,7 @@ void format_decorations(struct strbuf *sb,\n {\n \tconst struct name_decoration *decoration;\n \tconst struct name_decoration *current_and_HEAD;\n-\tconst char *color_commit, *color_reset;\n+\tconst char *color_symbol, *color_reset;\n \n \tconst char *prefix = \" (\";\n \tconst char *suffix = \")\";\n@@ -337,7 +339,10 @@ void format_decorations(struct strbuf *sb,\n \t\t\ttag = opts->tag;\n \t}\n \n-\tcolor_commit = diff_get_color(use_color, DIFF_COMMIT);\n+\tcolor_symbol = decorate_get_color(use_color, DECORATION_SYMBOL);\n+\tif (color_is_nil(color_symbol))\n+\t\tcolor_symbol = diff_get_color(use_color, DIFF_COMMIT);\n+\n \tcolor_reset = decorate_get_color(use_color, DECORATION_NONE);\n \n \tcurrent_and_HEAD = current_pointed_by_HEAD(decoration);\n@@ -352,7 +357,7 @@ void format_decorations(struct strbuf *sb,\n \t\t\t\tdecorate_get_color(use_color, decoration->type);\n \n \t\t\tif (*prefix) {\n-\t\t\t\tstrbuf_addstr(sb, color_commit);\n+\t\t\t\tstrbuf_addstr(sb, color_symbol);\n \t\t\t\tstrbuf_addstr(sb, prefix);\n \t\t\t\tstrbuf_addstr(sb, color_reset);\n \t\t\t}\n@@ -369,7 +374,7 @@ void format_decorations(struct strbuf *sb,\n \n \t\t\tif (current_and_HEAD &&\n \t\t\t    decoration->type == DECORATION_REF_HEAD) {\n-\t\t\t\tstrbuf_addstr(sb, color_commit);\n+\t\t\t\tstrbuf_addstr(sb, color_symbol);\n \t\t\t\tstrbuf_addstr(sb, pointer);\n \t\t\t\tstrbuf_addstr(sb, color_reset);\n \t\t\t\tstrbuf_addstr(sb, decorate_get_color(use_color, current_and_HEAD->type));\n@@ -382,7 +387,7 @@ void format_decorations(struct strbuf *sb,\n \t\tdecoration = decoration->next;\n \t}\n \tif (*suffix) {\n-\t\tstrbuf_addstr(sb, color_commit);\n+\t\tstrbuf_addstr(sb, color_symbol);\n \t\tstrbuf_addstr(sb, suffix);\n \t\tstrbuf_addstr(sb, color_reset);\n \t}\ndiff --git a/t/t4207-log-decoration-colors.sh b/t/t4207-log-decoration-colors.sh\nindex 21986a866df..f4173b61141 100755\n--- a/t/t4207-log-decoration-colors.sh\n+++ b/t/t4207-log-decoration-colors.sh\n@@ -18,6 +18,7 @@ test_expect_success setup '\n \tgit config color.decorate.tag \"reverse bold yellow\" &&\n \tgit config color.decorate.stash magenta &&\n \tgit config color.decorate.grafted black &&\n+\tgit config color.decorate.symbol white &&\n \tgit config color.decorate.HEAD cyan &&\n \n \tc_reset=\"<RESET>\" &&\n@@ -29,6 +30,7 @@ test_expect_success setup '\n \tc_stash=\"<MAGENTA>\" &&\n \tc_HEAD=\"<CYAN>\" &&\n \tc_grafted=\"<BLACK>\" &&\n+\tc_symbol=\"<WHITE>\" &&\n \n \ttest_commit A &&\n \tgit clone . other &&\n@@ -53,17 +55,17 @@ cmp_filtered_decorations () {\n # to this test since it does not contain any decoration, hence --first-parent\n test_expect_success 'commit decorations colored correctly' '\n \tcat >expect <<-EOF &&\n-\t${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_HEAD}HEAD${c_reset}\\\n-${c_commit} -> ${c_reset}${c_branch}main${c_reset}${c_commit}, \\\n-${c_reset}${c_tag}tag: ${c_reset}${c_tag}v1.0${c_reset}${c_commit}, \\\n-${c_reset}${c_tag}tag: ${c_reset}${c_tag}B${c_reset}${c_commit})${c_reset} B\n-${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\\\n-${c_tag}tag: ${c_reset}${c_tag}A1${c_reset}${c_commit}, \\\n-${c_reset}${c_remoteBranch}other/main${c_reset}${c_commit})${c_reset} A1\n-\t${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\\\n-${c_stash}refs/stash${c_reset}${c_commit})${c_reset} On main: Changes to A.t\n-\t${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\\\n-${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_commit})${c_reset} A\n+\t${c_commit}COMMIT_ID${c_reset}${c_symbol} (${c_reset}${c_HEAD}HEAD${c_reset}\\\n+${c_symbol} -> ${c_reset}${c_branch}main${c_reset}${c_symbol}, ${c_reset}\\\n+${c_tag}tag: ${c_reset}${c_tag}v1.0${c_reset}${c_symbol}, ${c_reset}\\\n+${c_tag}tag: ${c_reset}${c_tag}B${c_reset}${c_symbol})${c_reset} B\n+${c_commit}COMMIT_ID${c_reset}${c_symbol} (${c_reset}\\\n+${c_tag}tag: ${c_reset}${c_tag}A1${c_reset}${c_symbol}, ${c_reset}\\\n+${c_remoteBranch}other/main${c_reset}${c_symbol})${c_reset} A1\n+\t${c_commit}COMMIT_ID${c_reset}${c_symbol} (${c_reset}\\\n+${c_stash}refs/stash${c_reset}${c_symbol})${c_reset} On main: Changes to A.t\n+\t${c_commit}COMMIT_ID${c_reset}${c_symbol} (${c_reset}\\\n+${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_symbol})${c_reset} A\n \tEOF\n \n \tgit log --first-parent --no-abbrev --decorate --oneline --color=always --all >actual &&\n@@ -78,14 +80,14 @@ test_expect_success 'test coloring with replace-objects' '\n \tgit replace HEAD~1 HEAD~2 &&\n \n \tcat >expect <<-EOF &&\n-\t${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_HEAD}HEAD${c_reset}\\\n-${c_commit} -> ${c_reset}${c_branch}main${c_reset}${c_commit}, \\\n-${c_reset}${c_tag}tag: ${c_reset}${c_tag}D${c_reset}${c_commit})${c_reset} D\n-\t${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\\\n-${c_tag}tag: ${c_reset}${c_tag}C${c_reset}${c_commit}, \\\n-${c_reset}${c_grafted}replaced${c_reset}${c_commit})${c_reset} B\n-\t${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\\\n-${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_commit})${c_reset} A\n+\t${c_commit}COMMIT_ID${c_reset}${c_symbol} (${c_reset}${c_HEAD}HEAD${c_reset}\\\n+${c_symbol} -> ${c_reset}${c_branch}main${c_reset}${c_symbol}, ${c_reset}\\\n+${c_tag}tag: ${c_reset}${c_tag}D${c_reset}${c_symbol})${c_reset} D\n+\t${c_commit}COMMIT_ID${c_reset}${c_symbol} (${c_reset}\\\n+${c_tag}tag: ${c_reset}${c_tag}C${c_reset}${c_symbol}, ${c_reset}\\\n+${c_grafted}replaced${c_reset}${c_symbol})${c_reset} B\n+\t${c_commit}COMMIT_ID${c_reset}${c_symbol} (${c_reset}\\\n+${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_symbol})${c_reset} A\n EOF\n \n \tgit log --first-parent --no-abbrev --decorate --oneline --color=always HEAD >actual &&\n@@ -104,15 +106,15 @@ test_expect_success 'test coloring with grafted commit' '\n \tgit replace --graft HEAD HEAD~2 &&\n \n \tcat >expect <<-EOF &&\n-\t${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_HEAD}HEAD${c_reset}\\\n-${c_commit} -> ${c_reset}${c_branch}main${c_reset}${c_commit}, \\\n-${c_reset}${c_tag}tag: ${c_reset}${c_tag}D${c_reset}${c_commit}, \\\n-${c_reset}${c_grafted}replaced${c_reset}${c_commit})${c_reset} D\n-\t${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\\\n-${c_tag}tag: ${c_reset}${c_tag}v1.0${c_reset}${c_commit}, \\\n-${c_reset}${c_tag}tag: ${c_reset}${c_tag}B${c_reset}${c_commit})${c_reset} B\n-\t${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\\\n-${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_commit})${c_reset} A\n+\t${c_commit}COMMIT_ID${c_reset}${c_symbol} (${c_reset}${c_HEAD}HEAD${c_reset}\\\n+${c_symbol} -> ${c_reset}${c_branch}main${c_reset}${c_symbol}, ${c_reset}\\\n+${c_tag}tag: ${c_reset}${c_tag}D${c_reset}${c_symbol}, ${c_reset}\\\n+${c_grafted}replaced${c_reset}${c_symbol})${c_reset} D\n+\t${c_commit}COMMIT_ID${c_reset}${c_symbol} (${c_reset}\\\n+${c_tag}tag: ${c_reset}${c_tag}v1.0${c_reset}${c_symbol}, ${c_reset}\\\n+${c_tag}tag: ${c_reset}${c_tag}B${c_reset}${c_symbol})${c_reset} B\n+\t${c_commit}COMMIT_ID${c_reset}${c_symbol} (${c_reset}\\\n+${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_symbol})${c_reset} A\n \tEOF\n \n \tgit log --first-parent --no-abbrev --decorate --oneline --color=always HEAD >actual &&\n-- \n2.42.GIT\n\n"},{"id":"483523","messageId":"20231019193911.1669705-5-andy.koppe@gmail.com","threadId":"60303","inReplyTo":"20231003205442.22963-1-andy.koppe@gmail.com","subject":"[PATCH 4/7] refs: separate decoration type from default filter","fromName":"Andy Koppe","fromEmail":"andy.koppe@gmail.com","sentAt":"2023-10-19T19:39:08Z","receivedAt":"2023-10-19T19:39:51Z","isPatch":true,"sender":{"key":"andy.koppe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/223411?v=4"},"body":"Add 'include' bit to struct ref_namespace_info to determine whether a\nref namespace is to be included in the default decoration filters,\ninstead of using the decoration type for the purpose.\n\nThis is to allow adding ref namespaces that do have a decoration type\nbut that are not shown by default.\n\nSigned-off-by: Andy Koppe <andy.koppe@gmail.com>\n---\n builtin/log.c | 6 ++----\n refs.c        | 6 ++++++\n refs.h        | 4 ++++\n 3 files changed, 12 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/log.c b/builtin/log.c\nindex ba775d7b5cf..25d73c25697 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -227,10 +227,8 @@ static void set_default_decoration_filter(struct decoration_filter *decoration_f\n \t * populate with sensible defaults.\n \t */\n \tfor (i = 0; i < ARRAY_SIZE(ref_namespace); i++) {\n-\t\tif (!ref_namespace[i].decoration)\n-\t\t\tcontinue;\n-\n-\t\tstring_list_append(include, ref_namespace[i].ref);\n+\t\tif (ref_namespace[i].include)\n+\t\t\tstring_list_append(include, ref_namespace[i].ref);\n \t}\n }\n \ndiff --git a/refs.c b/refs.c\nindex fcae5dddc60..416c35f0c2f 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -70,14 +70,17 @@ struct ref_namespace_info ref_namespace[] = {\n \t\t.ref = \"HEAD\",\n \t\t.decoration = DECORATION_REF_HEAD,\n \t\t.exact = 1,\n+\t\t.include = 1,\n \t},\n \t[NAMESPACE_BRANCHES] = {\n \t\t.ref = \"refs/heads/\",\n \t\t.decoration = DECORATION_REF_LOCAL,\n+\t\t.include = 1,\n \t},\n \t[NAMESPACE_TAGS] = {\n \t\t.ref = \"refs/tags/\",\n \t\t.decoration = DECORATION_REF_TAG,\n+\t\t.include = 1,\n \t},\n \t[NAMESPACE_REMOTE_REFS] = {\n \t\t/*\n@@ -87,6 +90,7 @@ struct ref_namespace_info ref_namespace[] = {\n \t\t */\n \t\t.ref = \"refs/remotes/\",\n \t\t.decoration = DECORATION_REF_REMOTE,\n+\t\t.include = 1,\n \t},\n \t[NAMESPACE_STASH] = {\n \t\t/*\n@@ -96,6 +100,7 @@ struct ref_namespace_info ref_namespace[] = {\n \t\t.ref = \"refs/stash\",\n \t\t.exact = 1,\n \t\t.decoration = DECORATION_REF_STASH,\n+\t\t.include = 1,\n \t},\n \t[NAMESPACE_REPLACE] = {\n \t\t/*\n@@ -107,6 +112,7 @@ struct ref_namespace_info ref_namespace[] = {\n \t\t */\n \t\t.ref = \"refs/replace/\",\n \t\t.decoration = DECORATION_GRAFTED,\n+\t\t.include = 1,\n \t},\n \t[NAMESPACE_NOTES] = {\n \t\t/*\ndiff --git a/refs.h b/refs.h\nindex 23211a5ea1c..4b054d30fe5 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -987,10 +987,14 @@ struct ref_namespace_info {\n \t * If 'exact' is true, then we must match the 'ref' exactly.\n \t * Otherwise, use a prefix match.\n \t *\n+\t * If 'include' is true, the namespace is included in the\n+\t * default decoration filters.\n+\t *\n \t * 'ref_updated' is for internal use. It represents whether the\n \t * 'ref' value was replaced from its original literal version.\n \t */\n \tunsigned exact:1,\n+\t\t include:1,\n \t\t ref_updated:1;\n };\n \n-- \n2.42.GIT\n\n"},{"id":"483524","messageId":"20231019193911.1669705-6-andy.koppe@gmail.com","threadId":"60303","inReplyTo":"20231003205442.22963-1-andy.koppe@gmail.com","subject":"[PATCH 5/7] log: add color.decorate.ref option for other refs","fromName":"Andy Koppe","fromEmail":"andy.koppe@gmail.com","sentAt":"2023-10-19T19:39:09Z","receivedAt":"2023-10-19T19:39:52Z","isPatch":true,"sender":{"key":"andy.koppe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/223411?v=4"},"body":"Refs other than those with builtin special meaning do not appear in log\ndecorations by default, but they can be made to appear using the\ndecoration filter options. However, they would do so without coloring.\n\nAdd config option color.decorate.ref to address this, defaulting to bold\nmagenta, which is the same as refs/stash.\n\nTo implement this, add NAMESPACE_REF with pattern \"refs/\", but do not\nset its .include bit, so as to leave it out of the default decoration\nfilter.\n\nDocument the color.decorate slot on the git-config page and amend\nt4207-log-decoration-colors.sh to test it.\n\nSigned-off-by: Andy Koppe <andy.koppe@gmail.com>\n---\n Documentation/config/color.txt   | 3 +++\n commit.h                         | 1 +\n log-tree.c                       | 2 ++\n refs.c                           | 7 +++++++\n refs.h                           | 1 +\n t/t4207-log-decoration-colors.sh | 9 +++++++--\n 6 files changed, 21 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/config/color.txt b/Documentation/config/color.txt\nindex ba9f56885e3..086efebbe5d 100644\n--- a/Documentation/config/color.txt\n+++ b/Documentation/config/color.txt\n@@ -92,6 +92,9 @@ color.decorate.<slot>::\n \tthe stash ref\n `grafted`;;\n \tgrafted commits (used to implement shallow clones)\n+`ref`;;\n+\tany other refs (not shown unless enabled with one of the decoration\n+\tfilter options such as `--decorate-refs=<pattern>`)\n `symbol`;;\n \tpunctuation surrounding the other elements\n --\ndiff --git a/commit.h b/commit.h\nindex cb13e4d5baa..f6b2125fc42 100644\n--- a/commit.h\n+++ b/commit.h\n@@ -54,6 +54,7 @@ enum decoration_type {\n \tDECORATION_REF_REMOTE,\n \tDECORATION_REF_TAG,\n \tDECORATION_REF_STASH,\n+\tDECORATION_REF,\n \tDECORATION_REF_HEAD,\n \tDECORATION_GRAFTED,\n \tDECORATION_SYMBOL,\ndiff --git a/log-tree.c b/log-tree.c\nindex 890024f205b..fd99eb88d95 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -39,6 +39,7 @@ static char decoration_colors[][COLOR_MAXLEN] = {\n \t[DECORATION_REF_REMOTE]\t= GIT_COLOR_BOLD_RED,\n \t[DECORATION_REF_TAG]\t= GIT_COLOR_BOLD_YELLOW,\n \t[DECORATION_REF_STASH]\t= GIT_COLOR_BOLD_MAGENTA,\n+\t[DECORATION_REF]\t= GIT_COLOR_BOLD_MAGENTA,\n \t[DECORATION_REF_HEAD]\t= GIT_COLOR_BOLD_CYAN,\n \t[DECORATION_GRAFTED]\t= GIT_COLOR_BOLD_BLUE,\n \t[DECORATION_SYMBOL]\t= GIT_COLOR_NIL,\n@@ -49,6 +50,7 @@ static const char *color_decorate_slots[] = {\n \t[DECORATION_REF_REMOTE] = \"remoteBranch\",\n \t[DECORATION_REF_TAG]\t= \"tag\",\n \t[DECORATION_REF_STASH]\t= \"stash\",\n+\t[DECORATION_REF]\t= \"ref\",\n \t[DECORATION_REF_HEAD]\t= \"HEAD\",\n \t[DECORATION_GRAFTED]\t= \"grafted\",\n \t[DECORATION_SYMBOL]\t= \"symbol\",\ndiff --git a/refs.c b/refs.c\nindex 416c35f0c2f..b03cccab909 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -142,6 +142,13 @@ struct ref_namespace_info ref_namespace[] = {\n \t\t */\n \t\t.ref = \"refs/rewritten/\",\n \t},\n+\t[NAMESPACE_REFS] = {\n+\t\t/*\n+\t\t * Catch-all for any other refs.\n+\t\t */\n+\t\t.ref = \"refs/\",\n+\t\t.decoration = DECORATION_REF,\n+\t},\n };\n \n void update_ref_namespace(enum ref_namespace namespace, char *ref)\ndiff --git a/refs.h b/refs.h\nindex 4b054d30fe5..82aecd37a2b 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -1008,6 +1008,7 @@ enum ref_namespace {\n \tNAMESPACE_NOTES,\n \tNAMESPACE_PREFETCH,\n \tNAMESPACE_REWRITTEN,\n+\tNAMESPACE_REFS,\n \n \t/* Must be last */\n \tNAMESPACE__COUNT\ndiff --git a/t/t4207-log-decoration-colors.sh b/t/t4207-log-decoration-colors.sh\nindex f4173b61141..4b51e34f8b2 100755\n--- a/t/t4207-log-decoration-colors.sh\n+++ b/t/t4207-log-decoration-colors.sh\n@@ -17,6 +17,7 @@ test_expect_success setup '\n \tgit config color.decorate.remoteBranch red &&\n \tgit config color.decorate.tag \"reverse bold yellow\" &&\n \tgit config color.decorate.stash magenta &&\n+\tgit config color.decorate.ref blue &&\n \tgit config color.decorate.grafted black &&\n \tgit config color.decorate.symbol white &&\n \tgit config color.decorate.HEAD cyan &&\n@@ -28,11 +29,13 @@ test_expect_success setup '\n \tc_remoteBranch=\"<RED>\" &&\n \tc_tag=\"<BOLD;REVERSE;YELLOW>\" &&\n \tc_stash=\"<MAGENTA>\" &&\n+\tc_ref=\"<BLUE>\" &&\n \tc_HEAD=\"<CYAN>\" &&\n \tc_grafted=\"<BLACK>\" &&\n \tc_symbol=\"<WHITE>\" &&\n \n \ttest_commit A &&\n+\tgit update-ref refs/foo A &&\n \tgit clone . other &&\n \t(\n \t\tcd other &&\n@@ -65,10 +68,12 @@ ${c_remoteBranch}other/main${c_reset}${c_symbol})${c_reset} A1\n \t${c_commit}COMMIT_ID${c_reset}${c_symbol} (${c_reset}\\\n ${c_stash}refs/stash${c_reset}${c_symbol})${c_reset} On main: Changes to A.t\n \t${c_commit}COMMIT_ID${c_reset}${c_symbol} (${c_reset}\\\n-${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_symbol})${c_reset} A\n+${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_symbol}, ${c_reset}\\\n+${c_ref}refs/foo${c_reset}${c_symbol})${c_reset} A\n \tEOF\n \n-\tgit log --first-parent --no-abbrev --decorate --oneline --color=always --all >actual &&\n+\tgit log --first-parent --no-abbrev --decorate --clear-decorations \\\n+\t\t--oneline --color=always --all >actual &&\n \tcmp_filtered_decorations\n '\n \n-- \n2.42.GIT\n\n"},{"id":"483525","messageId":"20231019193911.1669705-7-andy.koppe@gmail.com","threadId":"60303","inReplyTo":"20231003205442.22963-1-andy.koppe@gmail.com","subject":"[PATCH 6/7] refs: exempt pseudoref patterns from prefixing","fromName":"Andy Koppe","fromEmail":"andy.koppe@gmail.com","sentAt":"2023-10-19T19:39:10Z","receivedAt":"2023-10-19T19:39:53Z","isPatch":true,"sender":{"key":"andy.koppe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/223411?v=4"},"body":"In normalize_glob_ref(), don't prefix patterns that look like pseudorefs\nwith \"refs/\". This is in preparation for showing pseudorefs such as\nORIG_HEAD in log decorations, as they are not matched as intended in\ndecoration filters otherwise.\n\nUse existing function is_pseudoref_syntax() to do this, declaring it in\nrefs.h to make it available to normalize_glob_ref() and anything else\nthat might need it. As the function returns true for HEAD as well, the\nspecial case for that is no longer needed.\n\nSigned-off-by: Andy Koppe <andy.koppe@gmail.com>\n---\n refs.c | 8 ++------\n refs.h | 2 ++\n 2 files changed, 4 insertions(+), 6 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex b03cccab909..492b9f7d4e5 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -564,12 +564,8 @@ void normalize_glob_ref(struct string_list_item *item, const char *prefix,\n \tif (prefix)\n \t\tstrbuf_addstr(&normalized_pattern, prefix);\n \telse if (!starts_with(pattern, \"refs/\") &&\n-\t\t   strcmp(pattern, \"HEAD\"))\n+\t\t !is_pseudoref_syntax(pattern))\n \t\tstrbuf_addstr(&normalized_pattern, \"refs/\");\n-\t/*\n-\t * NEEDSWORK: Special case other symrefs such as REBASE_HEAD,\n-\t * MERGE_HEAD, etc.\n-\t */\n \n \tstrbuf_addstr(&normalized_pattern, pattern);\n \tstrbuf_strip_suffix(&normalized_pattern, \"/\");\n@@ -840,7 +836,7 @@ int is_per_worktree_ref(const char *refname)\n \t       starts_with(refname, \"refs/rewritten/\");\n }\n \n-static int is_pseudoref_syntax(const char *refname)\n+int is_pseudoref_syntax(const char *refname)\n {\n \tconst char *c;\n \ndiff --git a/refs.h b/refs.h\nindex 82aecd37a2b..b77691d787a 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -123,6 +123,8 @@ int should_autocreate_reflog(const char *refname);\n \n int is_branch(const char *refname);\n \n+int is_pseudoref_syntax(const char *refname);\n+\n int refs_init_db(struct strbuf *err);\n \n /*\n-- \n2.42.GIT\n\n"},{"id":"483526","messageId":"20231019193911.1669705-8-andy.koppe@gmail.com","threadId":"60303","inReplyTo":"20231003205442.22963-1-andy.koppe@gmail.com","subject":"[PATCH 7/7] log: show pseudorefs in decorations","fromName":"Andy Koppe","fromEmail":"andy.koppe@gmail.com","sentAt":"2023-10-19T19:39:11Z","receivedAt":"2023-10-19T19:39:56Z","isPatch":true,"sender":{"key":"andy.koppe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/223411?v=4"},"body":"Show various pseudorefs in log decorations. This includes pseudorefs for\nongoing operations such as MERGE_HEAD and REBASE_HEAD, as well as\nORIG_HEAD for the HEAD position before any \"drastic\" operations.\n\nDo not include FETCH_HEAD in the default decoration filter though,\nbecause it would appear a lot in user's logs, often right alongside\nHEAD, while providing little value as usually a remote-tracking branch\nalready points at what's been fetched.\n\nTo implement this, introduce decoration type DECORATION_REF_PSEUDO with\ncorresponding color.decorate.pseudoref setting that defaults to bold\nblue. (This makes it similar to but not the same as HEAD, which defaults\nto bold cyan.)\n\nAdd entries for each pseudoref to the ref_namespace array in refs.c.\nProcess them in new function add_pseudoref_decorations(). They also get\npicked up by set_default_decoration_filter().\n\nDocument the showing of pseudorefs on the git-log page and the\ncolor.decorate.pseudoref setting on the git-config page.\n\nAmend t4207-log-decoration-colors.sh to test color.decorate.pseudoref,\nand tweak various other tests to reflect the appearance of ORIG_HEAD in\ndecorations.\n\nSigned-off-by: Andy Koppe <andy.koppe@gmail.com>\n---\n Documentation/config/color.txt                |  2 +\n Documentation/git-log.txt                     |  7 ++--\n commit.h                                      |  1 +\n log-tree.c                                    | 29 +++++++++++++\n refs.c                                        | 41 +++++++++++++++++++\n refs.h                                        |  7 ++++\n t/t4013/diff.log_--decorate=full_--all        |  2 +-\n ..._--decorate=full_--clear-decorations_--all |  4 +-\n t/t4013/diff.log_--decorate_--all             |  2 +-\n ...f.log_--decorate_--clear-decorations_--all |  4 +-\n t/t4202-log.sh                                | 23 ++++++-----\n t/t4207-log-decoration-colors.sh              | 13 ++++--\n 12 files changed, 113 insertions(+), 22 deletions(-)\n\ndiff --git a/Documentation/config/color.txt b/Documentation/config/color.txt\nindex 086efebbe5d..139fb90498a 100644\n--- a/Documentation/config/color.txt\n+++ b/Documentation/config/color.txt\n@@ -95,6 +95,8 @@ color.decorate.<slot>::\n `ref`;;\n \tany other refs (not shown unless enabled with one of the decoration\n \tfilter options such as `--decorate-refs=<pattern>`)\n+`pseudoref`;;\n+\tpseudorefs such as ORIG_HEAD or MERGE_HEAD\n `symbol`;;\n \tpunctuation surrounding the other elements\n --\ndiff --git a/Documentation/git-log.txt b/Documentation/git-log.txt\nindex 2a66cf88807..f217d16c439 100644\n--- a/Documentation/git-log.txt\n+++ b/Documentation/git-log.txt\n@@ -52,9 +52,10 @@ OPTIONS\n \tthe decorations, but an explicit `--decorate-refs` pattern will\n \toverride a match in `log.excludeDecoration`.\n +\n-If none of these options or config settings are given, then references are\n-used as decoration if they match `HEAD`, `refs/heads/`, `refs/remotes/`,\n-`refs/stash/`, or `refs/tags/`.\n+If none of these options or config settings are given, then refs matching\n+`refs/heads/`, `refs/remotes/`, `refs/stash/`, or `refs/tags/`, as well as\n+the `HEAD` ref and the pseudorefs `ORIG_HEAD`, `MERGE_HEAD`, `REBASE_HEAD`,\n+`CHERRY_PICK_HEAD`, `REVERT_HEAD` and `BISECT_HEAD` are shown.\n \n --clear-decorations::\n \tWhen specified, this option clears all previous `--decorate-refs`\ndiff --git a/commit.h b/commit.h\nindex f6b2125fc42..44dd3ce19b4 100644\n--- a/commit.h\n+++ b/commit.h\n@@ -56,6 +56,7 @@ enum decoration_type {\n \tDECORATION_REF_STASH,\n \tDECORATION_REF,\n \tDECORATION_REF_HEAD,\n+\tDECORATION_REF_PSEUDO,\n \tDECORATION_GRAFTED,\n \tDECORATION_SYMBOL,\n };\ndiff --git a/log-tree.c b/log-tree.c\nindex fd99eb88d95..eae288599d0 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -41,6 +41,7 @@ static char decoration_colors[][COLOR_MAXLEN] = {\n \t[DECORATION_REF_STASH]\t= GIT_COLOR_BOLD_MAGENTA,\n \t[DECORATION_REF]\t= GIT_COLOR_BOLD_MAGENTA,\n \t[DECORATION_REF_HEAD]\t= GIT_COLOR_BOLD_CYAN,\n+\t[DECORATION_REF_PSEUDO]\t= GIT_COLOR_BOLD_BLUE,\n \t[DECORATION_GRAFTED]\t= GIT_COLOR_BOLD_BLUE,\n \t[DECORATION_SYMBOL]\t= GIT_COLOR_NIL,\n };\n@@ -52,6 +53,7 @@ static const char *color_decorate_slots[] = {\n \t[DECORATION_REF_STASH]\t= \"stash\",\n \t[DECORATION_REF]\t= \"ref\",\n \t[DECORATION_REF_HEAD]\t= \"HEAD\",\n+\t[DECORATION_REF_PSEUDO]\t= \"pseudoref\",\n \t[DECORATION_GRAFTED]\t= \"grafted\",\n \t[DECORATION_SYMBOL]\t= \"symbol\",\n };\n@@ -146,6 +148,32 @@ static int ref_filter_match(const char *refname,\n \treturn 1;\n }\n \n+static void add_pseudoref_decorations(const struct decoration_filter *filter)\n+{\n+\tstruct ref_store *store = get_main_ref_store(the_repository);\n+\tint i;\n+\n+\tfor (i = 0; i < ARRAY_SIZE(ref_namespace); i++) {\n+\t\tstruct object_id oid;\n+\t\tstruct object *obj;\n+\t\tenum object_type objtype;\n+\t\tconst struct ref_namespace_info *info = &ref_namespace[i];\n+\n+\t\tif (info->decoration != DECORATION_REF_PSEUDO ||\n+\t\t    !refs_resolve_ref_unsafe(store, info->ref,\n+\t\t\t\t\t     RESOLVE_REF_READING, &oid, NULL) ||\n+\t\t    (filter && !ref_filter_match(info->ref, filter)))\n+\t\t\tcontinue;\n+\n+\t\tobjtype = oid_object_info(the_repository, &oid, NULL);\n+\t\tif (objtype < 0)\n+\t\t\tcontinue;\n+\n+\t\tobj = lookup_object_by_type(the_repository, &oid, objtype);\n+\t\tadd_name_decoration(DECORATION_REF_PSEUDO, info->ref, obj);\n+\t}\n+}\n+\n static int add_ref_decoration(const char *refname, const struct object_id *oid,\n \t\t\t      int flags UNUSED,\n \t\t\t      void *cb_data)\n@@ -236,6 +264,7 @@ void load_ref_decorations(struct decoration_filter *filter, int flags)\n \t\tdecoration_loaded = 1;\n \t\tdecoration_flags = flags;\n \t\tfor_each_ref(add_ref_decoration, filter);\n+\t\tadd_pseudoref_decorations(filter);\n \t\thead_ref(add_ref_decoration, filter);\n \t\tfor_each_commit_graft(add_graft_decoration, filter);\n \t}\ndiff --git a/refs.c b/refs.c\nindex 492b9f7d4e5..d960997aed1 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -149,6 +149,47 @@ struct ref_namespace_info ref_namespace[] = {\n \t\t.ref = \"refs/\",\n \t\t.decoration = DECORATION_REF,\n \t},\n+\t[NAMESPACE_ORIG_HEAD] = {\n+\t\t.ref = \"ORIG_HEAD\",\n+\t\t.exact = 1,\n+\t\t.decoration = DECORATION_REF_PSEUDO,\n+\t\t.include = 1,\n+\t},\n+\t[NAMESPACE_MERGE_HEAD] = {\n+\t\t.ref = \"MERGE_HEAD\",\n+\t\t.exact = 1,\n+\t\t.decoration = DECORATION_REF_PSEUDO,\n+\t\t.include = 1,\n+\t},\n+\t[NAMESPACE_REBASE_HEAD] = {\n+\t\t.ref = \"REBASE_HEAD\",\n+\t\t.exact = 1,\n+\t\t.decoration = DECORATION_REF_PSEUDO,\n+\t\t.include = 1,\n+\t},\n+\t[NAMESPACE_CHERRY_PICK_HEAD] = {\n+\t\t.ref = \"CHERRY_PICK_HEAD\",\n+\t\t.exact = 1,\n+\t\t.decoration = DECORATION_REF_PSEUDO,\n+\t\t.include = 1,\n+\t},\n+\t[NAMESPACE_REVERT_HEAD] = {\n+\t\t.ref = \"REVERT_HEAD\",\n+\t\t.exact = 1,\n+\t\t.decoration = DECORATION_REF_PSEUDO,\n+\t\t.include = 1,\n+\t},\n+\t[NAMESPACE_BISECT_HEAD] = {\n+\t\t.ref = \"BISECT_HEAD\",\n+\t\t.exact = 1,\n+\t\t.decoration = DECORATION_REF_PSEUDO,\n+\t\t.include = 1,\n+\t},\n+\t[NAMESPACE_FETCH_HEAD] = {\n+\t\t.ref = \"FETCH_HEAD\",\n+\t\t.exact = 1,\n+\t\t.decoration = DECORATION_REF_PSEUDO,\n+\t},\n };\n \n void update_ref_namespace(enum ref_namespace namespace, char *ref)\ndiff --git a/refs.h b/refs.h\nindex b77691d787a..5ac1f308d07 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -1011,6 +1011,13 @@ enum ref_namespace {\n \tNAMESPACE_PREFETCH,\n \tNAMESPACE_REWRITTEN,\n \tNAMESPACE_REFS,\n+\tNAMESPACE_ORIG_HEAD,\n+\tNAMESPACE_MERGE_HEAD,\n+\tNAMESPACE_REBASE_HEAD,\n+\tNAMESPACE_CHERRY_PICK_HEAD,\n+\tNAMESPACE_REVERT_HEAD,\n+\tNAMESPACE_BISECT_HEAD,\n+\tNAMESPACE_FETCH_HEAD,\n \n \t/* Must be last */\n \tNAMESPACE__COUNT\ndiff --git a/t/t4013/diff.log_--decorate=full_--all b/t/t4013/diff.log_--decorate=full_--all\nindex 6b0b334a5d6..9ebdd9b14fa 100644\n--- a/t/t4013/diff.log_--decorate=full_--all\n+++ b/t/t4013/diff.log_--decorate=full_--all\n@@ -39,7 +39,7 @@ Date:   Mon Jun 26 00:03:00 2006 +0000\n \n     Side\n \n-commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0\n+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 (ORIG_HEAD)\n Author: A U Thor <author@example.com>\n Date:   Mon Jun 26 00:02:00 2006 +0000\n \ndiff --git a/t/t4013/diff.log_--decorate=full_--clear-decorations_--all b/t/t4013/diff.log_--decorate=full_--clear-decorations_--all\nindex 1c030a6554e..7d16978e7f6 100644\n--- a/t/t4013/diff.log_--decorate=full_--clear-decorations_--all\n+++ b/t/t4013/diff.log_--decorate=full_--clear-decorations_--all\n@@ -33,13 +33,13 @@ Date:   Mon Jun 26 00:04:00 2006 +0000\n \n     Merge branch 'side'\n \n-commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a (refs/heads/side)\n+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a (FETCH_HEAD, refs/heads/side)\n Author: A U Thor <author@example.com>\n Date:   Mon Jun 26 00:03:00 2006 +0000\n \n     Side\n \n-commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0\n+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 (ORIG_HEAD)\n Author: A U Thor <author@example.com>\n Date:   Mon Jun 26 00:02:00 2006 +0000\n \ndiff --git a/t/t4013/diff.log_--decorate_--all b/t/t4013/diff.log_--decorate_--all\nindex c7df1f58141..46dde03cffa 100644\n--- a/t/t4013/diff.log_--decorate_--all\n+++ b/t/t4013/diff.log_--decorate_--all\n@@ -39,7 +39,7 @@ Date:   Mon Jun 26 00:03:00 2006 +0000\n \n     Side\n \n-commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0\n+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 (ORIG_HEAD)\n Author: A U Thor <author@example.com>\n Date:   Mon Jun 26 00:02:00 2006 +0000\n \ndiff --git a/t/t4013/diff.log_--decorate_--clear-decorations_--all b/t/t4013/diff.log_--decorate_--clear-decorations_--all\nindex 88be82cce31..4f9be50ce02 100644\n--- a/t/t4013/diff.log_--decorate_--clear-decorations_--all\n+++ b/t/t4013/diff.log_--decorate_--clear-decorations_--all\n@@ -33,13 +33,13 @@ Date:   Mon Jun 26 00:04:00 2006 +0000\n \n     Merge branch 'side'\n \n-commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a (side)\n+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a (FETCH_HEAD, side)\n Author: A U Thor <author@example.com>\n Date:   Mon Jun 26 00:03:00 2006 +0000\n \n     Side\n \n-commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0\n+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 (ORIG_HEAD)\n Author: A U Thor <author@example.com>\n Date:   Mon Jun 26 00:02:00 2006 +0000\n \ndiff --git a/t/t4202-log.sh b/t/t4202-log.sh\nindex af4a123cd22..ea048cb4a29 100755\n--- a/t/t4202-log.sh\n+++ b/t/t4202-log.sh\n@@ -927,7 +927,7 @@ test_expect_success 'multiple decorate-refs' '\n test_expect_success 'decorate-refs-exclude with glob' '\n \tcat >expect.decorate <<-\\EOF &&\n \tMerge-tag-reach (HEAD -> main)\n-\tMerge-tags-octopus-a-and-octopus-b\n+\tMerge-tags-octopus-a-and-octopus-b (ORIG_HEAD)\n \tseventh (tag: seventh)\n \toctopus-b (tag: octopus-b)\n \toctopus-a (tag: octopus-a)\n@@ -944,7 +944,7 @@ test_expect_success 'decorate-refs-exclude with glob' '\n test_expect_success 'decorate-refs-exclude without globs' '\n \tcat >expect.decorate <<-\\EOF &&\n \tMerge-tag-reach (HEAD -> main)\n-\tMerge-tags-octopus-a-and-octopus-b\n+\tMerge-tags-octopus-a-and-octopus-b (ORIG_HEAD)\n \tseventh (tag: seventh)\n \toctopus-b (tag: octopus-b, octopus-b)\n \toctopus-a (tag: octopus-a, octopus-a)\n@@ -961,7 +961,7 @@ test_expect_success 'decorate-refs-exclude without globs' '\n test_expect_success 'multiple decorate-refs-exclude' '\n \tcat >expect.decorate <<-\\EOF &&\n \tMerge-tag-reach (HEAD -> main)\n-\tMerge-tags-octopus-a-and-octopus-b\n+\tMerge-tags-octopus-a-and-octopus-b (ORIG_HEAD)\n \tseventh (tag: seventh)\n \toctopus-b (tag: octopus-b)\n \toctopus-a (tag: octopus-a)\n@@ -1022,10 +1022,12 @@ test_expect_success 'decorate-refs-exclude and simplify-by-decoration' '\n \tEOF\n \tgit log -n6 --decorate=short --pretty=\"tformat:%f%d\" \\\n \t\t--decorate-refs-exclude=\"*octopus*\" \\\n+\t\t--decorate-refs-exclude=\"ORIG_HEAD\" \\\n \t\t--simplify-by-decoration >actual &&\n \ttest_cmp expect.decorate actual &&\n-\tgit -c log.excludeDecoration=\"*octopus*\" log \\\n-\t\t-n6 --decorate=short --pretty=\"tformat:%f%d\" \\\n+\tgit -c log.excludeDecoration=\"*octopus*\" \\\n+\t    -c log.excludeDecoration=\"ORIG_HEAD\" \\\n+\t    log -n6 --decorate=short --pretty=\"tformat:%f%d\" \\\n \t\t--simplify-by-decoration >actual &&\n \ttest_cmp expect.decorate actual\n '\n@@ -1067,9 +1069,10 @@ test_expect_success 'decorate-refs and simplify-by-decoration without output' '\n \ttest_cmp expect actual\n '\n \n-test_expect_success 'decorate-refs-exclude HEAD' '\n+test_expect_success 'decorate-refs-exclude HEAD ORIG_HEAD' '\n \tgit log --decorate=full --oneline \\\n-\t\t--decorate-refs-exclude=\"HEAD\" >actual &&\n+\t\t--decorate-refs-exclude=\"HEAD\" \\\n+\t\t--decorate-refs-exclude=\"ORIG_HEAD\" >actual &&\n \t! grep HEAD actual\n '\n \n@@ -1082,7 +1085,7 @@ test_expect_success 'decorate-refs focus from default' '\n test_expect_success '--clear-decorations overrides defaults' '\n \tcat >expect.default <<-\\EOF &&\n \tMerge-tag-reach (HEAD -> refs/heads/main)\n-\tMerge-tags-octopus-a-and-octopus-b\n+\tMerge-tags-octopus-a-and-octopus-b (ORIG_HEAD)\n \tseventh (tag: refs/tags/seventh)\n \toctopus-b (tag: refs/tags/octopus-b, refs/heads/octopus-b)\n \toctopus-a (tag: refs/tags/octopus-a, refs/heads/octopus-a)\n@@ -1107,7 +1110,7 @@ test_expect_success '--clear-decorations overrides defaults' '\n \n \tcat >expect.all <<-\\EOF &&\n \tMerge-tag-reach (HEAD -> refs/heads/main)\n-\tMerge-tags-octopus-a-and-octopus-b\n+\tMerge-tags-octopus-a-and-octopus-b (ORIG_HEAD)\n \tseventh (tag: refs/tags/seventh)\n \toctopus-b (tag: refs/tags/octopus-b, refs/heads/octopus-b)\n \toctopus-a (tag: refs/tags/octopus-a, refs/heads/octopus-a)\n@@ -1139,7 +1142,7 @@ test_expect_success '--clear-decorations clears previous exclusions' '\n \tcat >expect.all <<-\\EOF &&\n \tMerge-tag-reach (HEAD -> refs/heads/main)\n \treach (tag: refs/tags/reach, refs/heads/reach)\n-\tMerge-tags-octopus-a-and-octopus-b\n+\tMerge-tags-octopus-a-and-octopus-b (ORIG_HEAD)\n \toctopus-b (tag: refs/tags/octopus-b, refs/heads/octopus-b)\n \toctopus-a (tag: refs/tags/octopus-a, refs/heads/octopus-a)\n \tseventh (tag: refs/tags/seventh)\ndiff --git a/t/t4207-log-decoration-colors.sh b/t/t4207-log-decoration-colors.sh\nindex 4b51e34f8b2..0b32e0bb8e9 100755\n--- a/t/t4207-log-decoration-colors.sh\n+++ b/t/t4207-log-decoration-colors.sh\n@@ -18,6 +18,7 @@ test_expect_success setup '\n \tgit config color.decorate.tag \"reverse bold yellow\" &&\n \tgit config color.decorate.stash magenta &&\n \tgit config color.decorate.ref blue &&\n+\tgit config color.decorate.pseudoref \"bold cyan\" &&\n \tgit config color.decorate.grafted black &&\n \tgit config color.decorate.symbol white &&\n \tgit config color.decorate.HEAD cyan &&\n@@ -30,6 +31,7 @@ test_expect_success setup '\n \tc_tag=\"<BOLD;REVERSE;YELLOW>\" &&\n \tc_stash=\"<MAGENTA>\" &&\n \tc_ref=\"<BLUE>\" &&\n+\tc_pseudoref=\"<BOLD;CYAN>\" &&\n \tc_HEAD=\"<CYAN>\" &&\n \tc_grafted=\"<BLACK>\" &&\n \tc_symbol=\"<WHITE>\" &&\n@@ -46,7 +48,10 @@ test_expect_success setup '\n \ttest_commit B &&\n \tgit tag v1.0 &&\n \techo >>A.t &&\n-\tgit stash save Changes to A.t\n+\tgit stash save Changes to A.t &&\n+\tgit reset other/main &&\n+\tgit reset ORIG_HEAD &&\n+\tgit revert --no-commit @~\n '\n \n cmp_filtered_decorations () {\n@@ -63,17 +68,19 @@ ${c_symbol} -> ${c_reset}${c_branch}main${c_reset}${c_symbol}, ${c_reset}\\\n ${c_tag}tag: ${c_reset}${c_tag}v1.0${c_reset}${c_symbol}, ${c_reset}\\\n ${c_tag}tag: ${c_reset}${c_tag}B${c_reset}${c_symbol})${c_reset} B\n ${c_commit}COMMIT_ID${c_reset}${c_symbol} (${c_reset}\\\n+${c_pseudoref}ORIG_HEAD${c_reset}${c_symbol}, ${c_reset}\\\n ${c_tag}tag: ${c_reset}${c_tag}A1${c_reset}${c_symbol}, ${c_reset}\\\n ${c_remoteBranch}other/main${c_reset}${c_symbol})${c_reset} A1\n \t${c_commit}COMMIT_ID${c_reset}${c_symbol} (${c_reset}\\\n ${c_stash}refs/stash${c_reset}${c_symbol})${c_reset} On main: Changes to A.t\n \t${c_commit}COMMIT_ID${c_reset}${c_symbol} (${c_reset}\\\n+${c_pseudoref}REVERT_HEAD${c_reset}${c_symbol}, ${c_reset}\\\n ${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_symbol}, ${c_reset}\\\n ${c_ref}refs/foo${c_reset}${c_symbol})${c_reset} A\n \tEOF\n \n-\tgit log --first-parent --no-abbrev --decorate --clear-decorations \\\n-\t\t--oneline --color=always --all >actual &&\n+\tgit log --first-parent --no-abbrev --decorate --color=always \\\n+\t\t--decorate-refs-exclude=FETCH_HEAD --oneline --all >actual &&\n \tcmp_filtered_decorations\n '\n \n-- \n2.42.GIT\n\n"},{"id":"483623","messageId":"xmqq1qdnseed.fsf@gitster.g","threadId":"60303","inReplyTo":"20231019193911.1669705-1-andy.koppe@gmail.com","subject":"Re: [PATCH 0/7] log: decorate pseudorefs and other refs","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-10-22T00:13:14Z","receivedAt":"2023-10-22T00:13:23Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Andy Koppe <andy.koppe@gmail.com> writes:\n\n> This patch series adds three slots to the color.decorate.<slot> config\n> option:\n> - 'symbol' for coloring the punctuation symbols used around the refs in\n>   decorations, which currently use the same color as the commit hash.\n> - 'ref' for coloring refs other than branches, remote-tracking branches,\n>   tags and the stash, which currently are not colored when included in\n>   decorations through custom decoration filter options.\n> - 'pseudoref' for coloring pseudorefs such as ORIG_HEAD or MERGE_HEAD.\n>   Include them in decorations by default.\n>\n> This series is to replace the 'decorate: add color.decorate.symbols\n> config option' patch proposed at:\n> https://lore.kernel.org/git/20231003205442.22963-1-andy.koppe@gmail.com\n\nIf that is the case, it probably would have been nicer to mark the\nseries as [PATCH v2].\n\nAlso, can you make messages [1/7]..[7/7] replies to [0/7] when you\nsend them out?  It seems that all 8 of them (including the cover\nletter) are replies to the previous round, which looked a bit\nunusual.\n\n\nAs to the contents of the series:\n\n [1/7] nicely lays out the color documentation; I do not think the\n       extra verbosity was absolutely needed for existing ones\n       (e.g., when a reader sees 'tag', the reader knows the color\n       will be applied to tags), but the more exotic ones the series\n       will be adding may deserve extra explanation on what they\n       are, so I guess it is OK.\n\n [2/7] is a trivial readability improvement.  It obviously should be\n       left outside the scope of this series, but we should notice\n       the same pattern in similar color tables (e.g., wt-status.c\n       has one, diff.c has another) and perform the same clean-up as\n       a #leftoverbits item.\n\n [3/7] They way _NIL color is used to control the defaulting looked\n       a bit unusual, but clever way to use a non-constant color\n       defined elsewhere as its default.  A similar trick is used in\n       wt-status.c:color() for STATUS_ONBRANCH, so this is nothing\n       new.\n\n [4/7] The name of new member .include added to ref_namespace_info\n       will not be understood by anybody unless they are too deeply\n       obsessed by decoration mechansim.  As the namespace_info\n       covers far wider interest, so a name that *shouts* that it is\n       about decoration filter must be used to be understood by\n       readers of the code.\n\n       To be quite honest, \"decoration filter\" is probably a name\n       that will not be understood by anybody, but coming up with a\n       better name for it is probably outside the scope of this\n       series.\n\n [5/7] I am not sure if \"other refs\" should be an item in the\n       namespace_info array.  If it is truly \"catch-all\", then\n       shouldn't the refs in other namespaces without their own\n       decoration (e.g. ones in refs/notes/ and refs/prefetch/) be\n       colored in the same way as this new class?  And if so, having\n       it as an independent element that sits next to these other\n       classes smells like a strange design.\n\n       Another more worrying thing is that existing .ref members are\n       designed to never overlap with each other, but this one\n       obviously does.  When a caller with a ref (or a pseudoref)\n       asks \"which namespace does this one belong to\", does the\n       existing code still do the right thing with this new element?\n       Without it, because there was no overlap, an implementation\n       can randomly search in the namespace_info table and stop at\n       the first hit, but now with the overlapping and widely open\n       .ref = \"refs/\", the implementation of the search must know\n       that it is a fallback position (i.e. if it found a match with\n       the fallback .ref = \"refs/\" , unless it looked at all other\n       entries that could begin with \"refs/\" and are more specific,\n       it needs to keep going).\n\n [6/7] This is pretty straight-forward, assuming that the existing\n       is_pseudoref_syntax() function does the right thing.  I am\n       not sure about that, though.  A refname with '-' is allowed\n       to be called a pseudoref???\n\n       Also, not a fault of this patch, but the \"_syntax\" in its\n       name is totally unnecessary, I would think.  At first glance,\n       I suspected that the excuse to append _syntax may have been\n       to signal the fact that the helper function does not check if\n       there actually is such a ref, but examining a few helpers\n       defined nearby tells us that such an excuse does not make\n       sense:\n\n           int is_per_worktree_ref(const char *) {\n\t\t   return starts_with(refname, \"refs/worktree/\") ||\n\t\t\t  starts_with(refname, \"refs/bisect/\") ||\n\t\t\t  starts_with(refname, \"refs/rewritten/\");\n\t   }\n           int is_pseudoref_syntax(const char *);\n           int is_current_worktree_ref(const char *ref) {\n                   return is_pseudoref_syntax(ref) || is_per_worktree_ref(ref);\n           }\n\n       All these three work on the refname and based on what is in\n       that refname string, decides what kind of ref it is.  There\n       is nothing especially \"syntax\" about the second one, and we\n       should rename it as part of #leftoverbits clean-up effort.\n\n       Another unrelated tangent is that is_per_worktree_ref() shown\n       above and the namespace_info array we saw earlier are not\n       even aware of each other, which is maintenance nightmare\n       waiting to happen.\n\n [7/7] Allowing pseudorefs to optionally used when decorating might\n       be a good idea, but I do not think it is particularly a good\n       design decision to enable it by default.  \n\n       Each of them forming a separate \"namespace\" also looks like a\n       poor design, as being able to group multiple things into one\n       family and treat them the same way is the primary point of\n       \"namespace\", I would think.  You do not want to say \"I want\n       to decorate off of ORIG_HEAD and FETCH_HEAD\"; instead you\n       would want to say \"I want to decorate off of any pseudoref\".\n\n\n"},{"id":"483639","messageId":"20231022214432.56325-2-andy.koppe@gmail.com","threadId":"60303","inReplyTo":"20231022214432.56325-1-andy.koppe@gmail.com","subject":"[PATCH v2 1/6] config: restructure color.decorate documentation","fromName":"Andy Koppe","fromEmail":"andy.koppe@gmail.com","sentAt":"2023-10-22T21:44:27Z","receivedAt":"2023-10-22T21:45:11Z","isPatch":true,"sender":{"key":"andy.koppe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/223411?v=4"},"body":"List color.decorate slots in git-config documentation one-by-one in the\nsame way as color.grep slots, to aid readability and make it easier to\nadd slots.\n\nSigned-off-by: Andy Koppe <andy.koppe@gmail.com>\n---\n Documentation/config/color.txt | 23 +++++++++++++++++++----\n 1 file changed, 19 insertions(+), 4 deletions(-)\n\ndiff --git a/Documentation/config/color.txt b/Documentation/config/color.txt\nindex 1795b2d16b..3453703f9b 100644\n--- a/Documentation/config/color.txt\n+++ b/Documentation/config/color.txt\n@@ -74,10 +74,25 @@ color.diff.<slot>::\n \t`oldBold`, and `newBold` (see linkgit:git-range-diff[1] for details).\n \n color.decorate.<slot>::\n-\tUse customized color for 'git log --decorate' output.  `<slot>` is one\n-\tof `branch`, `remoteBranch`, `tag`, `stash` or `HEAD` for local\n-\tbranches, remote-tracking branches, tags, stash and HEAD, respectively\n-\tand `grafted` for grafted commits.\n+\tUse customized color for the output of 'git log --decorate' as well as\n+\tthe `%d`, `%D` and `%(decorate)` placeholders in custom log formats,\n+\twhereby `<slot>` specifies which decoration elements the color applies\n+\tto:\n++\n+--\n+`HEAD`;;\n+\tthe current HEAD\n+`branch`;;\n+\tlocal branches\n+`remoteBranch`;;\n+\tremote-tracking branches\n+`tag`;;\n+\tlightweight and annotated tags\n+`stash`;;\n+\tthe stash ref\n+`grafted`;;\n+\tgrafted and replaced commits\n+--\n \n color.grep::\n \tWhen set to `always`, always highlight matches.  When `false` (or\n-- \n2.42.GIT\n\n"},{"id":"483640","messageId":"20231022214432.56325-1-andy.koppe@gmail.com","threadId":"60303","inReplyTo":"20231019193911.1669705-1-andy.koppe@gmail.com","subject":"[PATCH v2 0/6] log: decorate pseudorefs and other refs","fromName":"Andy Koppe","fromEmail":"andy.koppe@gmail.com","sentAt":"2023-10-22T21:44:26Z","receivedAt":"2023-10-22T21:45:11Z","isPatch":true,"sender":{"key":"andy.koppe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/223411?v=4"},"body":"This patch series implements decoration with pseudorefs and adds three\nslots to the color.decorate.<slot> config:\n- 'symbol' for coloring the punctuation symbols used around the refs in\n  decorations, which currently use the same color as the commit hash.\n- 'ref' for coloring refs other than branches, remote-tracking branches,\n  tags and the stash, which currently are not colored when included in\n  decorations through custom decoration filter options.\n- 'pseudoref' for coloring pseudorefs such as ORIG_HEAD or MERGE_HEAD.\n\nCI: https://github.com/ak2/git/actions/runs/6605893645\n\nAndy Koppe (6):\n  config: restructure color.decorate documentation\n  log: add color.decorate.symbol config variable\n  log: add color.decorate.ref config variable\n  refs: add pseudorefs array and iteration functions\n  refs: exempt pseudorefs from pattern prefixing\n  log: add color.decorate.pseudoref config variable\n\n Documentation/config/color.txt                | 32 +++++++-\n commit.h                                      |  3 +\n log-tree.c                                    | 43 +++++++++--\n refs.c                                        | 59 +++++++++++++--\n refs.h                                        |  5 ++\n ..._--decorate=full_--clear-decorations_--all |  4 +-\n ...f.log_--decorate_--clear-decorations_--all |  4 +-\n t/t4202-log.sh                                | 21 +++---\n t/t4207-log-decoration-colors.sh              | 74 +++++++++++--------\n 9 files changed, 185 insertions(+), 60 deletions(-)\n\n-- \n2.42.GIT\n\n"},{"id":"483641","messageId":"20231022214432.56325-3-andy.koppe@gmail.com","threadId":"60303","inReplyTo":"20231022214432.56325-1-andy.koppe@gmail.com","subject":"[PATCH v2 2/6] log: add color.decorate.symbol config variable","fromName":"Andy Koppe","fromEmail":"andy.koppe@gmail.com","sentAt":"2023-10-22T21:44:28Z","receivedAt":"2023-10-22T21:45:13Z","isPatch":true,"sender":{"key":"andy.koppe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/223411?v=4"},"body":"Add new color.decorate.symbol config variable for determining the\ncolor of the prefix, suffix, separator and pointer symbols used in\nlog --decorate output and related log format placeholders, to allow\nthem to be colored differently from commit hashes.\n\nFor backward compatibility, fall back to the commit hash color that can\nbe specified with the color.diff.commit variable if the new variable is\nnot provided.\n\nAdd the variable to the color.decorate.<slot> documentation.\n\nAmend t4207-log-decoration-colors.sh to test it. Put ${c_reset} elements\nin the expected output at the end of lines for consistency.\n\nSigned-off-by: Andy Koppe <andy.koppe@gmail.com>\n---\n Documentation/config/color.txt   |  2 ++\n commit.h                         |  1 +\n log-tree.c                       | 15 ++++++---\n t/t4207-log-decoration-colors.sh | 58 +++++++++++++++++---------------\n 4 files changed, 43 insertions(+), 33 deletions(-)\n\ndiff --git a/Documentation/config/color.txt b/Documentation/config/color.txt\nindex 3453703f9b..cc0a881125 100644\n--- a/Documentation/config/color.txt\n+++ b/Documentation/config/color.txt\n@@ -92,6 +92,8 @@ color.decorate.<slot>::\n \tthe stash ref\n `grafted`;;\n \tgrafted and replaced commits\n+`symbol`;;\n+\tpunctuation symbols surrounding the other elements\n --\n \n color.grep::\ndiff --git a/commit.h b/commit.h\nindex 28928833c5..cb13e4d5ba 100644\n--- a/commit.h\n+++ b/commit.h\n@@ -56,6 +56,7 @@ enum decoration_type {\n \tDECORATION_REF_STASH,\n \tDECORATION_REF_HEAD,\n \tDECORATION_GRAFTED,\n+\tDECORATION_SYMBOL,\n };\n \n void add_name_decoration(enum decoration_type type, const char *name, struct object *obj);\ndiff --git a/log-tree.c b/log-tree.c\nindex 504da6b519..5ad168458e 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -41,6 +41,7 @@ static char decoration_colors[][COLOR_MAXLEN] = {\n \tGIT_COLOR_BOLD_MAGENTA,\t/* REF_STASH */\n \tGIT_COLOR_BOLD_CYAN,\t/* REF_HEAD */\n \tGIT_COLOR_BOLD_BLUE,\t/* GRAFTED */\n+\tGIT_COLOR_NIL,\t\t/* SYMBOL */\n };\n \n static const char *color_decorate_slots[] = {\n@@ -50,6 +51,7 @@ static const char *color_decorate_slots[] = {\n \t[DECORATION_REF_STASH]\t= \"stash\",\n \t[DECORATION_REF_HEAD]\t= \"HEAD\",\n \t[DECORATION_GRAFTED]\t= \"grafted\",\n+\t[DECORATION_SYMBOL]\t= \"symbol\",\n };\n \n static const char *decorate_get_color(int decorate_use_color, enum decoration_type ix)\n@@ -312,7 +314,7 @@ void format_decorations(struct strbuf *sb,\n {\n \tconst struct name_decoration *decoration;\n \tconst struct name_decoration *current_and_HEAD;\n-\tconst char *color_commit, *color_reset;\n+\tconst char *color_symbol, *color_reset;\n \n \tconst char *prefix = \" (\";\n \tconst char *suffix = \")\";\n@@ -337,7 +339,10 @@ void format_decorations(struct strbuf *sb,\n \t\t\ttag = opts->tag;\n \t}\n \n-\tcolor_commit = diff_get_color(use_color, DIFF_COMMIT);\n+\tcolor_symbol = decorate_get_color(use_color, DECORATION_SYMBOL);\n+\tif (color_is_nil(color_symbol))\n+\t\tcolor_symbol = diff_get_color(use_color, DIFF_COMMIT);\n+\n \tcolor_reset = decorate_get_color(use_color, DECORATION_NONE);\n \n \tcurrent_and_HEAD = current_pointed_by_HEAD(decoration);\n@@ -352,7 +357,7 @@ void format_decorations(struct strbuf *sb,\n \t\t\t\tdecorate_get_color(use_color, decoration->type);\n \n \t\t\tif (*prefix) {\n-\t\t\t\tstrbuf_addstr(sb, color_commit);\n+\t\t\t\tstrbuf_addstr(sb, color_symbol);\n \t\t\t\tstrbuf_addstr(sb, prefix);\n \t\t\t\tstrbuf_addstr(sb, color_reset);\n \t\t\t}\n@@ -369,7 +374,7 @@ void format_decorations(struct strbuf *sb,\n \n \t\t\tif (current_and_HEAD &&\n \t\t\t    decoration->type == DECORATION_REF_HEAD) {\n-\t\t\t\tstrbuf_addstr(sb, color_commit);\n+\t\t\t\tstrbuf_addstr(sb, color_symbol);\n \t\t\t\tstrbuf_addstr(sb, pointer);\n \t\t\t\tstrbuf_addstr(sb, color_reset);\n \t\t\t\tstrbuf_addstr(sb, decorate_get_color(use_color, current_and_HEAD->type));\n@@ -382,7 +387,7 @@ void format_decorations(struct strbuf *sb,\n \t\tdecoration = decoration->next;\n \t}\n \tif (*suffix) {\n-\t\tstrbuf_addstr(sb, color_commit);\n+\t\tstrbuf_addstr(sb, color_symbol);\n \t\tstrbuf_addstr(sb, suffix);\n \t\tstrbuf_addstr(sb, color_reset);\n \t}\ndiff --git a/t/t4207-log-decoration-colors.sh b/t/t4207-log-decoration-colors.sh\nindex 21986a866d..f4173b6114 100755\n--- a/t/t4207-log-decoration-colors.sh\n+++ b/t/t4207-log-decoration-colors.sh\n@@ -18,6 +18,7 @@ test_expect_success setup '\n \tgit config color.decorate.tag \"reverse bold yellow\" &&\n \tgit config color.decorate.stash magenta &&\n \tgit config color.decorate.grafted black &&\n+\tgit config color.decorate.symbol white &&\n \tgit config color.decorate.HEAD cyan &&\n \n \tc_reset=\"<RESET>\" &&\n@@ -29,6 +30,7 @@ test_expect_success setup '\n \tc_stash=\"<MAGENTA>\" &&\n \tc_HEAD=\"<CYAN>\" &&\n \tc_grafted=\"<BLACK>\" &&\n+\tc_symbol=\"<WHITE>\" &&\n \n \ttest_commit A &&\n \tgit clone . other &&\n@@ -53,17 +55,17 @@ cmp_filtered_decorations () {\n # to this test since it does not contain any decoration, hence --first-parent\n test_expect_success 'commit decorations colored correctly' '\n \tcat >expect <<-EOF &&\n-\t${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_HEAD}HEAD${c_reset}\\\n-${c_commit} -> ${c_reset}${c_branch}main${c_reset}${c_commit}, \\\n-${c_reset}${c_tag}tag: ${c_reset}${c_tag}v1.0${c_reset}${c_commit}, \\\n-${c_reset}${c_tag}tag: ${c_reset}${c_tag}B${c_reset}${c_commit})${c_reset} B\n-${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\\\n-${c_tag}tag: ${c_reset}${c_tag}A1${c_reset}${c_commit}, \\\n-${c_reset}${c_remoteBranch}other/main${c_reset}${c_commit})${c_reset} A1\n-\t${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\\\n-${c_stash}refs/stash${c_reset}${c_commit})${c_reset} On main: Changes to A.t\n-\t${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\\\n-${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_commit})${c_reset} A\n+\t${c_commit}COMMIT_ID${c_reset}${c_symbol} (${c_reset}${c_HEAD}HEAD${c_reset}\\\n+${c_symbol} -> ${c_reset}${c_branch}main${c_reset}${c_symbol}, ${c_reset}\\\n+${c_tag}tag: ${c_reset}${c_tag}v1.0${c_reset}${c_symbol}, ${c_reset}\\\n+${c_tag}tag: ${c_reset}${c_tag}B${c_reset}${c_symbol})${c_reset} B\n+${c_commit}COMMIT_ID${c_reset}${c_symbol} (${c_reset}\\\n+${c_tag}tag: ${c_reset}${c_tag}A1${c_reset}${c_symbol}, ${c_reset}\\\n+${c_remoteBranch}other/main${c_reset}${c_symbol})${c_reset} A1\n+\t${c_commit}COMMIT_ID${c_reset}${c_symbol} (${c_reset}\\\n+${c_stash}refs/stash${c_reset}${c_symbol})${c_reset} On main: Changes to A.t\n+\t${c_commit}COMMIT_ID${c_reset}${c_symbol} (${c_reset}\\\n+${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_symbol})${c_reset} A\n \tEOF\n \n \tgit log --first-parent --no-abbrev --decorate --oneline --color=always --all >actual &&\n@@ -78,14 +80,14 @@ test_expect_success 'test coloring with replace-objects' '\n \tgit replace HEAD~1 HEAD~2 &&\n \n \tcat >expect <<-EOF &&\n-\t${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_HEAD}HEAD${c_reset}\\\n-${c_commit} -> ${c_reset}${c_branch}main${c_reset}${c_commit}, \\\n-${c_reset}${c_tag}tag: ${c_reset}${c_tag}D${c_reset}${c_commit})${c_reset} D\n-\t${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\\\n-${c_tag}tag: ${c_reset}${c_tag}C${c_reset}${c_commit}, \\\n-${c_reset}${c_grafted}replaced${c_reset}${c_commit})${c_reset} B\n-\t${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\\\n-${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_commit})${c_reset} A\n+\t${c_commit}COMMIT_ID${c_reset}${c_symbol} (${c_reset}${c_HEAD}HEAD${c_reset}\\\n+${c_symbol} -> ${c_reset}${c_branch}main${c_reset}${c_symbol}, ${c_reset}\\\n+${c_tag}tag: ${c_reset}${c_tag}D${c_reset}${c_symbol})${c_reset} D\n+\t${c_commit}COMMIT_ID${c_reset}${c_symbol} (${c_reset}\\\n+${c_tag}tag: ${c_reset}${c_tag}C${c_reset}${c_symbol}, ${c_reset}\\\n+${c_grafted}replaced${c_reset}${c_symbol})${c_reset} B\n+\t${c_commit}COMMIT_ID${c_reset}${c_symbol} (${c_reset}\\\n+${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_symbol})${c_reset} A\n EOF\n \n \tgit log --first-parent --no-abbrev --decorate --oneline --color=always HEAD >actual &&\n@@ -104,15 +106,15 @@ test_expect_success 'test coloring with grafted commit' '\n \tgit replace --graft HEAD HEAD~2 &&\n \n \tcat >expect <<-EOF &&\n-\t${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_HEAD}HEAD${c_reset}\\\n-${c_commit} -> ${c_reset}${c_branch}main${c_reset}${c_commit}, \\\n-${c_reset}${c_tag}tag: ${c_reset}${c_tag}D${c_reset}${c_commit}, \\\n-${c_reset}${c_grafted}replaced${c_reset}${c_commit})${c_reset} D\n-\t${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\\\n-${c_tag}tag: ${c_reset}${c_tag}v1.0${c_reset}${c_commit}, \\\n-${c_reset}${c_tag}tag: ${c_reset}${c_tag}B${c_reset}${c_commit})${c_reset} B\n-\t${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\\\n-${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_commit})${c_reset} A\n+\t${c_commit}COMMIT_ID${c_reset}${c_symbol} (${c_reset}${c_HEAD}HEAD${c_reset}\\\n+${c_symbol} -> ${c_reset}${c_branch}main${c_reset}${c_symbol}, ${c_reset}\\\n+${c_tag}tag: ${c_reset}${c_tag}D${c_reset}${c_symbol}, ${c_reset}\\\n+${c_grafted}replaced${c_reset}${c_symbol})${c_reset} D\n+\t${c_commit}COMMIT_ID${c_reset}${c_symbol} (${c_reset}\\\n+${c_tag}tag: ${c_reset}${c_tag}v1.0${c_reset}${c_symbol}, ${c_reset}\\\n+${c_tag}tag: ${c_reset}${c_tag}B${c_reset}${c_symbol})${c_reset} B\n+\t${c_commit}COMMIT_ID${c_reset}${c_symbol} (${c_reset}\\\n+${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_symbol})${c_reset} A\n \tEOF\n \n \tgit log --first-parent --no-abbrev --decorate --oneline --color=always HEAD >actual &&\n-- \n2.42.GIT\n\n"},{"id":"483642","messageId":"20231022214432.56325-4-andy.koppe@gmail.com","threadId":"60303","inReplyTo":"20231022214432.56325-1-andy.koppe@gmail.com","subject":"[PATCH v2 3/6] log: add color.decorate.ref config variable","fromName":"Andy Koppe","fromEmail":"andy.koppe@gmail.com","sentAt":"2023-10-22T21:44:29Z","receivedAt":"2023-10-22T21:45:13Z","isPatch":true,"sender":{"key":"andy.koppe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/223411?v=4"},"body":"Refs other than branches, remote-tracking branches, tags and the stash\ndo not appear in log decorations by default, but they can be shown by\nusing decoration filter options such as --clear-decorations or\nlog.initialDecorationSet. However, they would appear without color.\n\nAdd config variable color.decorate.ref for such refs, defaulting to bold\nmagenta, which is the same as refs/stash.\n\nDocument the new variable on the git-config page and amend\nt4207-log-decoration-colors.sh to test it.\n\nSigned-off-by: Andy Koppe <andy.koppe@gmail.com>\n---\n Documentation/config/color.txt   | 5 +++++\n commit.h                         | 1 +\n log-tree.c                       | 4 +++-\n t/t4207-log-decoration-colors.sh | 9 +++++++--\n 4 files changed, 16 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/config/color.txt b/Documentation/config/color.txt\nindex cc0a881125..005a2bdb03 100644\n--- a/Documentation/config/color.txt\n+++ b/Documentation/config/color.txt\n@@ -90,11 +90,16 @@ color.decorate.<slot>::\n \tlightweight and annotated tags\n `stash`;;\n \tthe stash ref\n+`ref`;;\n+\tany other refs (not shown by default)\n `grafted`;;\n \tgrafted and replaced commits\n `symbol`;;\n \tpunctuation symbols surrounding the other elements\n --\n++\n+(Variable `log.initialDecorationSet` or linkgit:git-log[1] option\n+`--clear-decorations` can be used to show all refs.)\n \n color.grep::\n \tWhen set to `always`, always highlight matches.  When `false` (or\ndiff --git a/commit.h b/commit.h\nindex cb13e4d5ba..f6b2125fc4 100644\n--- a/commit.h\n+++ b/commit.h\n@@ -54,6 +54,7 @@ enum decoration_type {\n \tDECORATION_REF_REMOTE,\n \tDECORATION_REF_TAG,\n \tDECORATION_REF_STASH,\n+\tDECORATION_REF,\n \tDECORATION_REF_HEAD,\n \tDECORATION_GRAFTED,\n \tDECORATION_SYMBOL,\ndiff --git a/log-tree.c b/log-tree.c\nindex 5ad168458e..36558f3008 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -39,6 +39,7 @@ static char decoration_colors[][COLOR_MAXLEN] = {\n \tGIT_COLOR_BOLD_RED,\t/* REF_REMOTE */\n \tGIT_COLOR_BOLD_YELLOW,\t/* REF_TAG */\n \tGIT_COLOR_BOLD_MAGENTA,\t/* REF_STASH */\n+\tGIT_COLOR_BOLD_MAGENTA, /* REF */\n \tGIT_COLOR_BOLD_CYAN,\t/* REF_HEAD */\n \tGIT_COLOR_BOLD_BLUE,\t/* GRAFTED */\n \tGIT_COLOR_NIL,\t\t/* SYMBOL */\n@@ -49,6 +50,7 @@ static const char *color_decorate_slots[] = {\n \t[DECORATION_REF_REMOTE] = \"remoteBranch\",\n \t[DECORATION_REF_TAG]\t= \"tag\",\n \t[DECORATION_REF_STASH]\t= \"stash\",\n+\t[DECORATION_REF]\t= \"ref\",\n \t[DECORATION_REF_HEAD]\t= \"HEAD\",\n \t[DECORATION_GRAFTED]\t= \"grafted\",\n \t[DECORATION_SYMBOL]\t= \"symbol\",\n@@ -151,7 +153,7 @@ static int add_ref_decoration(const char *refname, const struct object_id *oid,\n \tint i;\n \tstruct object *obj;\n \tenum object_type objtype;\n-\tenum decoration_type deco_type = DECORATION_NONE;\n+\tenum decoration_type deco_type = DECORATION_REF;\n \tstruct decoration_filter *filter = (struct decoration_filter *)cb_data;\n \tconst char *git_replace_ref_base = ref_namespace[NAMESPACE_REPLACE].ref;\n \ndiff --git a/t/t4207-log-decoration-colors.sh b/t/t4207-log-decoration-colors.sh\nindex f4173b6114..4b51e34f8b 100755\n--- a/t/t4207-log-decoration-colors.sh\n+++ b/t/t4207-log-decoration-colors.sh\n@@ -17,6 +17,7 @@ test_expect_success setup '\n \tgit config color.decorate.remoteBranch red &&\n \tgit config color.decorate.tag \"reverse bold yellow\" &&\n \tgit config color.decorate.stash magenta &&\n+\tgit config color.decorate.ref blue &&\n \tgit config color.decorate.grafted black &&\n \tgit config color.decorate.symbol white &&\n \tgit config color.decorate.HEAD cyan &&\n@@ -28,11 +29,13 @@ test_expect_success setup '\n \tc_remoteBranch=\"<RED>\" &&\n \tc_tag=\"<BOLD;REVERSE;YELLOW>\" &&\n \tc_stash=\"<MAGENTA>\" &&\n+\tc_ref=\"<BLUE>\" &&\n \tc_HEAD=\"<CYAN>\" &&\n \tc_grafted=\"<BLACK>\" &&\n \tc_symbol=\"<WHITE>\" &&\n \n \ttest_commit A &&\n+\tgit update-ref refs/foo A &&\n \tgit clone . other &&\n \t(\n \t\tcd other &&\n@@ -65,10 +68,12 @@ ${c_remoteBranch}other/main${c_reset}${c_symbol})${c_reset} A1\n \t${c_commit}COMMIT_ID${c_reset}${c_symbol} (${c_reset}\\\n ${c_stash}refs/stash${c_reset}${c_symbol})${c_reset} On main: Changes to A.t\n \t${c_commit}COMMIT_ID${c_reset}${c_symbol} (${c_reset}\\\n-${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_symbol})${c_reset} A\n+${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_symbol}, ${c_reset}\\\n+${c_ref}refs/foo${c_reset}${c_symbol})${c_reset} A\n \tEOF\n \n-\tgit log --first-parent --no-abbrev --decorate --oneline --color=always --all >actual &&\n+\tgit log --first-parent --no-abbrev --decorate --clear-decorations \\\n+\t\t--oneline --color=always --all >actual &&\n \tcmp_filtered_decorations\n '\n \n-- \n2.42.GIT\n\n"},{"id":"483644","messageId":"20231022214432.56325-5-andy.koppe@gmail.com","threadId":"60303","inReplyTo":"20231022214432.56325-1-andy.koppe@gmail.com","subject":"[PATCH v2 4/6] refs: add pseudorefs array and iteration functions","fromName":"Andy Koppe","fromEmail":"andy.koppe@gmail.com","sentAt":"2023-10-22T21:44:30Z","receivedAt":"2023-10-22T21:45:13Z","isPatch":true,"sender":{"key":"andy.koppe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/223411?v=4"},"body":"Define const array 'pseudorefs' with the names of the pseudorefs that\nare documented in gitrevisions.1, and add functions for_each_pseudoref()\nand refs_for_each_pseudoref() for iterating over them.\n\nThe functions process the pseudorefs in the same way as head_ref() and\nrefs_head_ref() process HEAD, invoking an each_ref_fn callback on each\npseudoref that exists.\n\nThis is in preparation for adding pseudorefs to log decorations.\n\nSigned-off-by: Andy Koppe <andy.koppe@gmail.com>\n---\n refs.c | 42 ++++++++++++++++++++++++++++++++++++++++++\n refs.h |  5 +++++\n 2 files changed, 47 insertions(+)\n\ndiff --git a/refs.c b/refs.c\nindex fcae5dddc6..aa7e4c02c5 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -65,6 +65,21 @@ static unsigned char refname_disposition[256] = {\n \t0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 4, 4\n };\n \n+/*\n+ * List of documented pseudorefs. This needs to be kept in sync with the list\n+ * in Documentation/revisions.txt.\n+ */\n+static const char *const pseudorefs[] = {\n+\t\"FETCH_HEAD\",\n+\t\"ORIG_HEAD\",\n+\t\"MERGE_HEAD\",\n+\t\"REBASE_HEAD\",\n+\t\"CHERRY_PICK_HEAD\",\n+\t\"REVERT_HEAD\",\n+\t\"BISECT_HEAD\",\n+\t\"AUTO_MERGE\",\n+};\n+\n struct ref_namespace_info ref_namespace[] = {\n \t[NAMESPACE_HEAD] = {\n \t\t.ref = \"HEAD\",\n@@ -1549,6 +1564,33 @@ int head_ref(each_ref_fn fn, void *cb_data)\n \treturn refs_head_ref(get_main_ref_store(the_repository), fn, cb_data);\n }\n \n+int refs_for_each_pseudoref(struct ref_store *refs,\n+\t\t\t    each_ref_fn fn, void *cb_data)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < ARRAY_SIZE(pseudorefs); i++) {\n+\t\tstruct object_id oid;\n+\t\tint flag;\n+\n+\t\tif (refs_resolve_ref_unsafe(refs, pseudorefs[i],\n+\t\t\t\t\t    RESOLVE_REF_READING, &oid, &flag)) {\n+\t\t\tint ret = fn(pseudorefs[i], &oid, flag, cb_data);\n+\n+\t\t\tif (ret)\n+\t\t\t\treturn ret;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+int for_each_pseudoref(each_ref_fn fn, void *cb_data)\n+{\n+\treturn refs_for_each_pseudoref(get_main_ref_store(the_repository),\n+\t\t\t\t       fn, cb_data);\n+}\n+\n struct ref_iterator *refs_ref_iterator_begin(\n \t\tstruct ref_store *refs,\n \t\tconst char *prefix,\ndiff --git a/refs.h b/refs.h\nindex 23211a5ea1..7b55cced31 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -320,6 +320,8 @@ typedef int each_repo_ref_fn(struct repository *r,\n  */\n int refs_head_ref(struct ref_store *refs,\n \t\t  each_ref_fn fn, void *cb_data);\n+int refs_for_each_pseudoref(struct ref_store *refs,\n+\t\t\t    each_ref_fn fn, void *cb_data);\n int refs_for_each_ref(struct ref_store *refs,\n \t\t      each_ref_fn fn, void *cb_data);\n int refs_for_each_ref_in(struct ref_store *refs, const char *prefix,\n@@ -334,6 +336,9 @@ int refs_for_each_remote_ref(struct ref_store *refs,\n /* just iterates the head ref. */\n int head_ref(each_ref_fn fn, void *cb_data);\n \n+/* iterates pseudorefs. */\n+int for_each_pseudoref(each_ref_fn fn, void *cb_data);\n+\n /* iterates all refs. */\n int for_each_ref(each_ref_fn fn, void *cb_data);\n \n-- \n2.42.GIT\n\n"},{"id":"483643","messageId":"20231022214432.56325-6-andy.koppe@gmail.com","threadId":"60303","inReplyTo":"20231022214432.56325-1-andy.koppe@gmail.com","subject":"[PATCH v2 5/6] refs: exempt pseudorefs from pattern prefixing","fromName":"Andy Koppe","fromEmail":"andy.koppe@gmail.com","sentAt":"2023-10-22T21:44:31Z","receivedAt":"2023-10-22T21:45:14Z","isPatch":true,"sender":{"key":"andy.koppe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/223411?v=4"},"body":"In normalize_glob_ref(), don't prefix pseudorefs with \"refs/\", thereby\nimplementing a NEEDSWORK from b877e617e6e5.\n\nThis is in preparation for showing pseudorefs in log decorations, as\nthey are not matched as intended in decoration filters otherwise. The\nfunction is only used in load_ref_decorations().\n\nSigned-off-by: Andy Koppe <andy.koppe@gmail.com>\n---\n refs.c | 17 ++++++++++-------\n 1 file changed, 10 insertions(+), 7 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex aa7e4c02c5..fbd15a8cff 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -565,13 +565,16 @@ void normalize_glob_ref(struct string_list_item *item, const char *prefix,\n \n \tif (prefix)\n \t\tstrbuf_addstr(&normalized_pattern, prefix);\n-\telse if (!starts_with(pattern, \"refs/\") &&\n-\t\t   strcmp(pattern, \"HEAD\"))\n-\t\tstrbuf_addstr(&normalized_pattern, \"refs/\");\n-\t/*\n-\t * NEEDSWORK: Special case other symrefs such as REBASE_HEAD,\n-\t * MERGE_HEAD, etc.\n-\t */\n+\telse if (!starts_with(pattern, \"refs/\") && strcmp(pattern, \"HEAD\")) {\n+\t\tint i;\n+\n+\t\tfor (i = 0; i < ARRAY_SIZE(pseudorefs); i++)\n+\t\t\tif (!strcmp(pattern, pseudorefs[i]))\n+\t\t\t\tbreak;\n+\n+\t\tif (i == ARRAY_SIZE(pseudorefs))\n+\t\t\tstrbuf_addstr(&normalized_pattern, \"refs/\");\n+\t}\n \n \tstrbuf_addstr(&normalized_pattern, pattern);\n \tstrbuf_strip_suffix(&normalized_pattern, \"/\");\n-- \n2.42.GIT\n\n"},{"id":"483645","messageId":"20231022214432.56325-7-andy.koppe@gmail.com","threadId":"60303","inReplyTo":"20231022214432.56325-1-andy.koppe@gmail.com","subject":"[PATCH v2 6/6] log: add color.decorate.pseudoref config variable","fromName":"Andy Koppe","fromEmail":"andy.koppe@gmail.com","sentAt":"2023-10-22T21:44:32Z","receivedAt":"2023-10-22T21:45:16Z","isPatch":true,"sender":{"key":"andy.koppe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/223411?v=4"},"body":"Add the ability to show pseudorefs in log decorations, and add config\nvariable color.decorate.pseudoref to determine their color. They will\nnot be shown unless the default decoration filtering is overridden with\nthe relevant log options such as --clear-decorations or\nlog.initialDecorationSet.\n\nSigned-off-by: Andy Koppe <andy.koppe@gmail.com>\n---\n Documentation/config/color.txt                |  4 +++-\n commit.h                                      |  1 +\n log-tree.c                                    | 24 +++++++++++++++++++\n ..._--decorate=full_--clear-decorations_--all |  4 ++--\n ...f.log_--decorate_--clear-decorations_--all |  4 ++--\n t/t4202-log.sh                                | 21 +++++++++-------\n t/t4207-log-decoration-colors.sh              | 13 +++++++---\n 7 files changed, 54 insertions(+), 17 deletions(-)\n\ndiff --git a/Documentation/config/color.txt b/Documentation/config/color.txt\nindex 005a2bdb03..7af7d65f76 100644\n--- a/Documentation/config/color.txt\n+++ b/Documentation/config/color.txt\n@@ -92,6 +92,8 @@ color.decorate.<slot>::\n \tthe stash ref\n `ref`;;\n \tany other refs (not shown by default)\n+`pseudoref`;;\n+\tpseudorefs such as ORIG_HEAD or MERGE_HEAD (not shown by default)\n `grafted`;;\n \tgrafted and replaced commits\n `symbol`;;\n@@ -99,7 +101,7 @@ color.decorate.<slot>::\n --\n +\n (Variable `log.initialDecorationSet` or linkgit:git-log[1] option\n-`--clear-decorations` can be used to show all refs.)\n+`--clear-decorations` can be used to show all refs and pseudorefs.)\n \n color.grep::\n \tWhen set to `always`, always highlight matches.  When `false` (or\ndiff --git a/commit.h b/commit.h\nindex f6b2125fc4..44dd3ce19b 100644\n--- a/commit.h\n+++ b/commit.h\n@@ -56,6 +56,7 @@ enum decoration_type {\n \tDECORATION_REF_STASH,\n \tDECORATION_REF,\n \tDECORATION_REF_HEAD,\n+\tDECORATION_REF_PSEUDO,\n \tDECORATION_GRAFTED,\n \tDECORATION_SYMBOL,\n };\ndiff --git a/log-tree.c b/log-tree.c\nindex 36558f3008..4091b55532 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -41,6 +41,7 @@ static char decoration_colors[][COLOR_MAXLEN] = {\n \tGIT_COLOR_BOLD_MAGENTA,\t/* REF_STASH */\n \tGIT_COLOR_BOLD_MAGENTA, /* REF */\n \tGIT_COLOR_BOLD_CYAN,\t/* REF_HEAD */\n+\tGIT_COLOR_BOLD_BLUE,\t/* REF_PSEUDO */\n \tGIT_COLOR_BOLD_BLUE,\t/* GRAFTED */\n \tGIT_COLOR_NIL,\t\t/* SYMBOL */\n };\n@@ -52,6 +53,7 @@ static const char *color_decorate_slots[] = {\n \t[DECORATION_REF_STASH]\t= \"stash\",\n \t[DECORATION_REF]\t= \"ref\",\n \t[DECORATION_REF_HEAD]\t= \"HEAD\",\n+\t[DECORATION_REF_PSEUDO]\t= \"pseudoref\",\n \t[DECORATION_GRAFTED]\t= \"grafted\",\n \t[DECORATION_SYMBOL]\t= \"symbol\",\n };\n@@ -208,6 +210,27 @@ static int add_ref_decoration(const char *refname, const struct object_id *oid,\n \treturn 0;\n }\n \n+static int add_pseudoref_decoration(const char *refname,\n+\t\t\t\t    const struct object_id *oid,\n+\t\t\t\t    int flags UNUSED,\n+\t\t\t\t    void *cb_data)\n+{\n+\tstruct object *obj;\n+\tenum object_type objtype;\n+\tstruct decoration_filter *filter = (struct decoration_filter *)cb_data;\n+\n+\tif (filter && !ref_filter_match(refname, filter))\n+\t\treturn 0;\n+\n+\tobjtype = oid_object_info(the_repository, oid, NULL);\n+\tif (objtype < 0)\n+\t\treturn 0;\n+\n+\tobj = lookup_object_by_type(the_repository, oid, objtype);\n+\tadd_name_decoration(DECORATION_REF_PSEUDO, refname, obj);\n+\treturn 0;\n+}\n+\n static int add_graft_decoration(const struct commit_graft *graft,\n \t\t\t\tvoid *cb_data UNUSED)\n {\n@@ -236,6 +259,7 @@ void load_ref_decorations(struct decoration_filter *filter, int flags)\n \t\tdecoration_loaded = 1;\n \t\tdecoration_flags = flags;\n \t\tfor_each_ref(add_ref_decoration, filter);\n+\t\tfor_each_pseudoref(add_pseudoref_decoration, filter);\n \t\thead_ref(add_ref_decoration, filter);\n \t\tfor_each_commit_graft(add_graft_decoration, filter);\n \t}\ndiff --git a/t/t4013/diff.log_--decorate=full_--clear-decorations_--all b/t/t4013/diff.log_--decorate=full_--clear-decorations_--all\nindex 1c030a6554..7d16978e7f 100644\n--- a/t/t4013/diff.log_--decorate=full_--clear-decorations_--all\n+++ b/t/t4013/diff.log_--decorate=full_--clear-decorations_--all\n@@ -33,13 +33,13 @@ Date:   Mon Jun 26 00:04:00 2006 +0000\n \n     Merge branch 'side'\n \n-commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a (refs/heads/side)\n+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a (FETCH_HEAD, refs/heads/side)\n Author: A U Thor <author@example.com>\n Date:   Mon Jun 26 00:03:00 2006 +0000\n \n     Side\n \n-commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0\n+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 (ORIG_HEAD)\n Author: A U Thor <author@example.com>\n Date:   Mon Jun 26 00:02:00 2006 +0000\n \ndiff --git a/t/t4013/diff.log_--decorate_--clear-decorations_--all b/t/t4013/diff.log_--decorate_--clear-decorations_--all\nindex 88be82cce3..4f9be50ce0 100644\n--- a/t/t4013/diff.log_--decorate_--clear-decorations_--all\n+++ b/t/t4013/diff.log_--decorate_--clear-decorations_--all\n@@ -33,13 +33,13 @@ Date:   Mon Jun 26 00:04:00 2006 +0000\n \n     Merge branch 'side'\n \n-commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a (side)\n+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a (FETCH_HEAD, side)\n Author: A U Thor <author@example.com>\n Date:   Mon Jun 26 00:03:00 2006 +0000\n \n     Side\n \n-commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0\n+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 (ORIG_HEAD)\n Author: A U Thor <author@example.com>\n Date:   Mon Jun 26 00:02:00 2006 +0000\n \ndiff --git a/t/t4202-log.sh b/t/t4202-log.sh\nindex af4a123cd2..b14da62e3e 100755\n--- a/t/t4202-log.sh\n+++ b/t/t4202-log.sh\n@@ -927,7 +927,7 @@ test_expect_success 'multiple decorate-refs' '\n test_expect_success 'decorate-refs-exclude with glob' '\n \tcat >expect.decorate <<-\\EOF &&\n \tMerge-tag-reach (HEAD -> main)\n-\tMerge-tags-octopus-a-and-octopus-b\n+\tMerge-tags-octopus-a-and-octopus-b (ORIG_HEAD)\n \tseventh (tag: seventh)\n \toctopus-b (tag: octopus-b)\n \toctopus-a (tag: octopus-a)\n@@ -944,7 +944,7 @@ test_expect_success 'decorate-refs-exclude with glob' '\n test_expect_success 'decorate-refs-exclude without globs' '\n \tcat >expect.decorate <<-\\EOF &&\n \tMerge-tag-reach (HEAD -> main)\n-\tMerge-tags-octopus-a-and-octopus-b\n+\tMerge-tags-octopus-a-and-octopus-b (ORIG_HEAD)\n \tseventh (tag: seventh)\n \toctopus-b (tag: octopus-b, octopus-b)\n \toctopus-a (tag: octopus-a, octopus-a)\n@@ -961,7 +961,7 @@ test_expect_success 'decorate-refs-exclude without globs' '\n test_expect_success 'multiple decorate-refs-exclude' '\n \tcat >expect.decorate <<-\\EOF &&\n \tMerge-tag-reach (HEAD -> main)\n-\tMerge-tags-octopus-a-and-octopus-b\n+\tMerge-tags-octopus-a-and-octopus-b (ORIG_HEAD)\n \tseventh (tag: seventh)\n \toctopus-b (tag: octopus-b)\n \toctopus-a (tag: octopus-a)\n@@ -1022,10 +1022,12 @@ test_expect_success 'decorate-refs-exclude and simplify-by-decoration' '\n \tEOF\n \tgit log -n6 --decorate=short --pretty=\"tformat:%f%d\" \\\n \t\t--decorate-refs-exclude=\"*octopus*\" \\\n+\t\t--decorate-refs-exclude=\"ORIG_HEAD\" \\\n \t\t--simplify-by-decoration >actual &&\n \ttest_cmp expect.decorate actual &&\n-\tgit -c log.excludeDecoration=\"*octopus*\" log \\\n-\t\t-n6 --decorate=short --pretty=\"tformat:%f%d\" \\\n+\tgit -c log.excludeDecoration=\"*octopus*\" \\\n+\t    -c log.excludeDecoration=\"ORIG_HEAD\" \\\n+\t    log -n6 --decorate=short --pretty=\"tformat:%f%d\" \\\n \t\t--simplify-by-decoration >actual &&\n \ttest_cmp expect.decorate actual\n '\n@@ -1067,9 +1069,10 @@ test_expect_success 'decorate-refs and simplify-by-decoration without output' '\n \ttest_cmp expect actual\n '\n \n-test_expect_success 'decorate-refs-exclude HEAD' '\n+test_expect_success 'decorate-refs-exclude HEAD ORIG_HEAD' '\n \tgit log --decorate=full --oneline \\\n-\t\t--decorate-refs-exclude=\"HEAD\" >actual &&\n+\t\t--decorate-refs-exclude=\"HEAD\" \\\n+\t\t--decorate-refs-exclude=\"ORIG_HEAD\" >actual &&\n \t! grep HEAD actual\n '\n \n@@ -1107,7 +1110,7 @@ test_expect_success '--clear-decorations overrides defaults' '\n \n \tcat >expect.all <<-\\EOF &&\n \tMerge-tag-reach (HEAD -> refs/heads/main)\n-\tMerge-tags-octopus-a-and-octopus-b\n+\tMerge-tags-octopus-a-and-octopus-b (ORIG_HEAD)\n \tseventh (tag: refs/tags/seventh)\n \toctopus-b (tag: refs/tags/octopus-b, refs/heads/octopus-b)\n \toctopus-a (tag: refs/tags/octopus-a, refs/heads/octopus-a)\n@@ -1139,7 +1142,7 @@ test_expect_success '--clear-decorations clears previous exclusions' '\n \tcat >expect.all <<-\\EOF &&\n \tMerge-tag-reach (HEAD -> refs/heads/main)\n \treach (tag: refs/tags/reach, refs/heads/reach)\n-\tMerge-tags-octopus-a-and-octopus-b\n+\tMerge-tags-octopus-a-and-octopus-b (ORIG_HEAD)\n \toctopus-b (tag: refs/tags/octopus-b, refs/heads/octopus-b)\n \toctopus-a (tag: refs/tags/octopus-a, refs/heads/octopus-a)\n \tseventh (tag: refs/tags/seventh)\ndiff --git a/t/t4207-log-decoration-colors.sh b/t/t4207-log-decoration-colors.sh\nindex 4b51e34f8b..0b32e0bb8e 100755\n--- a/t/t4207-log-decoration-colors.sh\n+++ b/t/t4207-log-decoration-colors.sh\n@@ -18,6 +18,7 @@ test_expect_success setup '\n \tgit config color.decorate.tag \"reverse bold yellow\" &&\n \tgit config color.decorate.stash magenta &&\n \tgit config color.decorate.ref blue &&\n+\tgit config color.decorate.pseudoref \"bold cyan\" &&\n \tgit config color.decorate.grafted black &&\n \tgit config color.decorate.symbol white &&\n \tgit config color.decorate.HEAD cyan &&\n@@ -30,6 +31,7 @@ test_expect_success setup '\n \tc_tag=\"<BOLD;REVERSE;YELLOW>\" &&\n \tc_stash=\"<MAGENTA>\" &&\n \tc_ref=\"<BLUE>\" &&\n+\tc_pseudoref=\"<BOLD;CYAN>\" &&\n \tc_HEAD=\"<CYAN>\" &&\n \tc_grafted=\"<BLACK>\" &&\n \tc_symbol=\"<WHITE>\" &&\n@@ -46,7 +48,10 @@ test_expect_success setup '\n \ttest_commit B &&\n \tgit tag v1.0 &&\n \techo >>A.t &&\n-\tgit stash save Changes to A.t\n+\tgit stash save Changes to A.t &&\n+\tgit reset other/main &&\n+\tgit reset ORIG_HEAD &&\n+\tgit revert --no-commit @~\n '\n \n cmp_filtered_decorations () {\n@@ -63,17 +68,19 @@ ${c_symbol} -> ${c_reset}${c_branch}main${c_reset}${c_symbol}, ${c_reset}\\\n ${c_tag}tag: ${c_reset}${c_tag}v1.0${c_reset}${c_symbol}, ${c_reset}\\\n ${c_tag}tag: ${c_reset}${c_tag}B${c_reset}${c_symbol})${c_reset} B\n ${c_commit}COMMIT_ID${c_reset}${c_symbol} (${c_reset}\\\n+${c_pseudoref}ORIG_HEAD${c_reset}${c_symbol}, ${c_reset}\\\n ${c_tag}tag: ${c_reset}${c_tag}A1${c_reset}${c_symbol}, ${c_reset}\\\n ${c_remoteBranch}other/main${c_reset}${c_symbol})${c_reset} A1\n \t${c_commit}COMMIT_ID${c_reset}${c_symbol} (${c_reset}\\\n ${c_stash}refs/stash${c_reset}${c_symbol})${c_reset} On main: Changes to A.t\n \t${c_commit}COMMIT_ID${c_reset}${c_symbol} (${c_reset}\\\n+${c_pseudoref}REVERT_HEAD${c_reset}${c_symbol}, ${c_reset}\\\n ${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_symbol}, ${c_reset}\\\n ${c_ref}refs/foo${c_reset}${c_symbol})${c_reset} A\n \tEOF\n \n-\tgit log --first-parent --no-abbrev --decorate --clear-decorations \\\n-\t\t--oneline --color=always --all >actual &&\n+\tgit log --first-parent --no-abbrev --decorate --color=always \\\n+\t\t--decorate-refs-exclude=FETCH_HEAD --oneline --all >actual &&\n \tcmp_filtered_decorations\n '\n \n-- \n2.42.GIT\n\n"},{"id":"483646","messageId":"fe3abed8-6be0-4d77-9057-79c9b7c0795c@gmail.com","threadId":"60303","inReplyTo":"xmqq1qdnseed.fsf@gitster.g","subject":"Re: [PATCH 0/7] log: decorate pseudorefs and other refs","fromName":"Andy Koppe","fromEmail":"andy.koppe@gmail.com","sentAt":"2023-10-22T21:49:48Z","receivedAt":"2023-10-22T21:49:53Z","isPatch":true,"sender":{"key":"andy.koppe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/223411?v=4"},"body":"On 22/10/2023 01:13, Junio C Hamano wrote:\n> Andy Koppe <andy.koppe@gmail.com> writes:\n>> This series is to replace the 'decorate: add color.decorate.symbols\n>> config option' patch proposed at:\n>> https://lore.kernel.org/git/20231003205442.22963-1-andy.koppe@gmail.com\n> \n> If that is the case, it probably would have been nicer to mark the\n> series as [PATCH v2].\n\nThanks, I wasn't sure about that due to the change in title and increase \nin scope. I shall err towards version-bumping in any future such cases.\n\n> Also, can you make messages [1/7]..[7/7] replies to [0/7] when you\n> send them out?  It seems that all 8 of them (including the cover\n> letter) are replies to the previous round, which looked a bit\n> unusual.\n\nNot quite sure how that happened, but I think my mistake was passing \n--in-reply-to to git-format-patch instead of git-send-email.\n\n>   [2/7] is a trivial readability improvement.  It obviously should be\n>         left outside the scope of this series, but we should notice\n>         the same pattern in similar color tables (e.g., wt-status.c\n>         has one, diff.c has another) and perform the same clean-up as\n>         a #leftoverbits item.\n\nOkay, I've removed that commit in v2. (I should have mentioned in the \ncommit message that it was triggered by the inconsistency with the \nimmediately following color_decorate_slots array, which uses designated \ninitializers.)\n\n>   [4/7] The name of new member .include added to ref_namespace_info\n>         will not be understood by anybody unless they are too deeply\n>         obsessed by decoration mechansim.  As the namespace_info\n>         covers far wider interest, so a name that *shouts* that it is\n>         about decoration filter must be used to be understood by\n>         readers of the code\n\nAgreed.\n\n>   [5/7] I am not sure if \"other refs\" should be an item in the\n>         namespace_info array.  If it is truly \"catch-all\", then\n>         shouldn't the refs in other namespaces without their own\n>         decoration (e.g. ones in refs/notes/ and refs/prefetch/) be\n>         colored in the same way as this new class?\n\nThey would, because add_ref_decoration() skips ref_namespace entries \nwithout a decoration type, so they would fall through to \"refs/\" and \npick up the DECORATION_REF type.\n\n>         And if so, having\n>         it as an independent element that sits next to these other\n>         classes smells like a strange design. >\n>         Another more worrying thing is that existing .ref members are\n>         designed to never overlap with each other, but this one\n>         obviously does.  When a caller with a ref (or a pseudoref)\n>         asks \"which namespace does this one belong to\", does the\n>         existing code still do the right thing with this new element?\n>         Without it, because there was no overlap, an implementation\n>         can randomly search in the namespace_info table and stop at\n>         the first hit, but now with the overlapping and widely open\n>         .ref = \"refs/\", the implementation of the search must know\n>         that it is a fallback position (i.e. if it found a match with\n>         the fallback .ref = \"refs/\" , unless it looked at all other\n>         entries that could begin with \"refs/\" and are more specific,\n>         it needs to keep going).\n\nFair points. I've rewritten things to not touch the ref_namespace array.\n>   [6/7] This is pretty straight-forward, assuming that the existing\n>         is_pseudoref_syntax() function does the right thing.  I am\n>         not sure about that, though.  A refname with '-' is allowed\n>         to be called a pseudoref???\n> \n>         Also, not a fault of this patch, but the \"_syntax\" in its\n>         name is totally unnecessary, I would think.  At first glance,\n>         I suspected that the excuse to append _syntax may have been\n>         to signal the fact that the helper function does not check if\n>         there actually is such a ref, but examining a few helpers\n>         defined nearby tells us that such an excuse does not make\n>         sense:\n\nI've dropped the use of that function from the change, checking against \nthe actual pseudoref names instead.\n\n>   [7/7] Allowing pseudorefs to optionally used when decorating might\n>         be a good idea, but I do not think it is particularly a good\n>         design decision to enable it by default.\n\nOkay!\n\n>         Each of them forming a separate \"namespace\" also looks like a\n>         poor design, as being able to group multiple things into one\n>         family and treat them the same way is the primary point of\n>         \"namespace\", I would think.\n\nFair enough, although the array already contains HEAD and refs/stash as \nsingletons. I had vacillated about shoe-horning the pseudorefs in there, \nand was swayed by having a single place to define which (pseudo)refs \nshould be included in decorations by default. That motivation goes away \nwith all the pseudorefs off by default.\n\nI've rewritten things to handle the pseudorefs separately from the \nref_namespace array, with iteration functions similar to the ones used \nfor HEAD and proper refs.\n\n >         You do not want to say \"I want\n >         to decorate off of ORIG_HEAD and FETCH_HEAD\"; instead you\n >         would want to say \"I want to decorate off of any pseudoref\".\n\nThey can now all be enabled with --clear-decorations or \nlog.initialDecorationSet=all, or be controlled individually with the \nother filter options.\n\nThank you very much for the review!\nAndy\n"},{"id":"483648","messageId":"xmqqpm16p4t3.fsf@gitster.g","threadId":"60303","inReplyTo":"fe3abed8-6be0-4d77-9057-79c9b7c0795c@gmail.com","subject":"Re: [PATCH 0/7] log: decorate pseudorefs and other refs","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-10-23T00:20:56Z","receivedAt":"2023-10-23T00:21:07Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Andy Koppe <andy.koppe@gmail.com> writes:\n\n>>   [2/7] is a trivial readability improvement.  It obviously should be\n>>         left outside the scope of this series, but we should notice\n>>         the same pattern in similar color tables (e.g., wt-status.c\n>>         has one, diff.c has another) and perform the same clean-up as\n>>         a #leftoverbits item.\n>\n> Okay, I've removed that commit in v2. (I should have mentioned in the\n> commit message that it was triggered by the inconsistency with the\n> immediately following color_decorate_slots array, which uses\n> designated initializers.)\n\nSorry, that is not what I meant.  [2/7] as a preliminary clean-up to\nwork in the same area does make very much sense.  What I meant to be\n\"outside the scope\" was to make similar fixes to other color tables\nthat this series does not care about.\n\n>>         .ref = \"refs/\", the implementation of the search must know\n>>         that it is a fallback position (i.e. if it found a match with\n>>         the fallback .ref = \"refs/\" , unless it looked at all other\n>>         entries that could begin with \"refs/\" and are more specific,\n>>         it needs to keep going).\n>\n> Fair points. I've rewritten things to not touch the ref_namespace array.\n\nWell, the namespace_info mechanism still may be a good place to have\nthe necessary information; it may be that the current implementation\ndetail of how a given ref is classified to one of the namespaces is\ntoo limiting---it essentially allows the string match with the .ref\nmember.  But we can imagine that it could be extended a bit, e.g.\n\n\tstruct ref_namespace_info {\n\t\tchar *ref;\n\t\tint (*membership)(const char *, const struct ref_namespace_info *);\n\t\t... other members ...;\n\t};\n\nwhere the .membership member is used in add_ref_decoration() to\ndetermine the membership of a given \"refname\" to the namespace \"i\"\nperhaps like so:\n\n\tstruct ref_namespace_info *info = &ref_namespace[i];\n\n\tif (!info->decoration)\n\t\tcontinue;\n+\tif (info->membership) {\n+\t\tif (info->membership(refname, info)) {\n+\t\t\tdeco_type = info->decoration;\n+\t\t\tbreak;\n+\t\t}\n+\t} else if (info->exact) {\n-\tif (info->exact) {\n\t\tif (!strcmp(refname, info->ref)) {\n\t\t\tdeco_type = info_decoration;\n\t\t\tbreak;\n\t}\n\nThen you can arrange the pseudoref class to use .membership function\nperhaps like this:\n\n\tstatic int pseudoref_namespace_membership(\n\t\tconst char *refname, const struct ref_namespace_info *info UNUSED\n\t)\n\t{\n\t\treturn is_pseudoref(refname);\n\t}\n\nand make them all into a single class.\n\nWhat I called a bad design was to reuse the namespace_info code\nwithout extending it to suit our needs.\n\nThis comment will probably affect everything below.\n\n>>   [6/7] This is pretty straight-forward, assuming that the existing\n>>         is_pseudoref_syntax() function does the right thing.  I am\n>>         not sure about that, though.  A refname with '-' is allowed\n>>         to be called a pseudoref???\n>>         Also, not a fault of this patch, but the \"_syntax\" in its\n>>         name is totally unnecessary, I would think.  At first glance,\n>>         I suspected that the excuse to append _syntax may have been\n>>         to signal the fact that the helper function does not check if\n>>         there actually is such a ref, but examining a few helpers\n>>         defined nearby tells us that such an excuse does not make\n>>         sense:\n>\n> I've dropped the use of that function from the change, checking\n> against the actual pseudoref names instead.\n>\n>>   [7/7] Allowing pseudorefs to optionally used when decorating might\n>>         be a good idea, but I do not think it is particularly a good\n>>         design decision to enable it by default.\n>\n> Okay!\n>\n>>         Each of them forming a separate \"namespace\" also looks like a\n>>         poor design, as being able to group multiple things into one\n>>         family and treat them the same way is the primary point of\n>>         \"namespace\", I would think.\n>\n> Fair enough, although the array already contains HEAD and refs/stash\n> as singletons.\n\nBut these deserve to be singletons, don't they?  There is no other\nthing that behaves like HEAD; there is no other thing that behaves\nlike stash; and they do not behave like each other.\n\nHaving said that, I do not think it makes much sense to decorate a\ncommit off of refs/stash, as the true richeness of the stash is not\nin its history but in its reflog, which the decoration code does not\ndig into.  But obviously it is not a part of the topic we are\ndiscussing (unless, of course, we are not \"adding\" new decoration\nsources and colors, but we are improving the decoration sources and\ncolors by adding new useful ones while retiring existing useless\nones).\n\nThanks.\n"},{"id":"483732","messageId":"20231023221143.72489-1-andy.koppe@gmail.com","threadId":"60303","inReplyTo":"20231022214432.56325-1-andy.koppe@gmail.com","subject":"[PATCH v3 0/7] log: decorate pseudorefs and other refs","fromName":"Andy Koppe","fromEmail":"andy.koppe@gmail.com","sentAt":"2023-10-23T22:11:36Z","receivedAt":"2023-10-23T22:11:59Z","isPatch":true,"sender":{"key":"andy.koppe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/223411?v=4"},"body":"This patch series implements decoration with pseudorefs and adds three\nslots to the color.decorate.<slot> config:\n- 'symbol' for coloring the punctuation symbols used around the refs in\n  decorations, which currently use the same color as the commit hash.\n- 'ref' for coloring refs other than branches, remote-tracking branches,\n  tags and the stash, which currently are not colored when included in\n  decorations through custom decoration filter options.\n- 'pseudoref' for coloring pseudorefs such as ORIG_HEAD or MERGE_HEAD.\n\nCI: https://github.com/ak2/git/actions/runs/6618230811\n\nAndy Koppe (7):\n  config: restructure color.decorate documentation\n  log: use designated inits for decoration_colors\n  log: add color.decorate.symbol config variable\n  log: add color.decorate.ref config variable\n  refs: add pseudorefs array and iteration functions\n  refs: exempt pseudorefs from pattern prefixing\n  log: add color.decorate.pseudoref config variable\n\n Documentation/config/color.txt                | 32 +++++++-\n commit.h                                      |  3 +\n log-tree.c                                    | 57 ++++++++++----\n refs.c                                        | 59 +++++++++++++--\n refs.h                                        |  5 ++\n ..._--decorate=full_--clear-decorations_--all |  4 +-\n ...f.log_--decorate_--clear-decorations_--all |  4 +-\n t/t4202-log.sh                                | 21 +++---\n t/t4207-log-decoration-colors.sh              | 74 +++++++++++--------\n 9 files changed, 192 insertions(+), 67 deletions(-)\n\n-- \n2.42.GIT\n\n"},{"id":"483733","messageId":"20231023221143.72489-2-andy.koppe@gmail.com","threadId":"60303","inReplyTo":"20231023221143.72489-1-andy.koppe@gmail.com","subject":"[PATCH v3 1/7] config: restructure color.decorate documentation","fromName":"Andy Koppe","fromEmail":"andy.koppe@gmail.com","sentAt":"2023-10-23T22:11:37Z","receivedAt":"2023-10-23T22:11:59Z","isPatch":true,"sender":{"key":"andy.koppe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/223411?v=4"},"body":"List color.decorate slots in git-config documentation one-by-one in the\nsame way as color.grep slots, to aid readability and make it easier to\nadd slots.\n\nSigned-off-by: Andy Koppe <andy.koppe@gmail.com>\n---\n Documentation/config/color.txt | 23 +++++++++++++++++++----\n 1 file changed, 19 insertions(+), 4 deletions(-)\n\ndiff --git a/Documentation/config/color.txt b/Documentation/config/color.txt\nindex 1795b2d16b..3453703f9b 100644\n--- a/Documentation/config/color.txt\n+++ b/Documentation/config/color.txt\n@@ -74,10 +74,25 @@ color.diff.<slot>::\n \t`oldBold`, and `newBold` (see linkgit:git-range-diff[1] for details).\n \n color.decorate.<slot>::\n-\tUse customized color for 'git log --decorate' output.  `<slot>` is one\n-\tof `branch`, `remoteBranch`, `tag`, `stash` or `HEAD` for local\n-\tbranches, remote-tracking branches, tags, stash and HEAD, respectively\n-\tand `grafted` for grafted commits.\n+\tUse customized color for the output of 'git log --decorate' as well as\n+\tthe `%d`, `%D` and `%(decorate)` placeholders in custom log formats,\n+\twhereby `<slot>` specifies which decoration elements the color applies\n+\tto:\n++\n+--\n+`HEAD`;;\n+\tthe current HEAD\n+`branch`;;\n+\tlocal branches\n+`remoteBranch`;;\n+\tremote-tracking branches\n+`tag`;;\n+\tlightweight and annotated tags\n+`stash`;;\n+\tthe stash ref\n+`grafted`;;\n+\tgrafted and replaced commits\n+--\n \n color.grep::\n \tWhen set to `always`, always highlight matches.  When `false` (or\n-- \n2.42.GIT\n\n"},{"id":"483734","messageId":"20231023221143.72489-3-andy.koppe@gmail.com","threadId":"60303","inReplyTo":"20231023221143.72489-1-andy.koppe@gmail.com","subject":"[PATCH v3 2/7] log: use designated inits for decoration_colors","fromName":"Andy Koppe","fromEmail":"andy.koppe@gmail.com","sentAt":"2023-10-23T22:11:38Z","receivedAt":"2023-10-23T22:12:00Z","isPatch":true,"sender":{"key":"andy.koppe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/223411?v=4"},"body":"Use designated initializers instead of comments to denote the slots in\nthe decoration_colors array for holding color settings, to make it\nconsistent with the immediately following color_decorate_slots array\nand reduce the likelihood of mistakes when extending them.\n\nSigned-off-by: Andy Koppe <andy.koppe@gmail.com>\n---\n log-tree.c | 14 +++++++-------\n 1 file changed, 7 insertions(+), 7 deletions(-)\n\ndiff --git a/log-tree.c b/log-tree.c\nindex 504da6b519..8bdf889f02 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -34,13 +34,13 @@ static int decoration_loaded;\n static int decoration_flags;\n \n static char decoration_colors[][COLOR_MAXLEN] = {\n-\tGIT_COLOR_RESET,\n-\tGIT_COLOR_BOLD_GREEN,\t/* REF_LOCAL */\n-\tGIT_COLOR_BOLD_RED,\t/* REF_REMOTE */\n-\tGIT_COLOR_BOLD_YELLOW,\t/* REF_TAG */\n-\tGIT_COLOR_BOLD_MAGENTA,\t/* REF_STASH */\n-\tGIT_COLOR_BOLD_CYAN,\t/* REF_HEAD */\n-\tGIT_COLOR_BOLD_BLUE,\t/* GRAFTED */\n+\t[DECORATION_NONE]\t= GIT_COLOR_RESET,\n+\t[DECORATION_REF_LOCAL]\t= GIT_COLOR_BOLD_GREEN,\n+\t[DECORATION_REF_REMOTE]\t= GIT_COLOR_BOLD_RED,\n+\t[DECORATION_REF_TAG]\t= GIT_COLOR_BOLD_YELLOW,\n+\t[DECORATION_REF_STASH]\t= GIT_COLOR_BOLD_MAGENTA,\n+\t[DECORATION_REF_HEAD]\t= GIT_COLOR_BOLD_CYAN,\n+\t[DECORATION_GRAFTED]\t= GIT_COLOR_BOLD_BLUE,\n };\n \n static const char *color_decorate_slots[] = {\n-- \n2.42.GIT\n\n"},{"id":"483735","messageId":"20231023221143.72489-5-andy.koppe@gmail.com","threadId":"60303","inReplyTo":"20231023221143.72489-1-andy.koppe@gmail.com","subject":"[PATCH v3 4/7] log: add color.decorate.ref config variable","fromName":"Andy Koppe","fromEmail":"andy.koppe@gmail.com","sentAt":"2023-10-23T22:11:40Z","receivedAt":"2023-10-23T22:12:02Z","isPatch":true,"sender":{"key":"andy.koppe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/223411?v=4"},"body":"Refs other than branches, remote-tracking branches, tags and the stash\ndo not appear in log decorations by default, but they can be shown by\nusing decoration filter options such as --clear-decorations or\nlog.initialDecorationSet. However, they would appear without color.\n\nAdd config variable color.decorate.ref for such refs, defaulting to bold\nmagenta, which is the same as refs/stash.\n\nDocument the new variable on the git-config page and amend\nt4207-log-decoration-colors.sh to test it.\n\nSigned-off-by: Andy Koppe <andy.koppe@gmail.com>\n---\n Documentation/config/color.txt   | 5 +++++\n commit.h                         | 1 +\n log-tree.c                       | 4 +++-\n t/t4207-log-decoration-colors.sh | 9 +++++++--\n 4 files changed, 16 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/config/color.txt b/Documentation/config/color.txt\nindex cc0a881125..005a2bdb03 100644\n--- a/Documentation/config/color.txt\n+++ b/Documentation/config/color.txt\n@@ -90,11 +90,16 @@ color.decorate.<slot>::\n \tlightweight and annotated tags\n `stash`;;\n \tthe stash ref\n+`ref`;;\n+\tany other refs (not shown by default)\n `grafted`;;\n \tgrafted and replaced commits\n `symbol`;;\n \tpunctuation symbols surrounding the other elements\n --\n++\n+(Variable `log.initialDecorationSet` or linkgit:git-log[1] option\n+`--clear-decorations` can be used to show all refs.)\n \n color.grep::\n \tWhen set to `always`, always highlight matches.  When `false` (or\ndiff --git a/commit.h b/commit.h\nindex cb13e4d5ba..f6b2125fc4 100644\n--- a/commit.h\n+++ b/commit.h\n@@ -54,6 +54,7 @@ enum decoration_type {\n \tDECORATION_REF_REMOTE,\n \tDECORATION_REF_TAG,\n \tDECORATION_REF_STASH,\n+\tDECORATION_REF,\n \tDECORATION_REF_HEAD,\n \tDECORATION_GRAFTED,\n \tDECORATION_SYMBOL,\ndiff --git a/log-tree.c b/log-tree.c\nindex 890024f205..fb3d87b83d 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -39,6 +39,7 @@ static char decoration_colors[][COLOR_MAXLEN] = {\n \t[DECORATION_REF_REMOTE]\t= GIT_COLOR_BOLD_RED,\n \t[DECORATION_REF_TAG]\t= GIT_COLOR_BOLD_YELLOW,\n \t[DECORATION_REF_STASH]\t= GIT_COLOR_BOLD_MAGENTA,\n+\t[DECORATION_REF]\t= GIT_COLOR_BOLD_MAGENTA,\n \t[DECORATION_REF_HEAD]\t= GIT_COLOR_BOLD_CYAN,\n \t[DECORATION_GRAFTED]\t= GIT_COLOR_BOLD_BLUE,\n \t[DECORATION_SYMBOL]\t= GIT_COLOR_NIL,\n@@ -49,6 +50,7 @@ static const char *color_decorate_slots[] = {\n \t[DECORATION_REF_REMOTE] = \"remoteBranch\",\n \t[DECORATION_REF_TAG]\t= \"tag\",\n \t[DECORATION_REF_STASH]\t= \"stash\",\n+\t[DECORATION_REF]\t= \"ref\",\n \t[DECORATION_REF_HEAD]\t= \"HEAD\",\n \t[DECORATION_GRAFTED]\t= \"grafted\",\n \t[DECORATION_SYMBOL]\t= \"symbol\",\n@@ -151,7 +153,7 @@ static int add_ref_decoration(const char *refname, const struct object_id *oid,\n \tint i;\n \tstruct object *obj;\n \tenum object_type objtype;\n-\tenum decoration_type deco_type = DECORATION_NONE;\n+\tenum decoration_type deco_type = DECORATION_REF;\n \tstruct decoration_filter *filter = (struct decoration_filter *)cb_data;\n \tconst char *git_replace_ref_base = ref_namespace[NAMESPACE_REPLACE].ref;\n \ndiff --git a/t/t4207-log-decoration-colors.sh b/t/t4207-log-decoration-colors.sh\nindex f4173b6114..4b51e34f8b 100755\n--- a/t/t4207-log-decoration-colors.sh\n+++ b/t/t4207-log-decoration-colors.sh\n@@ -17,6 +17,7 @@ test_expect_success setup '\n \tgit config color.decorate.remoteBranch red &&\n \tgit config color.decorate.tag \"reverse bold yellow\" &&\n \tgit config color.decorate.stash magenta &&\n+\tgit config color.decorate.ref blue &&\n \tgit config color.decorate.grafted black &&\n \tgit config color.decorate.symbol white &&\n \tgit config color.decorate.HEAD cyan &&\n@@ -28,11 +29,13 @@ test_expect_success setup '\n \tc_remoteBranch=\"<RED>\" &&\n \tc_tag=\"<BOLD;REVERSE;YELLOW>\" &&\n \tc_stash=\"<MAGENTA>\" &&\n+\tc_ref=\"<BLUE>\" &&\n \tc_HEAD=\"<CYAN>\" &&\n \tc_grafted=\"<BLACK>\" &&\n \tc_symbol=\"<WHITE>\" &&\n \n \ttest_commit A &&\n+\tgit update-ref refs/foo A &&\n \tgit clone . other &&\n \t(\n \t\tcd other &&\n@@ -65,10 +68,12 @@ ${c_remoteBranch}other/main${c_reset}${c_symbol})${c_reset} A1\n \t${c_commit}COMMIT_ID${c_reset}${c_symbol} (${c_reset}\\\n ${c_stash}refs/stash${c_reset}${c_symbol})${c_reset} On main: Changes to A.t\n \t${c_commit}COMMIT_ID${c_reset}${c_symbol} (${c_reset}\\\n-${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_symbol})${c_reset} A\n+${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_symbol}, ${c_reset}\\\n+${c_ref}refs/foo${c_reset}${c_symbol})${c_reset} A\n \tEOF\n \n-\tgit log --first-parent --no-abbrev --decorate --oneline --color=always --all >actual &&\n+\tgit log --first-parent --no-abbrev --decorate --clear-decorations \\\n+\t\t--oneline --color=always --all >actual &&\n \tcmp_filtered_decorations\n '\n \n-- \n2.42.GIT\n\n"},{"id":"483736","messageId":"20231023221143.72489-6-andy.koppe@gmail.com","threadId":"60303","inReplyTo":"20231023221143.72489-1-andy.koppe@gmail.com","subject":"[PATCH v3 5/7] refs: add pseudorefs array and iteration functions","fromName":"Andy Koppe","fromEmail":"andy.koppe@gmail.com","sentAt":"2023-10-23T22:11:41Z","receivedAt":"2023-10-23T22:12:02Z","isPatch":true,"sender":{"key":"andy.koppe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/223411?v=4"},"body":"Define const array 'pseudorefs' with the names of the pseudorefs that\nare documented in gitrevisions.1, and add functions for_each_pseudoref()\nand refs_for_each_pseudoref() for iterating over them.\n\nThe functions process the pseudorefs in the same way as head_ref() and\nrefs_head_ref() process HEAD, invoking an each_ref_fn callback on each\npseudoref that exists.\n\nThis is in preparation for adding pseudorefs to log decorations.\n\nSigned-off-by: Andy Koppe <andy.koppe@gmail.com>\n---\n refs.c | 42 ++++++++++++++++++++++++++++++++++++++++++\n refs.h |  5 +++++\n 2 files changed, 47 insertions(+)\n\ndiff --git a/refs.c b/refs.c\nindex fcae5dddc6..aa7e4c02c5 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -65,6 +65,21 @@ static unsigned char refname_disposition[256] = {\n \t0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 4, 4\n };\n \n+/*\n+ * List of documented pseudorefs. This needs to be kept in sync with the list\n+ * in Documentation/revisions.txt.\n+ */\n+static const char *const pseudorefs[] = {\n+\t\"FETCH_HEAD\",\n+\t\"ORIG_HEAD\",\n+\t\"MERGE_HEAD\",\n+\t\"REBASE_HEAD\",\n+\t\"CHERRY_PICK_HEAD\",\n+\t\"REVERT_HEAD\",\n+\t\"BISECT_HEAD\",\n+\t\"AUTO_MERGE\",\n+};\n+\n struct ref_namespace_info ref_namespace[] = {\n \t[NAMESPACE_HEAD] = {\n \t\t.ref = \"HEAD\",\n@@ -1549,6 +1564,33 @@ int head_ref(each_ref_fn fn, void *cb_data)\n \treturn refs_head_ref(get_main_ref_store(the_repository), fn, cb_data);\n }\n \n+int refs_for_each_pseudoref(struct ref_store *refs,\n+\t\t\t    each_ref_fn fn, void *cb_data)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < ARRAY_SIZE(pseudorefs); i++) {\n+\t\tstruct object_id oid;\n+\t\tint flag;\n+\n+\t\tif (refs_resolve_ref_unsafe(refs, pseudorefs[i],\n+\t\t\t\t\t    RESOLVE_REF_READING, &oid, &flag)) {\n+\t\t\tint ret = fn(pseudorefs[i], &oid, flag, cb_data);\n+\n+\t\t\tif (ret)\n+\t\t\t\treturn ret;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+int for_each_pseudoref(each_ref_fn fn, void *cb_data)\n+{\n+\treturn refs_for_each_pseudoref(get_main_ref_store(the_repository),\n+\t\t\t\t       fn, cb_data);\n+}\n+\n struct ref_iterator *refs_ref_iterator_begin(\n \t\tstruct ref_store *refs,\n \t\tconst char *prefix,\ndiff --git a/refs.h b/refs.h\nindex 23211a5ea1..7b55cced31 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -320,6 +320,8 @@ typedef int each_repo_ref_fn(struct repository *r,\n  */\n int refs_head_ref(struct ref_store *refs,\n \t\t  each_ref_fn fn, void *cb_data);\n+int refs_for_each_pseudoref(struct ref_store *refs,\n+\t\t\t    each_ref_fn fn, void *cb_data);\n int refs_for_each_ref(struct ref_store *refs,\n \t\t      each_ref_fn fn, void *cb_data);\n int refs_for_each_ref_in(struct ref_store *refs, const char *prefix,\n@@ -334,6 +336,9 @@ int refs_for_each_remote_ref(struct ref_store *refs,\n /* just iterates the head ref. */\n int head_ref(each_ref_fn fn, void *cb_data);\n \n+/* iterates pseudorefs. */\n+int for_each_pseudoref(each_ref_fn fn, void *cb_data);\n+\n /* iterates all refs. */\n int for_each_ref(each_ref_fn fn, void *cb_data);\n \n-- \n2.42.GIT\n\n"},{"id":"483738","messageId":"20231023221143.72489-4-andy.koppe@gmail.com","threadId":"60303","inReplyTo":"20231023221143.72489-1-andy.koppe@gmail.com","subject":"[PATCH v3 3/7] log: add color.decorate.symbol config variable","fromName":"Andy Koppe","fromEmail":"andy.koppe@gmail.com","sentAt":"2023-10-23T22:11:39Z","receivedAt":"2023-10-23T22:12:02Z","isPatch":true,"sender":{"key":"andy.koppe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/223411?v=4"},"body":"Add new color.decorate.symbol config variable for determining the\ncolor of the prefix, suffix, separator and pointer symbols used in\nlog --decorate output and related log format placeholders, to allow\nthem to be colored differently from commit hashes.\n\nFor backward compatibility, fall back to the commit hash color that can\nbe specified with the color.diff.commit variable if the new variable is\nnot provided.\n\nAdd the variable to the color.decorate.<slot> documentation.\n\nAmend t4207-log-decoration-colors.sh to test it. Put ${c_reset} elements\nin the expected output at the end of lines for consistency.\n\nSigned-off-by: Andy Koppe <andy.koppe@gmail.com>\n---\n Documentation/config/color.txt   |  2 ++\n commit.h                         |  1 +\n log-tree.c                       | 15 ++++++---\n t/t4207-log-decoration-colors.sh | 58 +++++++++++++++++---------------\n 4 files changed, 43 insertions(+), 33 deletions(-)\n\ndiff --git a/Documentation/config/color.txt b/Documentation/config/color.txt\nindex 3453703f9b..cc0a881125 100644\n--- a/Documentation/config/color.txt\n+++ b/Documentation/config/color.txt\n@@ -92,6 +92,8 @@ color.decorate.<slot>::\n \tthe stash ref\n `grafted`;;\n \tgrafted and replaced commits\n+`symbol`;;\n+\tpunctuation symbols surrounding the other elements\n --\n \n color.grep::\ndiff --git a/commit.h b/commit.h\nindex 28928833c5..cb13e4d5ba 100644\n--- a/commit.h\n+++ b/commit.h\n@@ -56,6 +56,7 @@ enum decoration_type {\n \tDECORATION_REF_STASH,\n \tDECORATION_REF_HEAD,\n \tDECORATION_GRAFTED,\n+\tDECORATION_SYMBOL,\n };\n \n void add_name_decoration(enum decoration_type type, const char *name, struct object *obj);\ndiff --git a/log-tree.c b/log-tree.c\nindex 8bdf889f02..890024f205 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -41,6 +41,7 @@ static char decoration_colors[][COLOR_MAXLEN] = {\n \t[DECORATION_REF_STASH]\t= GIT_COLOR_BOLD_MAGENTA,\n \t[DECORATION_REF_HEAD]\t= GIT_COLOR_BOLD_CYAN,\n \t[DECORATION_GRAFTED]\t= GIT_COLOR_BOLD_BLUE,\n+\t[DECORATION_SYMBOL]\t= GIT_COLOR_NIL,\n };\n \n static const char *color_decorate_slots[] = {\n@@ -50,6 +51,7 @@ static const char *color_decorate_slots[] = {\n \t[DECORATION_REF_STASH]\t= \"stash\",\n \t[DECORATION_REF_HEAD]\t= \"HEAD\",\n \t[DECORATION_GRAFTED]\t= \"grafted\",\n+\t[DECORATION_SYMBOL]\t= \"symbol\",\n };\n \n static const char *decorate_get_color(int decorate_use_color, enum decoration_type ix)\n@@ -312,7 +314,7 @@ void format_decorations(struct strbuf *sb,\n {\n \tconst struct name_decoration *decoration;\n \tconst struct name_decoration *current_and_HEAD;\n-\tconst char *color_commit, *color_reset;\n+\tconst char *color_symbol, *color_reset;\n \n \tconst char *prefix = \" (\";\n \tconst char *suffix = \")\";\n@@ -337,7 +339,10 @@ void format_decorations(struct strbuf *sb,\n \t\t\ttag = opts->tag;\n \t}\n \n-\tcolor_commit = diff_get_color(use_color, DIFF_COMMIT);\n+\tcolor_symbol = decorate_get_color(use_color, DECORATION_SYMBOL);\n+\tif (color_is_nil(color_symbol))\n+\t\tcolor_symbol = diff_get_color(use_color, DIFF_COMMIT);\n+\n \tcolor_reset = decorate_get_color(use_color, DECORATION_NONE);\n \n \tcurrent_and_HEAD = current_pointed_by_HEAD(decoration);\n@@ -352,7 +357,7 @@ void format_decorations(struct strbuf *sb,\n \t\t\t\tdecorate_get_color(use_color, decoration->type);\n \n \t\t\tif (*prefix) {\n-\t\t\t\tstrbuf_addstr(sb, color_commit);\n+\t\t\t\tstrbuf_addstr(sb, color_symbol);\n \t\t\t\tstrbuf_addstr(sb, prefix);\n \t\t\t\tstrbuf_addstr(sb, color_reset);\n \t\t\t}\n@@ -369,7 +374,7 @@ void format_decorations(struct strbuf *sb,\n \n \t\t\tif (current_and_HEAD &&\n \t\t\t    decoration->type == DECORATION_REF_HEAD) {\n-\t\t\t\tstrbuf_addstr(sb, color_commit);\n+\t\t\t\tstrbuf_addstr(sb, color_symbol);\n \t\t\t\tstrbuf_addstr(sb, pointer);\n \t\t\t\tstrbuf_addstr(sb, color_reset);\n \t\t\t\tstrbuf_addstr(sb, decorate_get_color(use_color, current_and_HEAD->type));\n@@ -382,7 +387,7 @@ void format_decorations(struct strbuf *sb,\n \t\tdecoration = decoration->next;\n \t}\n \tif (*suffix) {\n-\t\tstrbuf_addstr(sb, color_commit);\n+\t\tstrbuf_addstr(sb, color_symbol);\n \t\tstrbuf_addstr(sb, suffix);\n \t\tstrbuf_addstr(sb, color_reset);\n \t}\ndiff --git a/t/t4207-log-decoration-colors.sh b/t/t4207-log-decoration-colors.sh\nindex 21986a866d..f4173b6114 100755\n--- a/t/t4207-log-decoration-colors.sh\n+++ b/t/t4207-log-decoration-colors.sh\n@@ -18,6 +18,7 @@ test_expect_success setup '\n \tgit config color.decorate.tag \"reverse bold yellow\" &&\n \tgit config color.decorate.stash magenta &&\n \tgit config color.decorate.grafted black &&\n+\tgit config color.decorate.symbol white &&\n \tgit config color.decorate.HEAD cyan &&\n \n \tc_reset=\"<RESET>\" &&\n@@ -29,6 +30,7 @@ test_expect_success setup '\n \tc_stash=\"<MAGENTA>\" &&\n \tc_HEAD=\"<CYAN>\" &&\n \tc_grafted=\"<BLACK>\" &&\n+\tc_symbol=\"<WHITE>\" &&\n \n \ttest_commit A &&\n \tgit clone . other &&\n@@ -53,17 +55,17 @@ cmp_filtered_decorations () {\n # to this test since it does not contain any decoration, hence --first-parent\n test_expect_success 'commit decorations colored correctly' '\n \tcat >expect <<-EOF &&\n-\t${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_HEAD}HEAD${c_reset}\\\n-${c_commit} -> ${c_reset}${c_branch}main${c_reset}${c_commit}, \\\n-${c_reset}${c_tag}tag: ${c_reset}${c_tag}v1.0${c_reset}${c_commit}, \\\n-${c_reset}${c_tag}tag: ${c_reset}${c_tag}B${c_reset}${c_commit})${c_reset} B\n-${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\\\n-${c_tag}tag: ${c_reset}${c_tag}A1${c_reset}${c_commit}, \\\n-${c_reset}${c_remoteBranch}other/main${c_reset}${c_commit})${c_reset} A1\n-\t${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\\\n-${c_stash}refs/stash${c_reset}${c_commit})${c_reset} On main: Changes to A.t\n-\t${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\\\n-${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_commit})${c_reset} A\n+\t${c_commit}COMMIT_ID${c_reset}${c_symbol} (${c_reset}${c_HEAD}HEAD${c_reset}\\\n+${c_symbol} -> ${c_reset}${c_branch}main${c_reset}${c_symbol}, ${c_reset}\\\n+${c_tag}tag: ${c_reset}${c_tag}v1.0${c_reset}${c_symbol}, ${c_reset}\\\n+${c_tag}tag: ${c_reset}${c_tag}B${c_reset}${c_symbol})${c_reset} B\n+${c_commit}COMMIT_ID${c_reset}${c_symbol} (${c_reset}\\\n+${c_tag}tag: ${c_reset}${c_tag}A1${c_reset}${c_symbol}, ${c_reset}\\\n+${c_remoteBranch}other/main${c_reset}${c_symbol})${c_reset} A1\n+\t${c_commit}COMMIT_ID${c_reset}${c_symbol} (${c_reset}\\\n+${c_stash}refs/stash${c_reset}${c_symbol})${c_reset} On main: Changes to A.t\n+\t${c_commit}COMMIT_ID${c_reset}${c_symbol} (${c_reset}\\\n+${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_symbol})${c_reset} A\n \tEOF\n \n \tgit log --first-parent --no-abbrev --decorate --oneline --color=always --all >actual &&\n@@ -78,14 +80,14 @@ test_expect_success 'test coloring with replace-objects' '\n \tgit replace HEAD~1 HEAD~2 &&\n \n \tcat >expect <<-EOF &&\n-\t${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_HEAD}HEAD${c_reset}\\\n-${c_commit} -> ${c_reset}${c_branch}main${c_reset}${c_commit}, \\\n-${c_reset}${c_tag}tag: ${c_reset}${c_tag}D${c_reset}${c_commit})${c_reset} D\n-\t${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\\\n-${c_tag}tag: ${c_reset}${c_tag}C${c_reset}${c_commit}, \\\n-${c_reset}${c_grafted}replaced${c_reset}${c_commit})${c_reset} B\n-\t${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\\\n-${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_commit})${c_reset} A\n+\t${c_commit}COMMIT_ID${c_reset}${c_symbol} (${c_reset}${c_HEAD}HEAD${c_reset}\\\n+${c_symbol} -> ${c_reset}${c_branch}main${c_reset}${c_symbol}, ${c_reset}\\\n+${c_tag}tag: ${c_reset}${c_tag}D${c_reset}${c_symbol})${c_reset} D\n+\t${c_commit}COMMIT_ID${c_reset}${c_symbol} (${c_reset}\\\n+${c_tag}tag: ${c_reset}${c_tag}C${c_reset}${c_symbol}, ${c_reset}\\\n+${c_grafted}replaced${c_reset}${c_symbol})${c_reset} B\n+\t${c_commit}COMMIT_ID${c_reset}${c_symbol} (${c_reset}\\\n+${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_symbol})${c_reset} A\n EOF\n \n \tgit log --first-parent --no-abbrev --decorate --oneline --color=always HEAD >actual &&\n@@ -104,15 +106,15 @@ test_expect_success 'test coloring with grafted commit' '\n \tgit replace --graft HEAD HEAD~2 &&\n \n \tcat >expect <<-EOF &&\n-\t${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_HEAD}HEAD${c_reset}\\\n-${c_commit} -> ${c_reset}${c_branch}main${c_reset}${c_commit}, \\\n-${c_reset}${c_tag}tag: ${c_reset}${c_tag}D${c_reset}${c_commit}, \\\n-${c_reset}${c_grafted}replaced${c_reset}${c_commit})${c_reset} D\n-\t${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\\\n-${c_tag}tag: ${c_reset}${c_tag}v1.0${c_reset}${c_commit}, \\\n-${c_reset}${c_tag}tag: ${c_reset}${c_tag}B${c_reset}${c_commit})${c_reset} B\n-\t${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\\\n-${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_commit})${c_reset} A\n+\t${c_commit}COMMIT_ID${c_reset}${c_symbol} (${c_reset}${c_HEAD}HEAD${c_reset}\\\n+${c_symbol} -> ${c_reset}${c_branch}main${c_reset}${c_symbol}, ${c_reset}\\\n+${c_tag}tag: ${c_reset}${c_tag}D${c_reset}${c_symbol}, ${c_reset}\\\n+${c_grafted}replaced${c_reset}${c_symbol})${c_reset} D\n+\t${c_commit}COMMIT_ID${c_reset}${c_symbol} (${c_reset}\\\n+${c_tag}tag: ${c_reset}${c_tag}v1.0${c_reset}${c_symbol}, ${c_reset}\\\n+${c_tag}tag: ${c_reset}${c_tag}B${c_reset}${c_symbol})${c_reset} B\n+\t${c_commit}COMMIT_ID${c_reset}${c_symbol} (${c_reset}\\\n+${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_symbol})${c_reset} A\n \tEOF\n \n \tgit log --first-parent --no-abbrev --decorate --oneline --color=always HEAD >actual &&\n-- \n2.42.GIT\n\n"},{"id":"483737","messageId":"20231023221143.72489-7-andy.koppe@gmail.com","threadId":"60303","inReplyTo":"20231023221143.72489-1-andy.koppe@gmail.com","subject":"[PATCH v3 6/7] refs: exempt pseudorefs from pattern prefixing","fromName":"Andy Koppe","fromEmail":"andy.koppe@gmail.com","sentAt":"2023-10-23T22:11:42Z","receivedAt":"2023-10-23T22:12:03Z","isPatch":true,"sender":{"key":"andy.koppe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/223411?v=4"},"body":"In normalize_glob_ref(), don't prefix pseudorefs with \"refs/\", thereby\nimplementing a NEEDSWORK from b877e617e6e5.\n\nThis is in preparation for showing pseudorefs in log decorations, as\nthey are not matched as intended in decoration filters otherwise. The\nfunction is only used in load_ref_decorations().\n\nSigned-off-by: Andy Koppe <andy.koppe@gmail.com>\n---\n refs.c | 17 ++++++++++-------\n 1 file changed, 10 insertions(+), 7 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex aa7e4c02c5..fbd15a8cff 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -565,13 +565,16 @@ void normalize_glob_ref(struct string_list_item *item, const char *prefix,\n \n \tif (prefix)\n \t\tstrbuf_addstr(&normalized_pattern, prefix);\n-\telse if (!starts_with(pattern, \"refs/\") &&\n-\t\t   strcmp(pattern, \"HEAD\"))\n-\t\tstrbuf_addstr(&normalized_pattern, \"refs/\");\n-\t/*\n-\t * NEEDSWORK: Special case other symrefs such as REBASE_HEAD,\n-\t * MERGE_HEAD, etc.\n-\t */\n+\telse if (!starts_with(pattern, \"refs/\") && strcmp(pattern, \"HEAD\")) {\n+\t\tint i;\n+\n+\t\tfor (i = 0; i < ARRAY_SIZE(pseudorefs); i++)\n+\t\t\tif (!strcmp(pattern, pseudorefs[i]))\n+\t\t\t\tbreak;\n+\n+\t\tif (i == ARRAY_SIZE(pseudorefs))\n+\t\t\tstrbuf_addstr(&normalized_pattern, \"refs/\");\n+\t}\n \n \tstrbuf_addstr(&normalized_pattern, pattern);\n \tstrbuf_strip_suffix(&normalized_pattern, \"/\");\n-- \n2.42.GIT\n\n"},{"id":"483739","messageId":"20231023221143.72489-8-andy.koppe@gmail.com","threadId":"60303","inReplyTo":"20231023221143.72489-1-andy.koppe@gmail.com","subject":"[PATCH v3 7/7] log: add color.decorate.pseudoref config variable","fromName":"Andy Koppe","fromEmail":"andy.koppe@gmail.com","sentAt":"2023-10-23T22:11:43Z","receivedAt":"2023-10-23T22:12:05Z","isPatch":true,"sender":{"key":"andy.koppe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/223411?v=4"},"body":"Add the ability to show pseudorefs such as ORIG_HEAD and MERGE_HEAD in\nlog decorations. Add config variable color.decorate.pseudoref to\ndetermine their color, defaulting to bold cyan, which is the same as\nHEAD.\n\nThey will not be shown unless the default decoration filtering is\noverridden with relevant log options such as --clear-decorations or\nlog.initialDecorationSet.\n\nSigned-off-by: Andy Koppe <andy.koppe@gmail.com>\n---\n Documentation/config/color.txt                |  4 +++-\n commit.h                                      |  1 +\n log-tree.c                                    | 24 +++++++++++++++++++\n ..._--decorate=full_--clear-decorations_--all |  4 ++--\n ...f.log_--decorate_--clear-decorations_--all |  4 ++--\n t/t4202-log.sh                                | 21 +++++++++-------\n t/t4207-log-decoration-colors.sh              | 13 +++++++---\n 7 files changed, 54 insertions(+), 17 deletions(-)\n\ndiff --git a/Documentation/config/color.txt b/Documentation/config/color.txt\nindex 005a2bdb03..7af7d65f76 100644\n--- a/Documentation/config/color.txt\n+++ b/Documentation/config/color.txt\n@@ -92,6 +92,8 @@ color.decorate.<slot>::\n \tthe stash ref\n `ref`;;\n \tany other refs (not shown by default)\n+`pseudoref`;;\n+\tpseudorefs such as ORIG_HEAD or MERGE_HEAD (not shown by default)\n `grafted`;;\n \tgrafted and replaced commits\n `symbol`;;\n@@ -99,7 +101,7 @@ color.decorate.<slot>::\n --\n +\n (Variable `log.initialDecorationSet` or linkgit:git-log[1] option\n-`--clear-decorations` can be used to show all refs.)\n+`--clear-decorations` can be used to show all refs and pseudorefs.)\n \n color.grep::\n \tWhen set to `always`, always highlight matches.  When `false` (or\ndiff --git a/commit.h b/commit.h\nindex f6b2125fc4..44dd3ce19b 100644\n--- a/commit.h\n+++ b/commit.h\n@@ -56,6 +56,7 @@ enum decoration_type {\n \tDECORATION_REF_STASH,\n \tDECORATION_REF,\n \tDECORATION_REF_HEAD,\n+\tDECORATION_REF_PSEUDO,\n \tDECORATION_GRAFTED,\n \tDECORATION_SYMBOL,\n };\ndiff --git a/log-tree.c b/log-tree.c\nindex fb3d87b83d..65ebb74d40 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -41,6 +41,7 @@ static char decoration_colors[][COLOR_MAXLEN] = {\n \t[DECORATION_REF_STASH]\t= GIT_COLOR_BOLD_MAGENTA,\n \t[DECORATION_REF]\t= GIT_COLOR_BOLD_MAGENTA,\n \t[DECORATION_REF_HEAD]\t= GIT_COLOR_BOLD_CYAN,\n+\t[DECORATION_REF_PSEUDO]\t= GIT_COLOR_BOLD_CYAN,\n \t[DECORATION_GRAFTED]\t= GIT_COLOR_BOLD_BLUE,\n \t[DECORATION_SYMBOL]\t= GIT_COLOR_NIL,\n };\n@@ -52,6 +53,7 @@ static const char *color_decorate_slots[] = {\n \t[DECORATION_REF_STASH]\t= \"stash\",\n \t[DECORATION_REF]\t= \"ref\",\n \t[DECORATION_REF_HEAD]\t= \"HEAD\",\n+\t[DECORATION_REF_PSEUDO]\t= \"pseudoref\",\n \t[DECORATION_GRAFTED]\t= \"grafted\",\n \t[DECORATION_SYMBOL]\t= \"symbol\",\n };\n@@ -208,6 +210,27 @@ static int add_ref_decoration(const char *refname, const struct object_id *oid,\n \treturn 0;\n }\n \n+static int add_pseudoref_decoration(const char *refname,\n+\t\t\t\t    const struct object_id *oid,\n+\t\t\t\t    int flags UNUSED,\n+\t\t\t\t    void *cb_data)\n+{\n+\tstruct object *obj;\n+\tenum object_type objtype;\n+\tstruct decoration_filter *filter = (struct decoration_filter *)cb_data;\n+\n+\tif (filter && !ref_filter_match(refname, filter))\n+\t\treturn 0;\n+\n+\tobjtype = oid_object_info(the_repository, oid, NULL);\n+\tif (objtype < 0)\n+\t\treturn 0;\n+\n+\tobj = lookup_object_by_type(the_repository, oid, objtype);\n+\tadd_name_decoration(DECORATION_REF_PSEUDO, refname, obj);\n+\treturn 0;\n+}\n+\n static int add_graft_decoration(const struct commit_graft *graft,\n \t\t\t\tvoid *cb_data UNUSED)\n {\n@@ -236,6 +259,7 @@ void load_ref_decorations(struct decoration_filter *filter, int flags)\n \t\tdecoration_loaded = 1;\n \t\tdecoration_flags = flags;\n \t\tfor_each_ref(add_ref_decoration, filter);\n+\t\tfor_each_pseudoref(add_pseudoref_decoration, filter);\n \t\thead_ref(add_ref_decoration, filter);\n \t\tfor_each_commit_graft(add_graft_decoration, filter);\n \t}\ndiff --git a/t/t4013/diff.log_--decorate=full_--clear-decorations_--all b/t/t4013/diff.log_--decorate=full_--clear-decorations_--all\nindex 1c030a6554..7d16978e7f 100644\n--- a/t/t4013/diff.log_--decorate=full_--clear-decorations_--all\n+++ b/t/t4013/diff.log_--decorate=full_--clear-decorations_--all\n@@ -33,13 +33,13 @@ Date:   Mon Jun 26 00:04:00 2006 +0000\n \n     Merge branch 'side'\n \n-commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a (refs/heads/side)\n+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a (FETCH_HEAD, refs/heads/side)\n Author: A U Thor <author@example.com>\n Date:   Mon Jun 26 00:03:00 2006 +0000\n \n     Side\n \n-commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0\n+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 (ORIG_HEAD)\n Author: A U Thor <author@example.com>\n Date:   Mon Jun 26 00:02:00 2006 +0000\n \ndiff --git a/t/t4013/diff.log_--decorate_--clear-decorations_--all b/t/t4013/diff.log_--decorate_--clear-decorations_--all\nindex 88be82cce3..4f9be50ce0 100644\n--- a/t/t4013/diff.log_--decorate_--clear-decorations_--all\n+++ b/t/t4013/diff.log_--decorate_--clear-decorations_--all\n@@ -33,13 +33,13 @@ Date:   Mon Jun 26 00:04:00 2006 +0000\n \n     Merge branch 'side'\n \n-commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a (side)\n+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a (FETCH_HEAD, side)\n Author: A U Thor <author@example.com>\n Date:   Mon Jun 26 00:03:00 2006 +0000\n \n     Side\n \n-commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0\n+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 (ORIG_HEAD)\n Author: A U Thor <author@example.com>\n Date:   Mon Jun 26 00:02:00 2006 +0000\n \ndiff --git a/t/t4202-log.sh b/t/t4202-log.sh\nindex af4a123cd2..b14da62e3e 100755\n--- a/t/t4202-log.sh\n+++ b/t/t4202-log.sh\n@@ -927,7 +927,7 @@ test_expect_success 'multiple decorate-refs' '\n test_expect_success 'decorate-refs-exclude with glob' '\n \tcat >expect.decorate <<-\\EOF &&\n \tMerge-tag-reach (HEAD -> main)\n-\tMerge-tags-octopus-a-and-octopus-b\n+\tMerge-tags-octopus-a-and-octopus-b (ORIG_HEAD)\n \tseventh (tag: seventh)\n \toctopus-b (tag: octopus-b)\n \toctopus-a (tag: octopus-a)\n@@ -944,7 +944,7 @@ test_expect_success 'decorate-refs-exclude with glob' '\n test_expect_success 'decorate-refs-exclude without globs' '\n \tcat >expect.decorate <<-\\EOF &&\n \tMerge-tag-reach (HEAD -> main)\n-\tMerge-tags-octopus-a-and-octopus-b\n+\tMerge-tags-octopus-a-and-octopus-b (ORIG_HEAD)\n \tseventh (tag: seventh)\n \toctopus-b (tag: octopus-b, octopus-b)\n \toctopus-a (tag: octopus-a, octopus-a)\n@@ -961,7 +961,7 @@ test_expect_success 'decorate-refs-exclude without globs' '\n test_expect_success 'multiple decorate-refs-exclude' '\n \tcat >expect.decorate <<-\\EOF &&\n \tMerge-tag-reach (HEAD -> main)\n-\tMerge-tags-octopus-a-and-octopus-b\n+\tMerge-tags-octopus-a-and-octopus-b (ORIG_HEAD)\n \tseventh (tag: seventh)\n \toctopus-b (tag: octopus-b)\n \toctopus-a (tag: octopus-a)\n@@ -1022,10 +1022,12 @@ test_expect_success 'decorate-refs-exclude and simplify-by-decoration' '\n \tEOF\n \tgit log -n6 --decorate=short --pretty=\"tformat:%f%d\" \\\n \t\t--decorate-refs-exclude=\"*octopus*\" \\\n+\t\t--decorate-refs-exclude=\"ORIG_HEAD\" \\\n \t\t--simplify-by-decoration >actual &&\n \ttest_cmp expect.decorate actual &&\n-\tgit -c log.excludeDecoration=\"*octopus*\" log \\\n-\t\t-n6 --decorate=short --pretty=\"tformat:%f%d\" \\\n+\tgit -c log.excludeDecoration=\"*octopus*\" \\\n+\t    -c log.excludeDecoration=\"ORIG_HEAD\" \\\n+\t    log -n6 --decorate=short --pretty=\"tformat:%f%d\" \\\n \t\t--simplify-by-decoration >actual &&\n \ttest_cmp expect.decorate actual\n '\n@@ -1067,9 +1069,10 @@ test_expect_success 'decorate-refs and simplify-by-decoration without output' '\n \ttest_cmp expect actual\n '\n \n-test_expect_success 'decorate-refs-exclude HEAD' '\n+test_expect_success 'decorate-refs-exclude HEAD ORIG_HEAD' '\n \tgit log --decorate=full --oneline \\\n-\t\t--decorate-refs-exclude=\"HEAD\" >actual &&\n+\t\t--decorate-refs-exclude=\"HEAD\" \\\n+\t\t--decorate-refs-exclude=\"ORIG_HEAD\" >actual &&\n \t! grep HEAD actual\n '\n \n@@ -1107,7 +1110,7 @@ test_expect_success '--clear-decorations overrides defaults' '\n \n \tcat >expect.all <<-\\EOF &&\n \tMerge-tag-reach (HEAD -> refs/heads/main)\n-\tMerge-tags-octopus-a-and-octopus-b\n+\tMerge-tags-octopus-a-and-octopus-b (ORIG_HEAD)\n \tseventh (tag: refs/tags/seventh)\n \toctopus-b (tag: refs/tags/octopus-b, refs/heads/octopus-b)\n \toctopus-a (tag: refs/tags/octopus-a, refs/heads/octopus-a)\n@@ -1139,7 +1142,7 @@ test_expect_success '--clear-decorations clears previous exclusions' '\n \tcat >expect.all <<-\\EOF &&\n \tMerge-tag-reach (HEAD -> refs/heads/main)\n \treach (tag: refs/tags/reach, refs/heads/reach)\n-\tMerge-tags-octopus-a-and-octopus-b\n+\tMerge-tags-octopus-a-and-octopus-b (ORIG_HEAD)\n \toctopus-b (tag: refs/tags/octopus-b, refs/heads/octopus-b)\n \toctopus-a (tag: refs/tags/octopus-a, refs/heads/octopus-a)\n \tseventh (tag: refs/tags/seventh)\ndiff --git a/t/t4207-log-decoration-colors.sh b/t/t4207-log-decoration-colors.sh\nindex 4b51e34f8b..0b32e0bb8e 100755\n--- a/t/t4207-log-decoration-colors.sh\n+++ b/t/t4207-log-decoration-colors.sh\n@@ -18,6 +18,7 @@ test_expect_success setup '\n \tgit config color.decorate.tag \"reverse bold yellow\" &&\n \tgit config color.decorate.stash magenta &&\n \tgit config color.decorate.ref blue &&\n+\tgit config color.decorate.pseudoref \"bold cyan\" &&\n \tgit config color.decorate.grafted black &&\n \tgit config color.decorate.symbol white &&\n \tgit config color.decorate.HEAD cyan &&\n@@ -30,6 +31,7 @@ test_expect_success setup '\n \tc_tag=\"<BOLD;REVERSE;YELLOW>\" &&\n \tc_stash=\"<MAGENTA>\" &&\n \tc_ref=\"<BLUE>\" &&\n+\tc_pseudoref=\"<BOLD;CYAN>\" &&\n \tc_HEAD=\"<CYAN>\" &&\n \tc_grafted=\"<BLACK>\" &&\n \tc_symbol=\"<WHITE>\" &&\n@@ -46,7 +48,10 @@ test_expect_success setup '\n \ttest_commit B &&\n \tgit tag v1.0 &&\n \techo >>A.t &&\n-\tgit stash save Changes to A.t\n+\tgit stash save Changes to A.t &&\n+\tgit reset other/main &&\n+\tgit reset ORIG_HEAD &&\n+\tgit revert --no-commit @~\n '\n \n cmp_filtered_decorations () {\n@@ -63,17 +68,19 @@ ${c_symbol} -> ${c_reset}${c_branch}main${c_reset}${c_symbol}, ${c_reset}\\\n ${c_tag}tag: ${c_reset}${c_tag}v1.0${c_reset}${c_symbol}, ${c_reset}\\\n ${c_tag}tag: ${c_reset}${c_tag}B${c_reset}${c_symbol})${c_reset} B\n ${c_commit}COMMIT_ID${c_reset}${c_symbol} (${c_reset}\\\n+${c_pseudoref}ORIG_HEAD${c_reset}${c_symbol}, ${c_reset}\\\n ${c_tag}tag: ${c_reset}${c_tag}A1${c_reset}${c_symbol}, ${c_reset}\\\n ${c_remoteBranch}other/main${c_reset}${c_symbol})${c_reset} A1\n \t${c_commit}COMMIT_ID${c_reset}${c_symbol} (${c_reset}\\\n ${c_stash}refs/stash${c_reset}${c_symbol})${c_reset} On main: Changes to A.t\n \t${c_commit}COMMIT_ID${c_reset}${c_symbol} (${c_reset}\\\n+${c_pseudoref}REVERT_HEAD${c_reset}${c_symbol}, ${c_reset}\\\n ${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_symbol}, ${c_reset}\\\n ${c_ref}refs/foo${c_reset}${c_symbol})${c_reset} A\n \tEOF\n \n-\tgit log --first-parent --no-abbrev --decorate --clear-decorations \\\n-\t\t--oneline --color=always --all >actual &&\n+\tgit log --first-parent --no-abbrev --decorate --color=always \\\n+\t\t--decorate-refs-exclude=FETCH_HEAD --oneline --all >actual &&\n \tcmp_filtered_decorations\n '\n \n-- \n2.42.GIT\n\n"},{"id":"483740","messageId":"50a646f6-730d-4d79-84b6-c0ee8be748e7@gmail.com","threadId":"60303","inReplyTo":"xmqqpm16p4t3.fsf@gitster.g","subject":"Re: [PATCH 0/7] log: decorate pseudorefs and other refs","fromName":"Andy Koppe","fromEmail":"andy.koppe@gmail.com","sentAt":"2023-10-23T22:15:36Z","receivedAt":"2023-10-23T22:15:44Z","isPatch":true,"sender":{"key":"andy.koppe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/223411?v=4"},"body":"On 23/10/2023 01:20, Junio C Hamano wrote:\n> Andy Koppe <andy.koppe@gmail.com> writes:\n> \n>>>    [2/7] is a trivial readability improvement.  It obviously should be\n>>>          left outside the scope of this series, but we should notice\n>>>          the same pattern in similar color tables (e.g., wt-status.c\n>>>          has one, diff.c has another) and perform the same clean-up as\n>>>          a #leftoverbits item.\n>>\n>> Okay, I've removed that commit in v2. (I should have mentioned in the\n>> commit message that it was triggered by the inconsistency with the\n>> immediately following color_decorate_slots array, which uses\n>> designated initializers.)\n> \n> Sorry, that is not what I meant.  [2/7] as a preliminary clean-up to\n> work in the same area does make very much sense.  What I meant to be\n> \"outside the scope\" was to make similar fixes to other color tables\n> that this series does not care about.\n\nAh, sorry for misreading. Commit reinstated in v3.\n\n\n>> Fair enough, although the array already contains HEAD and refs/stash\n>> as singletons.\n> \n> But these deserve to be singletons, don't they?  There is no other\n> thing that behaves like HEAD; there is no other thing that behaves\n> like stash; and they do not behave like each other.\n\nThey do indeed, but arguably the pseudorefs are singletons rather than a \nnamespace like refs/heads as well, as there is a defined and documented \nset of them.\n\n\n>> I've rewritten things to not touch the ref_namespace array.\n> \n> Well, the namespace_info mechanism still may be a good place to have\n> the necessary information; it may be that the current implementation\n> detail of how a given ref is classified to one of the namespaces is\n> too limiting---it essentially allows the string match with the .ref\n> member.  But we can imagine that it could be extended a bit, e.g.\n> \n> \tstruct ref_namespace_info {\n> \t\tchar *ref;\n> \t\tint (*membership)(const char *, const struct ref_namespace_info *);\n> \t\t... other members ...;\n> \t};\n> \n> where the .membership member is used in add_ref_decoration() to\n> determine the membership of a given \"refname\" to the namespace \"i\"\n> perhaps like so:\n> \n> \tstruct ref_namespace_info *info = &ref_namespace[i];\n> \n> \tif (!info->decoration)\n> \t\tcontinue;\n> +\tif (info->membership) {\n> +\t\tif (info->membership(refname, info)) {\n> +\t\t\tdeco_type = info->decoration;\n> +\t\t\tbreak;\n> +\t\t}\n> +\t} else if (info->exact) {\n> -\tif (info->exact) {\n> \t\tif (!strcmp(refname, info->ref)) {\n> \t\t\tdeco_type = info_decoration;\n> \t\t\tbreak;\n> \t}\n> \n> Then you can arrange the pseudoref class to use .membership function\n> perhaps like this:\n> \n> \tstatic int pseudoref_namespace_membership(\n> \t\tconst char *refname, const struct ref_namespace_info *info UNUSED\n> \t)\n> \t{\n> \t\treturn is_pseudoref(refname);\n> \t}\n> \n> and make them all into a single class.\n\nThat's an interesting idea, but I'm not convinced it would buy us much, \nwhile also potentially complicating things for any other uses of the \nref_namespace array.\n\nMy premise here is that we do need a list of the documented pseudorefs, \nso that we can iterate through them and add the ones that do exist to \nthe decorations, whereby I admit that shoe-horning that list into the \nref_namespace array wasn't a good idea. If that premise is wrong, and \nthere's a better way to discover the pseudorefs, the following might be \nmoot.\n\nSending each found pseudoref through add_ref_decoration() and its lookup \nof ref_namespace would just confirm what we already know: it's a \npseudoref. Which is why both my initial attempt and the current one \ndon't actually invoke add_ref_decoration() for them.\n\nCould you have a closer look at the current design? It handles the \npseudorefs separately from proper refs, with their own iteration and \ncallback functions, which I think makes for simpler more self-contained \nchanges than v1 or the approach suggested above.\n\n\n> Having said that, I do not think it makes much sense to decorate a\n> commit off of refs/stash, as the true richeness of the stash is not\n> in its history but in its reflog, which the decoration code does not\n> dig into.  But obviously it is not a part of the topic we are\n> discussing (unless, of course, we are not \"adding\" new decoration\n> sources and colors, but we are improving the decoration sources and\n> colors by adding new useful ones while retiring existing useless\n> ones).\n\nI agree refs/stash is a weird one, and that it could be subsumed into \nthe color.decoration.ref setting for 'refs/*' that I'm adding here, \nwhich is also why I chose the same default color for it. I'd be happy to \ndrop color.decoration.stash if the minor break in compatibility for \nanyone who has customized it is acceptable. The setting would be quietly \nignored.\n\nAnother related thought: the '--clear-decorations' option of git-log \nseems unfortunately named as it suggests the opposite of what it \nactually does, which is to enable all decorations (unless subsequently \nconstrained with '--decorate-refs{,--exclude}=...').\n\nRegards,\nAndy\n"},{"id":"483752","messageId":"xmqqjzrc7ugc.fsf@gitster.g","threadId":"60303","inReplyTo":"20231023221143.72489-6-andy.koppe@gmail.com","subject":"Re: [PATCH v3 5/7] refs: add pseudorefs array and iteration functions","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-10-24T00:08:51Z","receivedAt":"2023-10-24T00:09:00Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Andy Koppe <andy.koppe@gmail.com> writes:\n\n> Define const array 'pseudorefs' with the names of the pseudorefs that\n> are documented in gitrevisions.1, and add functions for_each_pseudoref()\n> and refs_for_each_pseudoref() for iterating over them.\n\nMakes sense, and we can later (ab|re)use the same mechanism to\nextend \"git for-each-ref\" that currently only knows how to show\nthings under \"refs/\" hierarchy.\n\n> The functions process the pseudorefs in the same way as head_ref() and\n> refs_head_ref() process HEAD, invoking an each_ref_fn callback on each\n> pseudoref that exists.\n\nGood.\n"},{"id":"487946","messageId":"ZcEvLwp0t8-rcyGn@five231003","threadId":"60303","inReplyTo":"20231023221143.72489-6-andy.koppe@gmail.com","subject":"Re: [PATCH v3 5/7] refs: add pseudorefs array and iteration functions","fromName":"Kousik Sanagavarapu","fromEmail":"five231003@gmail.com","sentAt":"2024-02-05T18:55:43Z","receivedAt":"2024-02-05T18:55:48Z","isPatch":true,"sender":{"key":"five231003@gmail.com","avatar":"https://avatars.githubusercontent.com/u/75560439?v=4"},"body":"Andy Koppe <andy.koppe@gmail.com> wrote:\n\n> Define const array 'pseudorefs' with the names of the pseudorefs that\n> are documented in gitrevisions.1, and add functions for_each_pseudoref()\n> and refs_for_each_pseudoref() for iterating over them.\n> \n> The functions process the pseudorefs in the same way as head_ref() and\n> refs_head_ref() process HEAD, invoking an each_ref_fn callback on each\n> pseudoref that exists.\n> \n> This is in preparation for adding pseudorefs to log decorations.\n> \n> Signed-off-by: Andy Koppe <andy.koppe@gmail.com>\n> ---\n\n[...]\n\n> +/*\n> + * List of documented pseudorefs. This needs to be kept in sync with the list\n> + * in Documentation/revisions.txt.\n> + */\n> +static const char *const pseudorefs[] = {\n> +\t\"FETCH_HEAD\",\n> +\t\"ORIG_HEAD\",\n> +\t\"MERGE_HEAD\",\n> +\t\"REBASE_HEAD\",\n> +\t\"CHERRY_PICK_HEAD\",\n> +\t\"REVERT_HEAD\",\n> +\t\"BISECT_HEAD\",\n> +\t\"AUTO_MERGE\",\n> +};\n> +\n>  struct ref_namespace_info ref_namespace[] = {\n>  \t[NAMESPACE_HEAD] = {\n>  \t\t.ref = \"HEAD\",\n> @@ -1549,6 +1564,33 @@ int head_ref(each_ref_fn fn, void *cb_data)\n>  \treturn refs_head_ref(get_main_ref_store(the_repository), fn, cb_data);\n>  }\n\nThe first thing that popped up in my head was \"Should we somehow use\nis_pseudoref_syntax() instead of manually listing these?\" (although I\nread in this thread later that Junio was okay with the listing) but then ...\n\nI thought I saw something similar in some other thread (which entered\nthe mailing list much after this patch series was submitted) ...\n\n\thttps://lore.kernel.org/git/20231221170715.110565-2-karthik.188@gmail.com/T/\n\nThe whole thread is really interesting but some points that are worth to\nbe mentioned in this context are\n\n\t\" ... Patrick's reftable work based on Han-Wen's work revealed\n\tthe need to treat FETCH_HEAD and MERGE_HEAD as \"even more\n\tpecurilar than pseudorefs\" that need different term (tentatively\n\tcalled \"special refs\") ... \"\n\nSo since we are introducing this array in refs.c, which acts as a \"refs\nAPI\" currently\n\n\t\"A lot more reasonable thing to do may be to scan the\n\t$GIT_DIR for files whose name satisfy refs.c:is_pseudoref_syntax()\n\tand list them, instead of having a hardcoded list of these special\n\trefs.  In addition, when reftable and other backends that can\n\tnatively store things outside refs/ hierarchy is in use, they ought\n\tto know what they have so enumerating these would not be an issue\n\tfor them without having such a hardcoded table of names.\"\n\nAll that said, the above mentioned thread led to a series of patches for\na different purpose than this [1] (which are currently on their way to\n\"master\" according to the latest \"What's Cooking\" email on Feb 2).  The\nones that have significance w.r.t. to THIS patch series though, are\n\n\thttps://lore.kernel.org/git/20240129113527.607022-2-karthik.188@gmail.com/\n\thttps://lore.kernel.org/git/20240129113527.607022-4-karthik.188@gmail.com/\n\n(ignoring the reftable part).\n\nI find these to make sense HERE because using the functions introduced\nTHERE are much more robust when dealing with pseudorefs and can be used\nHERE.\n\nI haven't given it much thought but I think we would still end up\nwriting \"for_each_pseudoref()\", although much differently from below\n(and can't use \"refs_for_each_all_refs()\" directly) because of how we\ncall this function in PATCH 7/7 when actually doing the decoration - that\nis the decoration for pseudorefs is different (?)\n\nAnother approach would be I think to refactor the whole of how\ndecorations with refs work and somehow use \"refs_for_each_all_refs()\"\nwith its callback handling how we decorate the various refs - I need to\ndig deeper :) - since the end goal is to support showing all kinds of\nrefs when showing the log\n\n\t$ git log -1 --clear-decorations --oneline master\n\t2a540e432f (ORIG_HEAD, FETCH_HEAD, upstream/master, upstream/HEAD, master) The thirteenth batch\n\n(with color enabled)\n\n> +int refs_for_each_pseudoref(struct ref_store *refs,\n> +\t\t\t    each_ref_fn fn, void *cb_data)\n> +{\n> +\tint i;\n> +\n> +\tfor (i = 0; i < ARRAY_SIZE(pseudorefs); i++) {\n> +\t\tstruct object_id oid;\n> +\t\tint flag;\n> +\n> +\t\tif (refs_resolve_ref_unsafe(refs, pseudorefs[i],\n> +\t\t\t\t\t    RESOLVE_REF_READING, &oid, &flag)) {\n> +\t\t\tint ret = fn(pseudorefs[i], &oid, flag, cb_data);\n> +\n> +\t\t\tif (ret)\n> +\t\t\t\treturn ret;\n> +\t\t}\n> +\t}\n> +\n> +\treturn 0;\n> +}\n> +\n> +int for_each_pseudoref(each_ref_fn fn, void *cb_data)\n> +{\n> +\treturn refs_for_each_pseudoref(get_main_ref_store(the_repository),\n> +\t\t\t\t       fn, cb_data);\n> +}\n> +\n>  struct ref_iterator *refs_ref_iterator_begin(\n>  \t\tstruct ref_store *refs,\n>  \t\tconst char *prefix,\n> diff --git a/refs.h b/refs.h\n> index 23211a5ea1..7b55cced31 100644\n> --- a/refs.h\n> +++ b/refs.h\n> @@ -320,6 +320,8 @@ typedef int each_repo_ref_fn(struct repository *r,\n>   */\n>  int refs_head_ref(struct ref_store *refs,\n>  \t\t  each_ref_fn fn, void *cb_data);\n> +int refs_for_each_pseudoref(struct ref_store *refs,\n> +\t\t\t    each_ref_fn fn, void *cb_data);\n>  int refs_for_each_ref(struct ref_store *refs,\n>  \t\t      each_ref_fn fn, void *cb_data);\n>  int refs_for_each_ref_in(struct ref_store *refs, const char *prefix,\n> @@ -334,6 +336,9 @@ int refs_for_each_remote_ref(struct ref_store *refs,\n>  /* just iterates the head ref. */\n>  int head_ref(each_ref_fn fn, void *cb_data);\n>  \n> +/* iterates pseudorefs. */\n> +int for_each_pseudoref(each_ref_fn fn, void *cb_data);\n> +\n>  /* iterates all refs. */\n>  int for_each_ref(each_ref_fn fn, void *cb_data);\n>  \n> -- \n> 2.42.GIT\n\nSo yeah, I just wanted to point out the above things as we would need to\nrefactor this commit and the commits following this - patches 6/7 and 7/7.\n\nThanks\n\n[1]: https://lore.kernel.org/git/20240129113527.607022-1-karthik.188@gmail.com/\n"},{"id":"488188","messageId":"xmqqcyt853vz.fsf@gitster.g","threadId":"60303","inReplyTo":"ZcEvLwp0t8-rcyGn@five231003","subject":"Re: [PATCH v3 5/7] refs: add pseudorefs array and iteration functions","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2024-02-07T22:02:56Z","receivedAt":"2024-02-07T22:03:02Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Kousik Sanagavarapu <five231003@gmail.com> writes:\n\n> Andy Koppe <andy.koppe@gmail.com> wrote:\n> ...\n>> +static const char *const pseudorefs[] = {\n>> +\t\"FETCH_HEAD\",\n>> +\t\"ORIG_HEAD\",\n>> +\t\"MERGE_HEAD\",\n>> +\t\"REBASE_HEAD\",\n>> +\t\"CHERRY_PICK_HEAD\",\n>> +\t\"REVERT_HEAD\",\n>> +\t\"BISECT_HEAD\",\n>> +\t\"AUTO_MERGE\",\n>> +};\n>> +\n>>  struct ref_namespace_info ref_namespace[] = {\n>>  \t[NAMESPACE_HEAD] = {\n>>  \t\t.ref = \"HEAD\",\n>> @@ -1549,6 +1564,33 @@ int head_ref(each_ref_fn fn, void *cb_data)\n>>  \treturn refs_head_ref(get_main_ref_store(the_repository), fn, cb_data);\n>>  }\n>\n> The first thing that popped up in my head was \"Should we somehow use\n> is_pseudoref_syntax() instead of manually listing these?\" (although I\n> read in this thread later that Junio was okay with the listing) but then ...\n>\n> I thought I saw something similar in some other thread (which entered\n> the mailing list much after this patch series was submitted) ...\n>\n> \thttps://lore.kernel.org/git/20231221170715.110565-2-karthik.188@gmail.com/T/\n\nWe are halting Karthik's topic to rethink its UI for now, but your\npoint stands.  We should use a unified definition of what pseudorefs\nthere are across the codebase for consistency, and Karthik's topic\nwould be a better place to do so.\n\nAndy, let me drop this topic for now from my tree, and let's wait\nuntil Karthik's \"iterate over all refs\" topic solidifies, at which\ntime an updated iteration (v4?)  of this topic hopefully can build\non top of it.\n\nThanks.\n"}]}