All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Rafael Ascensão" <rafa.almas@gmail.com>
To: git@vger.kernel.org
Cc: "Rafael Ascensão" <rafa.almas@gmail.com>,
	me@ikke.info, gitster@pobox.com, hjemli@gmail.com,
	mhagger@alum.mit.edu, pclouds@gmail.com,
	ilari.liusvaara@elisanet.fi
Subject: [PATCH v1 2/2] log: add option to choose which refs to decorate
Date: Sat,  4 Nov 2017 00:41:44 +0000	[thread overview]
Message-ID: <20171104004144.5975-3-rafa.almas@gmail.com> (raw)
In-Reply-To: <20171104004144.5975-1-rafa.almas@gmail.com>

When `log --decorate` is used, git will decorate commits with all
available refs. While in most cases this the desired effect, under some
conditions it can lead to excessively verbose output.

Using `--exclude=<pattern>` can help mitigate that verboseness by
removing unnecessary 'branches' from the output. However, if the tip of
an excluded ref points to an ancestor of a non-excluded ref, git will
decorate it regardless.

With `--decorate-refs=<pattern>`, only refs that match <pattern> are
decorated while `--decorate-refs-exclude=<pattern>` allows to do the
reverse, remove ref decorations that match <pattern>

Both can be used together but --decorate-refs-exclude patterns have
precedence over --decorate-refs patterns.

The pattern follows similar rules as `--glob` except it doesn't assume a
trailing '/*' if glob characters are missing.

Both `--decorate-refs` and `--decorate-refs-exclude` can be used
multiple times.

Signed-off-by: Kevin Daudt <me@ikke.info>
Signed-off-by: Rafael Ascensão <rafa.almas@gmail.com>
---
 Documentation/git-log.txt |  12 ++++++
 builtin/log.c             |  10 ++++-
 log-tree.c                |  37 ++++++++++++++---
 log-tree.h                |   6 ++-
 pretty.c                  |   4 +-
 revision.c                |   2 +-
 t/t4202-log.sh            | 101 ++++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 162 insertions(+), 10 deletions(-)

diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt
index 32246fdb0..314417d89 100644
--- a/Documentation/git-log.txt
+++ b/Documentation/git-log.txt
@@ -38,6 +38,18 @@ OPTIONS
 	are shown as if 'short' were given, otherwise no ref names are
 	shown. The default option is 'short'.
 
+--decorate-refs=<pattern>::
+	Only print ref names that match the specified pattern. Uses the same
+	rules as `git rev-list --glob` except it doesn't assume a trailing a
+	trailing '/{asterisk}' if pattern lacks '?', '{asterisk}', or '['.
+	`--decorate-refs-exlclude` has precedence.
+
+--decorate-refs-exclude=<pattern>::
+	Do not print ref names that match the specified pattern. Uses the same
+	rules as `git rev-list --glob` except it doesn't assume a trailing a
+	trailing '/{asterisk}' if pattern lacks '?', '{asterisk}', or '['.
+	Has precedence over `--decorate-refs`.
+
 --source::
 	Print out the ref name given on the command line by which each
 	commit was reached.
diff --git a/builtin/log.c b/builtin/log.c
index d81a09051..3587c0055 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -143,11 +143,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_DUP;
+	static struct string_list decorate_refs_include = STRING_LIST_INIT_DUP;
+	struct ref_include_exclude_list ref_filter_lists = {&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_("ref"), N_("only decorate these refs")),
+		OPT_STRING_LIST(0, "decorate-refs-exclude", &decorate_refs_exclude,
+				N_("ref"), N_("do not decorate these refs")),
 		{ OPTION_CALLBACK, 0, "decorate", NULL, NULL, N_("decorate options"),
 		  PARSE_OPT_OPTARG, decorate_callback},
 		OPT_CALLBACK('L', NULL, &line_cb, "n,m:file",
@@ -206,7 +214,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_style, &ref_filter_lists);
 	}
 
 	if (rev->line_level_traverse)
