Merge branch 'ds/log-exclude-decoration-config'

The "--decorate-refs" and "--decorate-refs-exclude" options "git
log" takes have learned a companion configuration variable
log.excludeDecoration that sits at the lowest priority in the
family.

* ds/log-exclude-decoration-config:
  log: add log.excludeDecoration config option
  log-tree: make ref_filter_match() a helper method
This commit is contained in:
Junio C Hamano 2020-04-28 15:50:08 -07:00
Родитель 93d1f196a9 a6be5e6764
Коммит d3fc8dc53a
8 изменённых файлов: 132 добавлений и 63 удалений

Просмотреть файл

@ -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`,

Просмотреть файл

@ -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

Просмотреть файл

@ -166,9 +166,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[] = {
@ -239,7 +241,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);
} }

Просмотреть файл

@ -81,6 +81,56 @@ const struct name_decoration *get_name_decoration(const struct object *obj)
return lookup_decoration(&name_decoration, obj); return lookup_decoration(&name_decoration, obj);
} }
static int match_ref_pattern(const char *refname,
const struct string_list_item *item)
{
int matched = 0;
if (item->util == NULL) {
if (!wildmatch(item->string, refname, 0))
matched = 1;
} else {
const char *rest;
if (skip_prefix(refname, item->string, &rest) &&
(!*rest || *rest == '/'))
matched = 1;
}
return matched;
}
static int ref_filter_match(const char *refname,
const struct decoration_filter *filter)
{
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) {
if (match_ref_pattern(refname, item))
return 0;
}
}
if (include_patterns && include_patterns->nr) {
for_each_string_list_item(item, include_patterns) {
if (match_ref_pattern(refname, item))
return 1;
}
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;
}
static int add_ref_decoration(const char *refname, const struct object_id *oid, static int add_ref_decoration(const char *refname, const struct object_id *oid,
int flags, void *cb_data) int flags, void *cb_data)
{ {
@ -88,9 +138,7 @@ static int add_ref_decoration(const char *refname, const struct object_id *oid,
enum decoration_type type = DECORATION_NONE; enum decoration_type type = DECORATION_NONE;
struct decoration_filter *filter = (struct decoration_filter *)cb_data; struct decoration_filter *filter = (struct decoration_filter *)cb_data;
if (filter && !ref_filter_match(refname, if (filter && !ref_filter_match(refname, filter))
filter->include_ref_pattern,
filter->exclude_ref_pattern))
return 0; return 0;
if (starts_with(refname, git_replace_ref_base)) { if (starts_with(refname, git_replace_ref_base)) {
@ -155,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;

Просмотреть файл

@ -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);

44
refs.c
Просмотреть файл

@ -321,50 +321,6 @@ int ref_exists(const char *refname)
return refs_ref_exists(get_main_ref_store(the_repository), refname); return refs_ref_exists(get_main_ref_store(the_repository), refname);
} }
static int match_ref_pattern(const char *refname,
const struct string_list_item *item)
{
int matched = 0;
if (item->util == NULL) {
if (!wildmatch(item->string, refname, 0))
matched = 1;
} else {
const char *rest;
if (skip_prefix(refname, item->string, &rest) &&
(!*rest || *rest == '/'))
matched = 1;
}
return matched;
}
int ref_filter_match(const char *refname,
const struct string_list *include_patterns,
const struct string_list *exclude_patterns)
{
struct string_list_item *item;
if (exclude_patterns && exclude_patterns->nr) {
for_each_string_list_item(item, exclude_patterns) {
if (match_ref_pattern(refname, item))
return 0;
}
}
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;
}
}
if (!found)
return 0;
}
return 1;
}
static int filter_refs(const char *refname, const struct object_id *oid, static int filter_refs(const char *refname, const struct object_id *oid,
int flags, void *data) int flags, void *data)
{ {

12
refs.h
Просмотреть файл

@ -361,18 +361,6 @@ int for_each_rawref(each_ref_fn fn, void *cb_data);
void normalize_glob_ref(struct string_list_item *item, const char *prefix, void normalize_glob_ref(struct string_list_item *item, const char *prefix,
const char *pattern); const char *pattern);
/*
* Returns 0 if refname matches any of the exclude_patterns, or if it doesn't
* match any of the include_patterns. Returns 1 otherwise.
*
* If pattern list is NULL or empty, matching against that list is skipped.
* This has the effect of matching everything by default, unless the user
* specifies rules otherwise.
*/
int ref_filter_match(const char *refname,
const struct string_list *include_patterns,
const struct string_list *exclude_patterns);
static inline const char *has_glob_specials(const char *pattern) static inline const char *has_glob_specials(const char *pattern)
{ {
return strpbrk(pattern, "?*["); return strpbrk(pattern, "?*[");

Просмотреть файл

@ -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
' '