diff mbox series

[v3,2/2] log: add log.excludeDecoration config option

Message ID 96c865e9214802021f8e991d2194b7aea6cd6bba.1587046549.git.gitgitgadget@gmail.com (mailing list archive)
State New, archived
Headers show
Series [v2] log: add log.excludeDecoration config option | expand

Commit Message

John Passaro via GitGitGadget April 16, 2020, 2:15 p.m. UTC
From: Derrick Stolee <dstolee@microsoft.com>

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>
---
 Documentation/config/log.txt |  6 +++++
 Documentation/git-log.txt    |  5 +++-
 builtin/log.c                | 16 ++++++++++-
 log-tree.c                   | 19 ++++++++++----
 log-tree.h                   |  4 ++-
 t/t4202-log.sh               | 51 +++++++++++++++++++++++++++++++++++-
 6 files changed, 92 insertions(+), 9 deletions(-)

Comments

Junio C Hamano April 16, 2020, 5:49 p.m. UTC | #1
"Derrick Stolee via GitGitGadget" <gitgitgadget@gmail.com> writes:

> diff --git a/log-tree.c b/log-tree.c
> index ab6d29a746b..fd3fd3316a1 100644
> --- a/log-tree.c
> +++ b/log-tree.c
> @@ -103,6 +103,8 @@ static int ref_filter_match(const char *refname,
>  	struct string_list_item *item;
>  	const struct string_list *exclude_patterns = filter->exclude_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) {
>  		for_each_string_list_item(item, exclude_patterns) {
> @@ -112,17 +114,21 @@ static int ref_filter_match(const char *refname,
>  	}
>  
>  	if (include_patterns && include_patterns->nr) {
> -		int found = 0;
>  		for_each_string_list_item(item, include_patterns) {
>  			if (match_ref_pattern(refname, item)) {
> -				found = 1;
> -				break;
> +				return 1;
>  			}

Micronit.  

Let's mimick the early return in the loop above (for command line
excludes) and below (for configured excludes), each of which is just
a single "return" statement in a block without {braces} around.

Other than that, looks nicely done.

The new tests are really appreciated, too.
Junio C Hamano April 16, 2020, 6:03 p.m. UTC | #2
Junio C Hamano <gitster@pobox.com> writes:

>>  	if (include_patterns && include_patterns->nr) {
>> -		int found = 0;
>>  		for_each_string_list_item(item, include_patterns) {
>>  			if (match_ref_pattern(refname, item)) {
>> -				found = 1;
>> -				break;
>> +				return 1;
>>  			}
>
> Micronit.  
>
> Let's mimick the early return in the loop above (for command line
> excludes) and below (for configured excludes), each of which is just
> a single "return" statement in a block without {braces} around.

... heh, it seems that the nit is mine in the suggested alternative
upthread.  Let me amend while queuing.

Thanks.
Derrick Stolee April 17, 2020, 1:53 a.m. UTC | #3
On 4/16/2020 2:03 PM, Junio C Hamano wrote:
> Junio C Hamano <gitster@pobox.com> writes:
> 
>>>  	if (include_patterns && include_patterns->nr) {
>>> -		int found = 0;
>>>  		for_each_string_list_item(item, include_patterns) {
>>>  			if (match_ref_pattern(refname, item)) {
>>> -				found = 1;
>>> -				break;
>>> +				return 1;
>>>  			}
>>
>> Micronit.  
>>
>> Let's mimick the early return in the loop above (for command line
>> excludes) and below (for configured excludes), each of which is just
>> a single "return" statement in a block without {braces} around.
> 
> ... heh, it seems that the nit is mine in the suggested alternative
> upthread.  Let me amend while queuing.

Shame on me for not noticing. Thanks for the close look!

-Stolee
Junio C Hamano April 17, 2020, 2:01 a.m. UTC | #4
Derrick Stolee <stolee@gmail.com> writes:

> On 4/16/2020 2:03 PM, Junio C Hamano wrote:
>> Junio C Hamano <gitster@pobox.com> writes:
>> 
>>>>  	if (include_patterns && include_patterns->nr) {
>>>> -		int found = 0;
>>>>  		for_each_string_list_item(item, include_patterns) {
>>>>  			if (match_ref_pattern(refname, item)) {
>>>> -				found = 1;
>>>> -				break;
>>>> +				return 1;
>>>>  			}
>>>
>>> Micronit.  
>>>
>>> Let's mimick the early return in the loop above (for command line
>>> excludes) and below (for configured excludes), each of which is just
>>> a single "return" statement in a block without {braces} around.
>> 
>> ... heh, it seems that the nit is mine in the suggested alternative
>> upthread.  Let me amend while queuing.
>
> Shame on me for not noticing. Thanks for the close look!

Heh, shame is mine, too ;-)

Thanks.
diff mbox series

Patch

diff --git a/Documentation/config/log.txt b/Documentation/config/log.txt
index e9e1e397f3f..208d5fdcaa6 100644
--- a/Documentation/config/log.txt
+++ b/Documentation/config/log.txt
@@ -18,6 +18,12 @@  log.decorate::
 	names are shown. This is the same as the `--decorate` option
 	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::
 	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`,
diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt
index bed09bb09e5..17592234ba4 100644
--- a/Documentation/git-log.txt
+++ b/Documentation/git-log.txt
@@ -43,7 +43,10 @@  OPTIONS
 	If no `--decorate-refs` is given, pretend as if all refs were
 	included.  For each candidate, do not use it for decoration 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::
 	Print out the ref name given on the command line by which each
diff --git a/builtin/log.c b/builtin/log.c
index 83a4a6188e2..72192710dcd 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -164,9 +164,11 @@  static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
 	int quiet = 0, source = 0, mailmap;
 	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_config = STRING_LIST_INIT_NODUP;
 	static struct string_list decorate_refs_include = STRING_LIST_INIT_NODUP;
 	struct decoration_filter decoration_filter = {&decorate_refs_include,
-						      &decorate_refs_exclude};
+						      &decorate_refs_exclude,
+						      &decorate_refs_exclude_config};
 	static struct revision_sources revision_sources;
 
 	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) {
+		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;
+
 		load_ref_decorations(&decoration_filter, decoration_style);
 	}
 
diff --git a/log-tree.c b/log-tree.c
index ab6d29a746b..fd3fd3316a1 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -103,6 +103,8 @@  static int ref_filter_match(const char *refname,
 	struct string_list_item *item;
 	const struct string_list *exclude_patterns = filter->exclude_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) {
 		for_each_string_list_item(item, exclude_patterns) {
@@ -112,17 +114,21 @@  static int ref_filter_match(const char *refname,
 	}
 
 	if (include_patterns && include_patterns->nr) {
-		int found = 0;
 		for_each_string_list_item(item, include_patterns) {
 			if (match_ref_pattern(refname, item)) {
-				found = 1;
-				break;
+				return 1;
 			}
 		}
+		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;
 }
 
@@ -198,6 +204,9 @@  void load_ref_decorations(struct decoration_filter *filter, int flags)
 			for_each_string_list_item(item, filter->include_ref_pattern) {
 				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_flags = flags;
diff --git a/log-tree.h b/log-tree.h
index e6686280746..8fa79289ec6 100644
--- a/log-tree.h
+++ b/log-tree.h
@@ -8,7 +8,9 @@  struct log_info {
 };
 
 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);
diff --git a/t/t4202-log.sh b/t/t4202-log.sh
index 0f766ba65f5..78f9ade6870 100755
--- a/t/t4202-log.sh
+++ b/t/t4202-log.sh
@@ -742,7 +742,23 @@  test_expect_success 'decorate-refs with glob' '
 	octopus-a (octopus-a)
 	reach
 	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" \
+		--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
 '
@@ -787,6 +803,9 @@  test_expect_success 'decorate-refs-exclude with glob' '
 	EOF
 	git log -n6 --decorate=short --pretty="tformat:%f%d" \
 		--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
 '
 
@@ -801,6 +820,9 @@  test_expect_success 'decorate-refs-exclude without globs' '
 	EOF
 	git log -n6 --decorate=short --pretty="tformat:%f%d" \
 		--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
 '
 
@@ -816,11 +838,19 @@  test_expect_success 'multiple decorate-refs-exclude' '
 	git log -n6 --decorate=short --pretty="tformat:%f%d" \
 		--decorate-refs-exclude="heads/octopus*" \
 		--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_expect_success 'decorate-refs and decorate-refs-exclude' '
-	cat >expect.decorate <<-\EOF &&
+	cat >expect.no-decorate <<-\EOF &&
 	Merge-tag-reach (master)
 	Merge-tags-octopus-a-and-octopus-b
 	seventh
@@ -831,6 +861,21 @@  test_expect_success 'decorate-refs and decorate-refs-exclude' '
 	git log -n6 --decorate=short --pretty="tformat:%f%d" \
 		--decorate-refs="heads/*" \
 		--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
 '
 
@@ -846,6 +891,10 @@  test_expect_success 'decorate-refs-exclude and simplify-by-decoration' '
 	git log -n6 --decorate=short --pretty="tformat:%f%d" \
 		--decorate-refs-exclude="*octopus*" \
 		--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
 '