diff --git a/log-tree.c b/log-tree.c
index cea056234..8efc7ac3d 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -94,9 +94,33 @@ static int add_ref_decoration(const char *refname, const struct object_id *oid,
 {
 	struct object *obj;
 	enum decoration_type type = DECORATION_NONE;
+	struct ref_include_exclude_list *filter = (struct ref_include_exclude_list *)cb_data;
+	struct string_list_item *item;
+	struct strbuf real_pattern = STRBUF_INIT;
+
+	if(filter && filter->exclude->nr > 0) {
+		/* if current ref is on the exclude list skip */
+		for_each_string_list_item(item, filter->exclude) {
+			strbuf_reset(&real_pattern);
+			normalize_glob_ref(&real_pattern, NULL, item->string, 0);
+			if (!wildmatch(real_pattern.buf, refname, 0))
+				goto finish;
+		}
+	}
 
-	assert(cb_data == NULL);
+	if (filter && filter->include->nr > 0) {
+		/* if current ref is present on the include jump to decorate */
+		for_each_string_list_item(item, filter->include) {
+			strbuf_reset(&real_pattern);
+			normalize_glob_ref(&real_pattern, NULL, item->string, 0);
+			if (!wildmatch(real_pattern.buf, refname, 0))
+				goto decorate;
+		}
+		/* Filter was given, but no match was found, skip */
+		goto finish;
+	}
 
+decorate:
 	if (starts_with(refname, git_replace_ref_base)) {
 		struct object_id original_oid;
 		if (!check_replace_refs)
@@ -136,6 +160,9 @@ static int add_ref_decoration(const char *refname, const struct object_id *oid,
 			parse_object(&obj->oid);
 		add_name_decoration(DECORATION_REF_TAG, refname, obj);
 	}
+
+finish:
+	strbuf_release(&real_pattern);
 	return 0;
 }
 
@@ -148,15 +175,15 @@ 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(int flags, struct ref_include_exclude_list *data)
 {
 	if (!decoration_loaded) {
 
 		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, data);
+		head_ref(add_ref_decoration, data);
+		for_each_commit_graft(add_graft_decoration, data);
 	}
 }
 
diff --git a/log-tree.h b/log-tree.h
index 48f11fb74..66563af88 100644
--- a/log-tree.h
+++ b/log-tree.h
@@ -7,6 +7,10 @@ struct log_info {
 	struct commit *commit, *parent;
 };
 
+struct ref_include_exclude_list {
+	struct string_list *include, *exclude;
+};
+
 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(int flags, struct ref_include_exclude_list *);
 
 #define FORMAT_PATCH_NAME_MAX 64
 void fmt_output_commit(struct strbuf *, struct commit *, struct rev_info *);
diff --git a/pretty.c b/pretty.c
index 2f6b0ae6c..87a6cc4f9 100644
--- a/pretty.c
+++ b/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(DECORATE_SHORT_REFS, NULL);
 		format_decorations(sb, commit, c->auto_color);
 		return 1;
 	case 'D':
-		load_ref_decorations(DECORATE_SHORT_REFS);
+		load_ref_decorations(DECORATE_SHORT_REFS, NULL);
 		format_decorations_extended(sb, commit, c->auto_color, "", ", ", "");
 		return 1;
 	case 'g':		/* reflog info */
diff --git a/revision.c b/revision.c
index d167223e6..298ff054b 100644
--- a/revision.c
+++ b/revision.c
@@ -1822,7 +1822,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(DECORATE_SHORT_REFS, NULL);
 	} else if (!strcmp(arg, "--date-order")) {
 		revs->sort_order = REV_SORT_BY_COMMIT_DATE;
 		revs->topo_order = 1;
diff --git a/t/t4202-log.sh b/t/t4202-log.sh
index 8f155da7a..e26d09a5c 100755
--- a/t/t4202-log.sh
+++ b/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="%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="%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 &&
-- 
2.15.0


  parent reply	other threads:[~2017-11-04  0:42 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-11-04  0:41 [PATCH v1 0/2] Add option to git log to choose which refs receive decoration Rafael Ascensão
2017-11-04  0:41 ` [PATCH v1 1/2] refs: extract function to normalize partial refs Rafael Ascensão
2017-11-04  2:27   ` Junio C Hamano
2017-11-04  7:33     ` Rafael Ascensão
2017-11-04 22:45     ` Kevin Daudt
2017-11-05 13:21       ` Michael Haggerty
2017-11-05 13:42   ` Michael Haggerty
2017-11-06  1:23     ` Junio C Hamano
2017-11-06  2:37       ` Rafael Ascensão
2017-11-06  7:00       ` Michael Haggerty
2017-11-04  0:41 ` Rafael Ascensão [this message]
2017-11-04  3:49   ` [PATCH v1 2/2] log: add option to choose which refs to decorate Junio C Hamano
2017-11-04  7:34     ` Rafael Ascensão
2017-11-05  2:00       ` Junio C Hamano
2017-11-05  6:17         ` Junio C Hamano
2017-11-06  3:24           ` Rafael Ascensão
2017-11-06  3:51             ` Junio C Hamano
2017-11-06  7:09           ` Michael Haggerty
2017-11-06 20:10     ` Jacob Keller
2017-11-07  0:18       ` Junio C Hamano
2017-11-10 13:38         ` Rafael Ascensão
2017-11-10 17:42           ` Junio C Hamano
2017-11-21 21:33 ` [PATCH v2] " Rafael Ascensão
2017-11-22  4:18   ` Junio C Hamano

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20171104004144.5975-3-rafa.almas@gmail.com \
    --to=rafa.almas@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    --cc=hjemli@gmail.com \
    --cc=ilari.liusvaara@elisanet.fi \
    --cc=me@ikke.info \
    --cc=mhagger@alum.mit.edu \
    --cc=pclouds@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.