log: add log.excludeDecoration config option

In 'git log', the --decorate-refs-exclude option appends a pattern
to a string_list. This list is used to prevent showing some refs
in the decoration output, or even by --simplify-by-decoration.

Users may want to use their refs space to store utility refs that
should not appear in the decoration output. For example, Scalar [1]
runs a background fetch but places the "new" refs inside the
refs/scalar/hidden/<remote>/* refspace instead of refs/<remote>/*
to avoid updating remote refs when the user is not looking. However,
these "hidden" refs appear during regular 'git log' queries.

A similar idea to use "hidden" refs is under consideration for core
Git [2].

Add the 'log.excludeDecoration' config option so users can exclude
some refs from decorations by default instead of needing to use
--decorate-refs-exclude manually. The config value is multi-valued
much like the command-line option. The documentation is careful to
point out that the config value can be overridden by the
--decorate-refs option, even though --decorate-refs-exclude would
always "win" over --decorate-refs.

Since the 'log.excludeDecoration' takes lower precedence to
--decorate-refs, and --decorate-refs-exclude takes higher
precedence, the struct decoration_filter needed another field.
This led also to new logic in load_ref_decorations() and
ref_filter_match().

There are several tests in t4202-log.sh that test the
--decorate-refs-(include|exclude) options, so these are extended.
Since the expected output is already stored as a file, most tests
could simply replace a "--decorate-refs-exclude" option with an
in-line config setting. Other tests involve the precedence of
the config option compared to command-line options and needed more
modification.

[1] https://github.com/microsoft/scalar
[2] https://lore.kernel.org/git/77b1da5d3063a2404cd750adfe3bb8be9b6c497d.1585946894.git.gitgitgadget@gmail.com/

Helped-by: Junio C Hamano <gister@pobox.com>
Signed-off-by: Derrick Stolee <dstolee@microsoft.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Derrick Stolee 2020-04-16 14:15:49 +00:00 committed by Junio C Hamano
parent c9f7a793e8
commit a6be5e6764
6 changed files with 94 additions and 12 deletions

View File

@ -18,6 +18,12 @@ log.decorate::
names are shown. This is the same as the `--decorate` option names are shown. This is the same as the `--decorate` option
of the `git log`. of the `git log`.
log.excludeDecoration::
Exclude the specified patterns from the log decorations. This is
similar to the `--decorate-refs-exclude` command-line option, but
the config option can be overridden by the `--decorate-refs`
option.
log.follow:: log.follow::
If `true`, `git log` will act as if the `--follow` option was used when If `true`, `git log` will act as if the `--follow` option was used when
a single <path> is given. This has the same limitations as `--follow`, a single <path> is given. This has the same limitations as `--follow`,

View File

@ -43,7 +43,10 @@ OPTIONS
If no `--decorate-refs` is given, pretend as if all refs were If no `--decorate-refs` is given, pretend as if all refs were
included. For each candidate, do not use it for decoration if it included. For each candidate, do not use it for decoration if it
matches any patterns given to `--decorate-refs-exclude` or if it matches any patterns given to `--decorate-refs-exclude` or if it
doesn't match any of the patterns given to `--decorate-refs`. doesn't match any of the patterns given to `--decorate-refs`. The
`log.excludeDecoration` config option allows excluding refs from
the decorations, but an explicit `--decorate-refs` pattern will
override a match in `log.excludeDecoration`.
--source:: --source::
Print out the ref name given on the command line by which each Print out the ref name given on the command line by which each

View File

@ -164,9 +164,11 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
int quiet = 0, source = 0, mailmap; int quiet = 0, source = 0, mailmap;
static struct line_opt_callback_data line_cb = {NULL, NULL, STRING_LIST_INIT_DUP}; static struct line_opt_callback_data line_cb = {NULL, NULL, STRING_LIST_INIT_DUP};
static struct string_list decorate_refs_exclude = STRING_LIST_INIT_NODUP; static struct string_list decorate_refs_exclude = STRING_LIST_INIT_NODUP;
static struct string_list decorate_refs_exclude_config = STRING_LIST_INIT_NODUP;
static struct string_list decorate_refs_include = STRING_LIST_INIT_NODUP; static struct string_list decorate_refs_include = STRING_LIST_INIT_NODUP;
struct decoration_filter decoration_filter = {&decorate_refs_include, struct decoration_filter decoration_filter = {&decorate_refs_include,
&decorate_refs_exclude}; &decorate_refs_exclude,
&decorate_refs_exclude_config};
static struct revision_sources revision_sources; static struct revision_sources revision_sources;
const struct option builtin_log_options[] = { const struct option builtin_log_options[] = {
@ -236,7 +238,19 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
} }
if (decoration_style) { if (decoration_style) {
const struct string_list *config_exclude =
repo_config_get_value_multi(the_repository,
"log.excludeDecoration");
if (config_exclude) {
struct string_list_item *item;
for_each_string_list_item(item, config_exclude)
string_list_append(&decorate_refs_exclude_config,
item->string);
}
rev->show_decorations = 1; rev->show_decorations = 1;
load_ref_decorations(&decoration_filter, decoration_style); load_ref_decorations(&decoration_filter, decoration_style);
} }

View File

@ -103,6 +103,8 @@ static int ref_filter_match(const char *refname,
struct string_list_item *item; struct string_list_item *item;
const struct string_list *exclude_patterns = filter->exclude_ref_pattern; const struct string_list *exclude_patterns = filter->exclude_ref_pattern;
const struct string_list *include_patterns = filter->include_ref_pattern; const struct string_list *include_patterns = filter->include_ref_pattern;
const struct string_list *exclude_patterns_config =
filter->exclude_ref_config_pattern;
if (exclude_patterns && exclude_patterns->nr) { if (exclude_patterns && exclude_patterns->nr) {
for_each_string_list_item(item, exclude_patterns) { for_each_string_list_item(item, exclude_patterns) {
@ -112,17 +114,20 @@ static int ref_filter_match(const char *refname,
} }
if (include_patterns && include_patterns->nr) { if (include_patterns && include_patterns->nr) {
int found = 0;
for_each_string_list_item(item, include_patterns) { for_each_string_list_item(item, include_patterns) {
if (match_ref_pattern(refname, item)) { if (match_ref_pattern(refname, item))
found = 1; return 1;
break;
}
} }
return 0;
if (!found)
return 0;
} }
if (exclude_patterns_config && exclude_patterns_config->nr) {
for_each_string_list_item(item, exclude_patterns_config) {
if (match_ref_pattern(refname, item))
return 0;
}
}
return 1; return 1;
} }
@ -198,6 +203,9 @@ void load_ref_decorations(struct decoration_filter *filter, int flags)
for_each_string_list_item(item, filter->include_ref_pattern) { for_each_string_list_item(item, filter->include_ref_pattern) {
normalize_glob_ref(item, NULL, item->string); normalize_glob_ref(item, NULL, item->string);
} }
for_each_string_list_item(item, filter->exclude_ref_config_pattern) {
normalize_glob_ref(item, NULL, item->string);
}
} }
decoration_loaded = 1; decoration_loaded = 1;
decoration_flags = flags; decoration_flags = flags;

View File

@ -8,7 +8,9 @@ struct log_info {
}; };
struct decoration_filter { struct decoration_filter {
struct string_list *include_ref_pattern, *exclude_ref_pattern; struct string_list *include_ref_pattern;
struct string_list *exclude_ref_pattern;
struct string_list *exclude_ref_config_pattern;
}; };
int parse_decorate_color_config(const char *var, const char *slot_name, const char *value); int parse_decorate_color_config(const char *var, const char *slot_name, const char *value);

View File

@ -742,8 +742,24 @@ test_expect_success 'decorate-refs with glob' '
octopus-a (octopus-a) octopus-a (octopus-a)
reach reach
EOF EOF
cat >expect.no-decorate <<-\EOF &&
Merge-tag-reach
Merge-tags-octopus-a-and-octopus-b
seventh
octopus-b
octopus-a
reach
EOF
git log -n6 --decorate=short --pretty="tformat:%f%d" \ git log -n6 --decorate=short --pretty="tformat:%f%d" \
--decorate-refs="heads/octopus*" >actual && --decorate-refs="heads/octopus*" >actual &&
test_cmp expect.decorate actual &&
git log -n6 --decorate=short --pretty="tformat:%f%d" \
--decorate-refs-exclude="heads/octopus*" \
--decorate-refs="heads/octopus*" >actual &&
test_cmp expect.no-decorate actual &&
git -c log.excludeDecoration="heads/octopus*" log \
-n6 --decorate=short --pretty="tformat:%f%d" \
--decorate-refs="heads/octopus*" >actual &&
test_cmp expect.decorate actual test_cmp expect.decorate actual
' '
@ -787,6 +803,9 @@ test_expect_success 'decorate-refs-exclude with glob' '
EOF EOF
git log -n6 --decorate=short --pretty="tformat:%f%d" \ git log -n6 --decorate=short --pretty="tformat:%f%d" \
--decorate-refs-exclude="heads/octopus*" >actual && --decorate-refs-exclude="heads/octopus*" >actual &&
test_cmp expect.decorate actual &&
git -c log.excludeDecoration="heads/octopus*" log \
-n6 --decorate=short --pretty="tformat:%f%d" >actual &&
test_cmp expect.decorate actual test_cmp expect.decorate actual
' '
@ -801,6 +820,9 @@ test_expect_success 'decorate-refs-exclude without globs' '
EOF EOF
git log -n6 --decorate=short --pretty="tformat:%f%d" \ git log -n6 --decorate=short --pretty="tformat:%f%d" \
--decorate-refs-exclude="tags/reach" >actual && --decorate-refs-exclude="tags/reach" >actual &&
test_cmp expect.decorate actual &&
git -c log.excludeDecoration="tags/reach" log \
-n6 --decorate=short --pretty="tformat:%f%d" >actual &&
test_cmp expect.decorate actual test_cmp expect.decorate actual
' '
@ -816,11 +838,19 @@ test_expect_success 'multiple decorate-refs-exclude' '
git log -n6 --decorate=short --pretty="tformat:%f%d" \ git log -n6 --decorate=short --pretty="tformat:%f%d" \
--decorate-refs-exclude="heads/octopus*" \ --decorate-refs-exclude="heads/octopus*" \
--decorate-refs-exclude="tags/reach" >actual && --decorate-refs-exclude="tags/reach" >actual &&
test_cmp expect.decorate actual &&
git -c log.excludeDecoration="heads/octopus*" \
-c log.excludeDecoration="tags/reach" log \
-n6 --decorate=short --pretty="tformat:%f%d" >actual &&
test_cmp expect.decorate actual &&
git -c log.excludeDecoration="heads/octopus*" log \
--decorate-refs-exclude="tags/reach" \
-n6 --decorate=short --pretty="tformat:%f%d" >actual &&
test_cmp expect.decorate actual test_cmp expect.decorate actual
' '
test_expect_success 'decorate-refs and decorate-refs-exclude' ' test_expect_success 'decorate-refs and decorate-refs-exclude' '
cat >expect.decorate <<-\EOF && cat >expect.no-decorate <<-\EOF &&
Merge-tag-reach (master) Merge-tag-reach (master)
Merge-tags-octopus-a-and-octopus-b Merge-tags-octopus-a-and-octopus-b
seventh seventh
@ -831,6 +861,21 @@ test_expect_success 'decorate-refs and decorate-refs-exclude' '
git log -n6 --decorate=short --pretty="tformat:%f%d" \ git log -n6 --decorate=short --pretty="tformat:%f%d" \
--decorate-refs="heads/*" \ --decorate-refs="heads/*" \
--decorate-refs-exclude="heads/oc*" >actual && --decorate-refs-exclude="heads/oc*" >actual &&
test_cmp expect.no-decorate actual
'
test_expect_success 'deocrate-refs and log.excludeDecoration' '
cat >expect.decorate <<-\EOF &&
Merge-tag-reach (master)
Merge-tags-octopus-a-and-octopus-b
seventh
octopus-b (octopus-b)
octopus-a (octopus-a)
reach (reach)
EOF
git -c log.excludeDecoration="heads/oc*" log \
--decorate-refs="heads/*" \
-n6 --decorate=short --pretty="tformat:%f%d" >actual &&
test_cmp expect.decorate actual test_cmp expect.decorate actual
' '
@ -846,6 +891,10 @@ test_expect_success 'decorate-refs-exclude and simplify-by-decoration' '
git log -n6 --decorate=short --pretty="tformat:%f%d" \ git log -n6 --decorate=short --pretty="tformat:%f%d" \
--decorate-refs-exclude="*octopus*" \ --decorate-refs-exclude="*octopus*" \
--simplify-by-decoration >actual && --simplify-by-decoration >actual &&
test_cmp expect.decorate actual &&
git -c log.excludeDecoration="*octopus*" log \
-n6 --decorate=short --pretty="tformat:%f%d" \
--simplify-by-decoration >actual &&
test_cmp expect.decorate actual test_cmp expect.decorate actual
' '