Merge branch 'ra/decorate-limit-refs'
The tagnames "git log --decorate" uses to annotate the commits can now be limited to subset of available refs with the two additional options, --decorate-refs[-exclude]=<pattern>. * ra/decorate-limit-refs: log: add option to choose which refs to decorate
This commit is contained in:
commit
6c3daa2346
@ -38,6 +38,13 @@ OPTIONS
|
||||
are shown as if 'short' were given, otherwise no ref names are
|
||||
shown. The default option is 'short'.
|
||||
|
||||
--decorate-refs=<pattern>::
|
||||
--decorate-refs-exclude=<pattern>::
|
||||
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`.
|
||||
|
||||
--source::
|
||||
Print out the ref name given on the command line by which each
|
||||
commit was reached.
|
||||
|
@ -142,11 +142,19 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
|
||||
struct userformat_want w;
|
||||
int quiet = 0, source = 0, mailmap = 0;
|
||||
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_include = STRING_LIST_INIT_NODUP;
|
||||
struct decoration_filter decoration_filter = {&decorate_refs_include,
|
||||
&decorate_refs_exclude};
|
||||
|
||||
const struct option builtin_log_options[] = {
|
||||
OPT__QUIET(&quiet, N_("suppress diff output")),
|
||||
OPT_BOOL(0, "source", &source, N_("show source")),
|
||||
OPT_BOOL(0, "use-mailmap", &mailmap, N_("Use mail map file")),
|
||||
OPT_STRING_LIST(0, "decorate-refs", &decorate_refs_include,
|
||||
N_("pattern"), N_("only decorate refs that match <pattern>")),
|
||||
OPT_STRING_LIST(0, "decorate-refs-exclude", &decorate_refs_exclude,
|
||||
N_("pattern"), N_("do not decorate refs that match <pattern>")),
|
||||
{ OPTION_CALLBACK, 0, "decorate", NULL, NULL, N_("decorate options"),
|
||||
PARSE_OPT_OPTARG, decorate_callback},
|
||||
OPT_CALLBACK('L', NULL, &line_cb, "n,m:file",
|
||||
@ -205,7 +213,7 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
|
||||
|
||||
if (decoration_style) {
|
||||
rev->show_decorations = 1;
|
||||
load_ref_decorations(decoration_style);
|
||||
load_ref_decorations(&decoration_filter, decoration_style);
|
||||
}
|
||||
|
||||
if (rev->line_level_traverse)
|
||||
|
24
log-tree.c
24
log-tree.c
@ -94,8 +94,12 @@ static int add_ref_decoration(const char *refname, const struct object_id *oid,
|
||||
{
|
||||
struct object *obj;
|
||||
enum decoration_type type = DECORATION_NONE;
|
||||
struct decoration_filter *filter = (struct decoration_filter *)cb_data;
|
||||
|
||||
assert(cb_data == NULL);
|
||||
if (filter && !ref_filter_match(refname,
|
||||
filter->include_ref_pattern,
|
||||
filter->exclude_ref_pattern))
|
||||
return 0;
|
||||
|
||||
if (starts_with(refname, git_replace_ref_base)) {
|
||||
struct object_id original_oid;
|
||||
@ -148,15 +152,23 @@ static int add_graft_decoration(const struct commit_graft *graft, void *cb_data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void load_ref_decorations(int flags)
|
||||
void load_ref_decorations(struct decoration_filter *filter, int flags)
|
||||
{
|
||||
if (!decoration_loaded) {
|
||||
|
||||
if (filter) {
|
||||
struct string_list_item *item;
|
||||
for_each_string_list_item(item, filter->exclude_ref_pattern) {
|
||||
normalize_glob_ref(item, NULL, item->string);
|
||||
}
|
||||
for_each_string_list_item(item, filter->include_ref_pattern) {
|
||||
normalize_glob_ref(item, NULL, item->string);
|
||||
}
|
||||
}
|
||||
decoration_loaded = 1;
|
||||
decoration_flags = flags;
|
||||
for_each_ref(add_ref_decoration, NULL);
|
||||
head_ref(add_ref_decoration, NULL);
|
||||
for_each_commit_graft(add_graft_decoration, NULL);
|
||||
for_each_ref(add_ref_decoration, filter);
|
||||
head_ref(add_ref_decoration, filter);
|
||||
for_each_commit_graft(add_graft_decoration, filter);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,10 @@ struct log_info {
|
||||
struct commit *commit, *parent;
|
||||
};
|
||||
|
||||
struct decoration_filter {
|
||||
struct string_list *include_ref_pattern, *exclude_ref_pattern;
|
||||
};
|
||||
|
||||
int parse_decorate_color_config(const char *var, const char *slot_name, const char *value);
|
||||
void init_log_tree_opt(struct rev_info *);
|
||||
int log_tree_diff_flush(struct rev_info *);
|
||||
@ -24,7 +28,7 @@ void show_decorations(struct rev_info *opt, struct commit *commit);
|
||||
void log_write_email_headers(struct rev_info *opt, struct commit *commit,
|
||||
const char **extra_headers_p,
|
||||
int *need_8bit_cte_p);
|
||||
void load_ref_decorations(int flags);
|
||||
void load_ref_decorations(struct decoration_filter *filter, int flags);
|
||||
|
||||
#define FORMAT_PATCH_NAME_MAX 64
|
||||
void fmt_output_commit(struct strbuf *, struct commit *, struct rev_info *);
|
||||
|
4
pretty.c
4
pretty.c
@ -1186,11 +1186,11 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
|
||||
strbuf_addstr(sb, get_revision_mark(NULL, commit));
|
||||
return 1;
|
||||
case 'd':
|
||||
load_ref_decorations(DECORATE_SHORT_REFS);
|
||||
load_ref_decorations(NULL, DECORATE_SHORT_REFS);
|
||||
format_decorations(sb, commit, c->auto_color);
|
||||
return 1;
|
||||
case 'D':
|
||||
load_ref_decorations(DECORATE_SHORT_REFS);
|
||||
load_ref_decorations(NULL, DECORATE_SHORT_REFS);
|
||||
format_decorations_extended(sb, commit, c->auto_color, "", ", ", "");
|
||||
return 1;
|
||||
case 'g': /* reflog info */
|
||||
|
65
refs.c
65
refs.c
@ -242,6 +242,50 @@ int ref_exists(const char *refname)
|
||||
return !!resolve_ref_unsafe(refname, RESOLVE_REF_READING, NULL, NULL);
|
||||
}
|
||||
|
||||
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,
|
||||
int flags, void *data)
|
||||
{
|
||||
@ -369,6 +413,27 @@ int head_ref_namespaced(each_ref_fn fn, void *cb_data)
|
||||
return ret;
|
||||
}
|
||||
|
||||
void normalize_glob_ref(struct string_list_item *item, const char *prefix,
|
||||
const char *pattern)
|
||||
{
|
||||
struct strbuf normalized_pattern = STRBUF_INIT;
|
||||
|
||||
if (*pattern == '/')
|
||||
BUG("pattern must not start with '/'");
|
||||
|
||||
if (prefix) {
|
||||
strbuf_addstr(&normalized_pattern, prefix);
|
||||
}
|
||||
else if (!starts_with(pattern, "refs/"))
|
||||
strbuf_addstr(&normalized_pattern, "refs/");
|
||||
strbuf_addstr(&normalized_pattern, pattern);
|
||||
strbuf_strip_suffix(&normalized_pattern, "/");
|
||||
|
||||
item->string = strbuf_detach(&normalized_pattern, NULL);
|
||||
item->util = has_glob_specials(pattern) ? NULL : item->string;
|
||||
strbuf_release(&normalized_pattern);
|
||||
}
|
||||
|
||||
int for_each_glob_ref_in(each_ref_fn fn, const char *pattern,
|
||||
const char *prefix, void *cb_data)
|
||||
{
|
||||
|
24
refs.h
24
refs.h
@ -312,6 +312,30 @@ int for_each_namespaced_ref(each_ref_fn fn, void *cb_data);
|
||||
int refs_for_each_rawref(struct ref_store *refs, each_ref_fn fn, void *cb_data);
|
||||
int for_each_rawref(each_ref_fn fn, void *cb_data);
|
||||
|
||||
/*
|
||||
* Normalizes partial refs to their fully qualified form.
|
||||
* Will prepend <prefix> to the <pattern> if it doesn't start with 'refs/'.
|
||||
* <prefix> will default to 'refs/' if NULL.
|
||||
*
|
||||
* item.string will be set to the result.
|
||||
* item.util will be set to NULL if <pattern> contains glob characters, or
|
||||
* non-NULL if it doesn't.
|
||||
*/
|
||||
void normalize_glob_ref(struct string_list_item *item, const char *prefix,
|
||||
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)
|
||||
{
|
||||
return strpbrk(pattern, "?*[");
|
||||
|
@ -1832,7 +1832,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
|
||||
revs->simplify_by_decoration = 1;
|
||||
revs->limited = 1;
|
||||
revs->prune = 1;
|
||||
load_ref_decorations(DECORATE_SHORT_REFS);
|
||||
load_ref_decorations(NULL, DECORATE_SHORT_REFS);
|
||||
} else if (!strcmp(arg, "--date-order")) {
|
||||
revs->sort_order = REV_SORT_BY_COMMIT_DATE;
|
||||
revs->topo_order = 1;
|
||||
|
101
t/t4202-log.sh
101
t/t4202-log.sh
@ -737,6 +737,107 @@ test_expect_success 'log.decorate configuration' '
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'decorate-refs with glob' '
|
||||
cat >expect.decorate <<-\EOF &&
|
||||
Merge-tag-reach
|
||||
Merge-tags-octopus-a-and-octopus-b
|
||||
seventh
|
||||
octopus-b (octopus-b)
|
||||
octopus-a (octopus-a)
|
||||
reach
|
||||
EOF
|
||||
git log -n6 --decorate=short --pretty="tformat:%f%d" \
|
||||
--decorate-refs="heads/octopus*" >actual &&
|
||||
test_cmp expect.decorate actual
|
||||
'
|
||||
|
||||
test_expect_success 'decorate-refs without globs' '
|
||||
cat >expect.decorate <<-\EOF &&
|
||||
Merge-tag-reach
|
||||
Merge-tags-octopus-a-and-octopus-b
|
||||
seventh
|
||||
octopus-b
|
||||
octopus-a
|
||||
reach (tag: reach)
|
||||
EOF
|
||||
git log -n6 --decorate=short --pretty="tformat:%f%d" \
|
||||
--decorate-refs="tags/reach" >actual &&
|
||||
test_cmp expect.decorate actual
|
||||
'
|
||||
|
||||
test_expect_success 'multiple decorate-refs' '
|
||||
cat >expect.decorate <<-\EOF &&
|
||||
Merge-tag-reach
|
||||
Merge-tags-octopus-a-and-octopus-b
|
||||
seventh
|
||||
octopus-b (octopus-b)
|
||||
octopus-a (octopus-a)
|
||||
reach (tag: reach)
|
||||
EOF
|
||||
git log -n6 --decorate=short --pretty="tformat:%f%d" \
|
||||
--decorate-refs="heads/octopus*" \
|
||||
--decorate-refs="tags/reach" >actual &&
|
||||
test_cmp expect.decorate actual
|
||||
'
|
||||
|
||||
test_expect_success 'decorate-refs-exclude with glob' '
|
||||
cat >expect.decorate <<-\EOF &&
|
||||
Merge-tag-reach (HEAD -> master)
|
||||
Merge-tags-octopus-a-and-octopus-b
|
||||
seventh (tag: seventh)
|
||||
octopus-b (tag: octopus-b)
|
||||
octopus-a (tag: octopus-a)
|
||||
reach (tag: reach, reach)
|
||||
EOF
|
||||
git log -n6 --decorate=short --pretty="tformat:%f%d" \
|
||||
--decorate-refs-exclude="heads/octopus*" >actual &&
|
||||
test_cmp expect.decorate actual
|
||||
'
|
||||
|
||||
test_expect_success 'decorate-refs-exclude without globs' '
|
||||
cat >expect.decorate <<-\EOF &&
|
||||
Merge-tag-reach (HEAD -> master)
|
||||
Merge-tags-octopus-a-and-octopus-b
|
||||
seventh (tag: seventh)
|
||||
octopus-b (tag: octopus-b, octopus-b)
|
||||
octopus-a (tag: octopus-a, octopus-a)
|
||||
reach (reach)
|
||||
EOF
|
||||
git log -n6 --decorate=short --pretty="tformat:%f%d" \
|
||||
--decorate-refs-exclude="tags/reach" >actual &&
|
||||
test_cmp expect.decorate actual
|
||||
'
|
||||
|
||||
test_expect_success 'multiple decorate-refs-exclude' '
|
||||
cat >expect.decorate <<-\EOF &&
|
||||
Merge-tag-reach (HEAD -> master)
|
||||
Merge-tags-octopus-a-and-octopus-b
|
||||
seventh (tag: seventh)
|
||||
octopus-b (tag: octopus-b)
|
||||
octopus-a (tag: octopus-a)
|
||||
reach (reach)
|
||||
EOF
|
||||
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
|
||||
'
|
||||
|
||||
test_expect_success 'decorate-refs and decorate-refs-exclude' '
|
||||
cat >expect.decorate <<-\EOF &&
|
||||
Merge-tag-reach (master)
|
||||
Merge-tags-octopus-a-and-octopus-b
|
||||
seventh
|
||||
octopus-b
|
||||
octopus-a
|
||||
reach (reach)
|
||||
EOF
|
||||
git log -n6 --decorate=short --pretty="tformat:%f%d" \
|
||||
--decorate-refs="heads/*" \
|
||||
--decorate-refs-exclude="heads/oc*" >actual &&
|
||||
test_cmp expect.decorate actual
|
||||
'
|
||||
|
||||
test_expect_success 'log.decorate config parsing' '
|
||||
git log --oneline --decorate=full >expect.full &&
|
||||
git log --oneline --decorate=short >expect.short &&
|
||||
|
Loading…
Reference in New Issue
Block a user