git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* [PATCH v6 00/11] add options to for-each-ref
@ 2015-06-25  8:46 Karthik Nayak
  2015-06-25  8:57 ` [PATCH v6 01/11] t6302: for-each-ref tests for ref-filter APIs Karthik Nayak
  0 siblings, 1 reply; 25+ messages in thread
From: Karthik Nayak @ 2015-06-25  8:46 UTC (permalink / raw)
  To: Git; +Cc: Junio C Hamano, Christian Couder, Matthieu Moy

v5 of this patch series can be found here :
http://article.gmane.org/gmane.comp.version-control.git/272590

This is a continuation of my GSoC project to unify git tag -l, git
branch -l and for-each-ref. Continued from this patch series :
http://thread.gmane.org/gmane.comp.version-control.git/271563

Changes in v5:
03/11: grammatical changes.
04/11: grammatical changes.
05/11: remove unnecessary if statement and remove caps used in commit message.
06/11: use xcalloc instead of using a commit_list as we know the size
of the array.
07/11: s/<object>/[<object>]/ as the object is optional.
08/11: rename parse_opt_commit_object_name() to parse_opt_commits().
09/11: make branch.c also to use the macros.
11/11: s/<object>/[<object>]/ as the object is optional.

Changes in v6:
Renamed the test file from t6301 to t6302 to avoid conflicts.

Thanks to Matthieu, Christian, Junio and Eric for the input on the
last iteration.

--
Regards,
Karthik Nayak

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH v6 01/11] t6302: for-each-ref tests for ref-filter APIs
  2015-06-25  8:46 [PATCH v6 00/11] add options to for-each-ref Karthik Nayak
@ 2015-06-25  8:57 ` Karthik Nayak
  2015-06-25  8:57   ` [PATCH v6 02/11] tag: libify parse_opt_points_at() Karthik Nayak
                     ` (10 more replies)
  0 siblings, 11 replies; 25+ messages in thread
From: Karthik Nayak @ 2015-06-25  8:57 UTC (permalink / raw)
  To: git; +Cc: christian.couder, Matthieu.Moy, gitster, Karthik Nayak

Add a test suite for testing the ref-filter APIs used
by for-each-ref. We just intialize the test suite for now.
More tests will be added in the following patches as more
options are added to for-each-ref.

Based-on-patch-by: Jeff King <peff@peff.net>
Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
 t/t6302-for-each-ref-filter.sh | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)
 create mode 100644 t/t6302-for-each-ref-filter.sh

diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh
new file mode 100644
index 0000000..b1fa8d4
--- /dev/null
+++ b/t/t6302-for-each-ref-filter.sh
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+test_description='test for-each-refs usage of ref-filter APIs'
+
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-gpg.sh
+
+test_expect_success 'setup some history and refs' '
+	test_commit one &&
+	test_commit two &&
+	test_commit three &&
+	git checkout -b side &&
+	test_commit four &&
+	git tag -s -m "A signed tag message" signed-tag &&
+	git checkout master &&
+	git update-ref refs/odd/spot master
+'
+
+test_done
-- 
2.4.4

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v6 02/11] tag: libify parse_opt_points_at()
  2015-06-25  8:57 ` [PATCH v6 01/11] t6302: for-each-ref tests for ref-filter APIs Karthik Nayak
@ 2015-06-25  8:57   ` Karthik Nayak
  2015-06-25  8:57   ` [PATCH v6 03/11] ref-filter: implement '--points-at' option Karthik Nayak
                     ` (9 subsequent siblings)
  10 siblings, 0 replies; 25+ messages in thread
From: Karthik Nayak @ 2015-06-25  8:57 UTC (permalink / raw)
  To: git; +Cc: christian.couder, Matthieu.Moy, gitster, Karthik Nayak

Rename 'parse_opt_points_at()' to 'parse_opt_object_name()' and
move it from 'tag.c' to 'parse-options'. This now acts as a common
parse_opt function which accepts an objectname and stores it into
a sha1_array.

Based-on-patch-by: Jeff King <peff@peff.net>
Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
 builtin/tag.c      | 21 ++-------------------
 parse-options-cb.c | 17 +++++++++++++++++
 parse-options.h    |  1 +
 3 files changed, 20 insertions(+), 19 deletions(-)

diff --git a/builtin/tag.c b/builtin/tag.c
index 5f6cdc5..e36c43e 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -546,23 +546,6 @@ static int strbuf_check_tag_ref(struct strbuf *sb, const char *name)
 	return check_refname_format(sb->buf, 0);
 }
 
-static int parse_opt_points_at(const struct option *opt __attribute__((unused)),
-			const char *arg, int unset)
-{
-	unsigned char sha1[20];
-
-	if (unset) {
-		sha1_array_clear(&points_at);
-		return 0;
-	}
-	if (!arg)
-		return error(_("switch 'points-at' requires an object"));
-	if (get_sha1(arg, sha1))
-		return error(_("malformed object name '%s'"), arg);
-	sha1_array_append(&points_at, sha1);
-	return 0;
-}
-
 static int parse_opt_sort(const struct option *opt, const char *arg, int unset)
 {
 	int *sort = opt->value;
@@ -625,8 +608,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
 			parse_opt_with_commit, (intptr_t)"HEAD",
 		},
 		{
-			OPTION_CALLBACK, 0, "points-at", NULL, N_("object"),
-			N_("print only tags of the object"), 0, parse_opt_points_at
+			OPTION_CALLBACK, 0, "points-at", &points_at, N_("object"),
+			N_("print only tags of the object"), 0, parse_opt_object_name
 		},
 		OPT_END()
 	};
diff --git a/parse-options-cb.c b/parse-options-cb.c
index be8c413..de75411 100644
--- a/parse-options-cb.c
+++ b/parse-options-cb.c
@@ -4,6 +4,7 @@
 #include "commit.h"
 #include "color.h"
 #include "string-list.h"
+#include "sha1-array.h"
 
 /*----- some often used options -----*/
 
@@ -92,6 +93,22 @@ int parse_opt_with_commit(const struct option *opt, const char *arg, int unset)
 	return 0;
 }
 
+int parse_opt_object_name(const struct option *opt, const char *arg, int unset)
+{
+	unsigned char sha1[20];
+
+	if (unset) {
+		sha1_array_clear(opt->value);
+		return 0;
+	}
+	if (!arg)
+		return -1;
+	if (get_sha1(arg, sha1))
+		return error(_("malformed object name '%s'"), arg);
+	sha1_array_append(opt->value, sha1);
+	return 0;
+}
+
 int parse_opt_tertiary(const struct option *opt, const char *arg, int unset)
 {
 	int *target = opt->value;
diff --git a/parse-options.h b/parse-options.h
index c71e9da..36c71fe 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -220,6 +220,7 @@ extern int parse_opt_approxidate_cb(const struct option *, const char *, int);
 extern int parse_opt_expiry_date_cb(const struct option *, const char *, int);
 extern int parse_opt_color_flag_cb(const struct option *, const char *, int);
 extern int parse_opt_verbosity_cb(const struct option *, const char *, int);
+extern int parse_opt_object_name(const struct option *, const char *, int);
 extern int parse_opt_with_commit(const struct option *, const char *, int);
 extern int parse_opt_tertiary(const struct option *, const char *, int);
 extern int parse_opt_string_list(const struct option *, const char *, int);
-- 
2.4.4

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v6 03/11] ref-filter: implement '--points-at' option
  2015-06-25  8:57 ` [PATCH v6 01/11] t6302: for-each-ref tests for ref-filter APIs Karthik Nayak
  2015-06-25  8:57   ` [PATCH v6 02/11] tag: libify parse_opt_points_at() Karthik Nayak
@ 2015-06-25  8:57   ` Karthik Nayak
  2015-06-29 17:40     ` Junio C Hamano
  2015-06-25  8:57   ` [PATCH v6 04/11] for-each-ref: add " Karthik Nayak
                     ` (8 subsequent siblings)
  10 siblings, 1 reply; 25+ messages in thread
From: Karthik Nayak @ 2015-06-25  8:57 UTC (permalink / raw)
  To: git; +Cc: christian.couder, Matthieu.Moy, gitster, Karthik Nayak

In 'tag -l' we have '--points-at' option which lets users
list only tags which point to a particular commit. Implement
this option in 'ref-filter.{c,h}' so that other commands can
benefit from this.

This is duplicated from tag.c, we will eventually remove that
when we port tag.c to use ref-filter APIs.

Based-on-patch-by: Jeff King <peff@peff.net>
Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
 builtin/tag.c |  4 ++++
 ref-filter.c  | 26 ++++++++++++++++++++++++++
 ref-filter.h  |  1 +
 3 files changed, 31 insertions(+)

diff --git a/builtin/tag.c b/builtin/tag.c
index e36c43e..280981f 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -56,6 +56,10 @@ static int match_pattern(const char **patterns, const char *ref)
 	return 0;
 }
 
+/*
+ * This is currently duplicated in ref-filter.c, and will eventually be
+ * removed as we port tag.c to use the ref-filter APIs.
+ */
 static const unsigned char *match_points_at(const char *refname,
 					    const unsigned char *sha1)
 {
diff --git a/ref-filter.c b/ref-filter.c
index 43502a4..f40f06e 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -842,6 +842,29 @@ static int match_name_as_path(const char **pattern, const char *refname)
 	return 0;
 }
 
+/*
+ * Given a ref (sha1, refname) see if it points to one of the sha1s
+ * in a sha1_array.
+ */
+static int match_points_at(struct sha1_array *points_at, const unsigned char *sha1,
+			   const char *refname)
+{
+	struct object *obj;
+
+	if (!points_at || !points_at->nr)
+		return 1;
+
+	if (sha1_array_lookup(points_at, sha1) >= 0)
+		return 1;
+
+	obj = parse_object_or_die(sha1, refname);
+	if (obj->type == OBJ_TAG &&
+	    sha1_array_lookup(points_at, ((struct tag *)obj)->tagged->sha1) >= 0)
+		return 1;
+
+	return 0;
+}
+
 /* Allocate space for a new ref_array_item and copy the objectname and flag to it */
 static struct ref_array_item *new_ref_array_item(const char *refname,
 						 const unsigned char *objectname,
@@ -875,6 +898,9 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,
 	if (*filter->name_patterns && !match_name_as_path(filter->name_patterns, refname))
 		return 0;
 
+	if (!match_points_at(&filter->points_at, oid->hash, refname))
+		return 0;
+
 	/*
 	 * We do not open the object yet; sort may only need refname
 	 * to do its job and the resulting list may yet to be pruned
diff --git a/ref-filter.h b/ref-filter.h
index 6997984..c2856b8 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -42,6 +42,7 @@ struct ref_array {
 
 struct ref_filter {
 	const char **name_patterns;
+	struct sha1_array points_at;
 };
 
 struct ref_filter_cbdata {
-- 
2.4.4

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v6 04/11] for-each-ref: add '--points-at' option
  2015-06-25  8:57 ` [PATCH v6 01/11] t6302: for-each-ref tests for ref-filter APIs Karthik Nayak
  2015-06-25  8:57   ` [PATCH v6 02/11] tag: libify parse_opt_points_at() Karthik Nayak
  2015-06-25  8:57   ` [PATCH v6 03/11] ref-filter: implement '--points-at' option Karthik Nayak
@ 2015-06-25  8:57   ` Karthik Nayak
  2015-06-29 17:46     ` Junio C Hamano
  2015-06-29 18:38     ` Junio C Hamano
  2015-06-25  8:57   ` [PATCH v6 05/11] ref-filter: add parse_opt_merge_filter() Karthik Nayak
                     ` (7 subsequent siblings)
  10 siblings, 2 replies; 25+ messages in thread
From: Karthik Nayak @ 2015-06-25  8:57 UTC (permalink / raw)
  To: git; +Cc: christian.couder, Matthieu.Moy, gitster, Karthik Nayak

Add the '--points-at' option provided by 'ref-filter'. The
option lets the user to pick only refs which point to a particular
commit.

Add documentation and tests for the same.

Based-on-patch-by: Jeff King <peff@peff.net>
Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
 Documentation/git-for-each-ref.txt |  3 +++
 builtin/for-each-ref.c             |  9 +++++++--
 t/t6302-for-each-ref-filter.sh     | 20 ++++++++++++++++++++
 3 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index 7f8d9a5..0ede41d 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -10,6 +10,7 @@ SYNOPSIS
 [verse]
 'git for-each-ref' [--count=<count>] [--shell|--perl|--python|--tcl]
 		   [(--sort=<key>)...] [--format=<format>] [<pattern>...]
+		   [--points-at <object>]
 
 DESCRIPTION
 -----------
@@ -62,6 +63,8 @@ OPTIONS
 	the specified host language.  This is meant to produce
 	a scriptlet that can directly be `eval`ed.
 
+--points-at <object>::
+	Only list refs pointing to the given object.
 
 FIELD NAMES
 -----------
diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c
index 7919206..46f9b05 100644
--- a/builtin/for-each-ref.c
+++ b/builtin/for-each-ref.c
@@ -7,6 +7,7 @@
 
 static char const * const for_each_ref_usage[] = {
 	N_("git for-each-ref [<options>] [<pattern>]"),
+	N_("git for-each-ref [--points-at <object>]"),
 	NULL
 };
 
@@ -34,9 +35,15 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
 		OPT_STRING(  0 , "format", &format, N_("format"), N_("format to use for the output")),
 		OPT_CALLBACK(0 , "sort", sorting_tail, N_("key"),
 			    N_("field name to sort on"), &parse_opt_ref_sorting),
+		OPT_CALLBACK(0, "points-at", &filter.points_at,
+			     N_("object"), N_("print only refs pointing to the given object"),
+			     parse_opt_object_name),
 		OPT_END(),
 	};
 
+	memset(&array, 0, sizeof(array));
+	memset(&filter, 0, sizeof(filter));
+
 	parse_options(argc, argv, prefix, opts, for_each_ref_usage, 0);
 	if (maxcount < 0) {
 		error("invalid --count argument: `%d'", maxcount);
@@ -55,8 +62,6 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
 	/* for warn_ambiguous_refs */
 	git_config(git_default_config, NULL);
 
-	memset(&array, 0, sizeof(array));
-	memset(&filter, 0, sizeof(filter));
 	filter.name_patterns = argv;
 	filter_refs(&array, &filter, FILTER_REFS_ALL | FILTER_REFS_INCLUDE_BROKEN);
 	ref_array_sort(sorting, &array);
diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh
index b1fa8d4..7269a66 100644
--- a/t/t6302-for-each-ref-filter.sh
+++ b/t/t6302-for-each-ref-filter.sh
@@ -16,4 +16,24 @@ test_expect_success 'setup some history and refs' '
 	git update-ref refs/odd/spot master
 '
 
+test_expect_success 'filtering with --points-at' '
+	cat >expect <<-\EOF &&
+	refs/heads/master
+	refs/odd/spot
+	refs/tags/three
+	EOF
+	git for-each-ref --format="%(refname)" --points-at=master >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'check signed tags with --points-at' '
+	cat >expect <<-\EOF &&
+	refs/heads/side
+	refs/tags/four
+	refs/tags/signed-tag four
+	EOF
+	git for-each-ref --format="%(refname) %(*subject)" --points-at=side >actual &&
+	test_cmp expect actual
+'
+
 test_done
-- 
2.4.4

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v6 05/11] ref-filter: add parse_opt_merge_filter()
  2015-06-25  8:57 ` [PATCH v6 01/11] t6302: for-each-ref tests for ref-filter APIs Karthik Nayak
                     ` (2 preceding siblings ...)
  2015-06-25  8:57   ` [PATCH v6 04/11] for-each-ref: add " Karthik Nayak
@ 2015-06-25  8:57   ` Karthik Nayak
  2015-06-25  8:57   ` [PATCH v6 06/11] ref-filter: implement '--merged' and '--no-merged' options Karthik Nayak
                     ` (6 subsequent siblings)
  10 siblings, 0 replies; 25+ messages in thread
From: Karthik Nayak @ 2015-06-25  8:57 UTC (permalink / raw)
  To: git; +Cc: christian.couder, Matthieu.Moy, gitster, Karthik Nayak

Add 'parse_opt_merge_filter()' to parse '--merged' and '--no-merged'
options and write macros for the same.

This is copied from 'builtin/branch.c' which will eventually be removed
when we port 'branch.c' to use ref-filter APIs.

Based-on-patch-by: Jeff King <peff@peff.net>
Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
 builtin/branch.c |  4 ++++
 ref-filter.c     | 19 +++++++++++++++++++
 ref-filter.h     | 11 +++++++++++
 3 files changed, 34 insertions(+)

diff --git a/builtin/branch.c b/builtin/branch.c
index b42e5b6..ddd90e6 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -745,6 +745,10 @@ static void rename_branch(const char *oldname, const char *newname, int force)
 	strbuf_release(&newsection);
 }
 
+/*
+ * This function is duplicated in ref-filter. It will eventually be removed
+ * when we port branch.c to use ref-filter APIs.
+ */
 static int opt_parse_merge_filter(const struct option *opt, const char *arg, int unset)
 {
 	merge_filter = ((opt->long_name[0] == 'n')
diff --git a/ref-filter.c b/ref-filter.c
index f40f06e..0c2d67c 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -1125,3 +1125,22 @@ int parse_opt_ref_sorting(const struct option *opt, const char *arg, int unset)
 	s->atom = parse_ref_filter_atom(arg, arg+len);
 	return 0;
 }
+
+int parse_opt_merge_filter(const struct option *opt, const char *arg, int unset)
+{
+	struct ref_filter *rf = opt->value;
+	unsigned char sha1[20];
+
+	rf->merge = starts_with(opt->long_name, "no")
+		? REF_FILTER_MERGED_OMIT
+		: REF_FILTER_MERGED_INCLUDE;
+
+	if (get_sha1(arg, sha1))
+		die(_("malformed object name %s"), arg);
+
+	rf->merge_commit = lookup_commit_reference_gently(sha1, 0);
+	if (!rf->merge_commit)
+		return opterror(opt, "must point to a commit", 0);
+
+	return 0;
+}
diff --git a/ref-filter.h b/ref-filter.h
index c2856b8..ad2902b 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -50,6 +50,15 @@ struct ref_filter_cbdata {
 	struct ref_filter *filter;
 };
 
+/*  Macros for checking --merged and --no-merged options */
+#define _OPT_MERGED_NO_MERGED(option, filter, h)				\
+	{ OPTION_CALLBACK, 0, option, (filter), N_("commit"), (h), \
+	  PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NONEG, \
+	  parse_opt_merge_filter, (intptr_t) "HEAD" \
+	}
+#define OPT_MERGED(f, h) _OPT_MERGED_NO_MERGED("merged", f, h)
+#define OPT_NO_MERGED(f, h) _OPT_MERGED_NO_MERGED("no-merged", f, h)
+
 /*
  * API for filtering a set of refs. Based on the type of refs the user
  * has requested, we iterate through those refs and apply filters
@@ -71,5 +80,7 @@ void show_ref_array_item(struct ref_array_item *info, const char *format, int qu
 int parse_opt_ref_sorting(const struct option *opt, const char *arg, int unset);
 /*  Default sort option based on refname */
 struct ref_sorting *ref_default_sorting(void);
+/*  Function to parse --merged and --no-merged options */
+int parse_opt_merge_filter(const struct option *opt, const char *arg, int unset);
 
 #endif /*  REF_FILTER_H  */
-- 
2.4.4

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v6 06/11] ref-filter: implement '--merged' and '--no-merged' options
  2015-06-25  8:57 ` [PATCH v6 01/11] t6302: for-each-ref tests for ref-filter APIs Karthik Nayak
                     ` (3 preceding siblings ...)
  2015-06-25  8:57   ` [PATCH v6 05/11] ref-filter: add parse_opt_merge_filter() Karthik Nayak
@ 2015-06-25  8:57   ` Karthik Nayak
  2015-06-29 18:03     ` Junio C Hamano
  2015-06-25  8:57   ` [PATCH v6 07/11] for-each-ref: add " Karthik Nayak
                     ` (5 subsequent siblings)
  10 siblings, 1 reply; 25+ messages in thread
From: Karthik Nayak @ 2015-06-25  8:57 UTC (permalink / raw)
  To: git; +Cc: christian.couder, Matthieu.Moy, gitster, Karthik Nayak

In 'branch -l' we have '--merged' option which only lists refs (branches)
merged into the named commit and '--no-merged' option which only lists
refs (branches) not merged into the named commit. Implement these two
options in ref-filter.{c,h} so that other commands can benefit from this.

Based-on-patch-by: Jeff King <peff@peff.net>
Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
 ref-filter.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
 ref-filter.h |  8 +++++++
 2 files changed, 77 insertions(+), 4 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index 0c2d67c..2f20cb3 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -9,6 +9,7 @@
 #include "tag.h"
 #include "quote.h"
 #include "ref-filter.h"
+#include "revision.h"
 
 typedef enum { FIELD_STR, FIELD_ULONG, FIELD_TIME } cmp_type;
 
@@ -889,6 +890,7 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,
 	struct ref_filter_cbdata *ref_cbdata = cb_data;
 	struct ref_filter *filter = ref_cbdata->filter;
 	struct ref_array_item *ref;
+	struct commit *commit = NULL;
 
 	if (flag & REF_BAD_NAME) {
 		  warning("ignoring ref with broken name %s", refname);
@@ -902,11 +904,23 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,
 		return 0;
 
 	/*
+	 * A merge filter is applied on refs pointing to commits. Hence
+	 * obtain the commit using the 'oid' available and discard all
+	 * non-commits early. The actual filtering is done later.
+	 */
+	if (filter->merge_commit) {
+		commit = lookup_commit_reference_gently(oid->hash, 1);
+		if (!commit)
+			return 0;
+	}
+
+	/*
 	 * We do not open the object yet; sort may only need refname
 	 * to do its job and the resulting list may yet to be pruned
 	 * by maxcount logic.
 	 */
 	ref = new_ref_array_item(refname, oid->hash, flag);
+	ref->commit = commit;
 
 	REALLOC_ARRAY(ref_cbdata->array->items, ref_cbdata->array->nr + 1);
 	ref_cbdata->array->items[ref_cbdata->array->nr++] = ref;
@@ -932,6 +946,50 @@ void ref_array_clear(struct ref_array *array)
 	array->nr = array->alloc = 0;
 }
 
+static void do_merge_filter(struct ref_filter_cbdata *ref_cbdata)
+{
+	struct rev_info revs;
+	int i, old_nr;
+	struct ref_filter *filter = ref_cbdata->filter;
+	struct ref_array *array = ref_cbdata->array;
+	struct commit **to_clear = xcalloc(sizeof(struct commit *), array->nr);
+
+	init_revisions(&revs, NULL);
+
+	for (i = 0; i < array->nr; i++) {
+		struct ref_array_item *item = array->items[i];
+		add_pending_object(&revs, &item->commit->object, item->refname);
+		to_clear[i] = item->commit;
+	}
+
+	filter->merge_commit->object.flags |= UNINTERESTING;
+	add_pending_object(&revs, &filter->merge_commit->object, "");
+
+	revs.limited = 1;
+	if (prepare_revision_walk(&revs))
+		die(_("revision walk setup failed"));
+
+	old_nr = array->nr;
+	array->nr = 0;
+
+	for (i = 0; i < old_nr; i++) {
+		struct ref_array_item *item = array->items[i];
+		struct commit *commit = item->commit;
+
+		int is_merged = !!(commit->object.flags & UNINTERESTING);
+
+		if (is_merged == (filter->merge == REF_FILTER_MERGED_INCLUDE))
+			array->items[array->nr++] = array->items[i];
+		else
+			free_array_item(item);
+	}
+
+	for (i = 0; i < old_nr; i++)
+		clear_commit_marks(to_clear[i], ALL_REV_FLAGS);
+	clear_commit_marks(filter->merge_commit, ALL_REV_FLAGS);
+	free(to_clear);
+}
+
 /*
  * API for filtering a set of refs. Based on the type of refs the user
  * has requested, we iterate through those refs and apply filters
@@ -941,17 +999,24 @@ void ref_array_clear(struct ref_array *array)
 int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int type)
 {
 	struct ref_filter_cbdata ref_cbdata;
+	int ret = 0;
 
 	ref_cbdata.array = array;
 	ref_cbdata.filter = filter;
 
+	/*  Simple per-ref filtering */
 	if (type & (FILTER_REFS_ALL | FILTER_REFS_INCLUDE_BROKEN))
-		return for_each_rawref(ref_filter_handler, &ref_cbdata);
+		ret = for_each_rawref(ref_filter_handler, &ref_cbdata);
 	else if (type & FILTER_REFS_ALL)
-		return for_each_ref(ref_filter_handler, &ref_cbdata);
-	else
+		ret = for_each_ref(ref_filter_handler, &ref_cbdata);
+	else if (type)
 		die("filter_refs: invalid type");
-	return 0;
+
+	/*  Filters that need revision walking */
+	if (filter->merge_commit)
+		do_merge_filter(&ref_cbdata);
+
+	return ret;
 }
 
 static int cmp_ref_sorting(struct ref_sorting *s, struct ref_array_item *a, struct ref_array_item *b)
diff --git a/ref-filter.h b/ref-filter.h
index ad2902b..7241a1d 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -31,6 +31,7 @@ struct ref_array_item {
 	unsigned char objectname[20];
 	int flag;
 	const char *symref;
+	struct commit *commit;
 	struct atom_value *value;
 	char refname[FLEX_ARRAY];
 };
@@ -43,6 +44,13 @@ struct ref_array {
 struct ref_filter {
 	const char **name_patterns;
 	struct sha1_array points_at;
+
+	enum {
+		REF_FILTER_MERGED_NONE = 0,
+		REF_FILTER_MERGED_INCLUDE,
+		REF_FILTER_MERGED_OMIT
+	} merge;
+	struct commit *merge_commit;
 };
 
 struct ref_filter_cbdata {
-- 
2.4.4

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v6 07/11] for-each-ref: add '--merged' and '--no-merged' options
  2015-06-25  8:57 ` [PATCH v6 01/11] t6302: for-each-ref tests for ref-filter APIs Karthik Nayak
                     ` (4 preceding siblings ...)
  2015-06-25  8:57   ` [PATCH v6 06/11] ref-filter: implement '--merged' and '--no-merged' options Karthik Nayak
@ 2015-06-25  8:57   ` Karthik Nayak
  2015-06-25  8:57   ` [PATCH v6 08/11] parse-option: rename parse_opt_with_commit() Karthik Nayak
                     ` (4 subsequent siblings)
  10 siblings, 0 replies; 25+ messages in thread
From: Karthik Nayak @ 2015-06-25  8:57 UTC (permalink / raw)
  To: git; +Cc: christian.couder, Matthieu.Moy, gitster, Karthik Nayak

Add the '--merged' and '--no-merged' options provided by 'ref-filter'.
The '--merged' option lets the user to only list refs merged into the
named commit. The '--no-merged' option lets the user to only list refs
not merged into the named commit.

Add documentation and tests for the same.

Based-on-patch-by: Jeff King <peff@peff.net>
Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
 Documentation/git-for-each-ref.txt | 10 +++++++++-
 builtin/for-each-ref.c             |  3 +++
 t/t6302-for-each-ref-filter.sh     | 22 ++++++++++++++++++++++
 3 files changed, 34 insertions(+), 1 deletion(-)

diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index 0ede41d..290a5c1 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -10,7 +10,7 @@ SYNOPSIS
 [verse]
 'git for-each-ref' [--count=<count>] [--shell|--perl|--python|--tcl]
 		   [(--sort=<key>)...] [--format=<format>] [<pattern>...]
-		   [--points-at <object>]
+		   [--points-at <object>] [(--merged | --no-merged) [<object>]]
 
 DESCRIPTION
 -----------
@@ -66,6 +66,14 @@ OPTIONS
 --points-at <object>::
 	Only list refs pointing to the given object.
 
+--merged [<object>]::
+	Only list refs whose tips are reachable from the
+	specified commit (HEAD if not specified).
+
+--no-merged [<object>]::
+	Only list refs whose tips are not reachable from the
+	specified commit (HEAD if not specified).
+
 FIELD NAMES
 -----------
 
diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c
index 46f9b05..ba70798 100644
--- a/builtin/for-each-ref.c
+++ b/builtin/for-each-ref.c
@@ -8,6 +8,7 @@
 static char const * const for_each_ref_usage[] = {
 	N_("git for-each-ref [<options>] [<pattern>]"),
 	N_("git for-each-ref [--points-at <object>]"),
+	N_("git for-each-ref [(--merged | --no-merged) [<object>]]"),
 	NULL
 };
 
@@ -38,6 +39,8 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
 		OPT_CALLBACK(0, "points-at", &filter.points_at,
 			     N_("object"), N_("print only refs pointing to the given object"),
 			     parse_opt_object_name),
+		OPT_MERGED(&filter, N_("print only refs that are merged")),
+		OPT_NO_MERGED(&filter, N_("print only refs that are not merged")),
 		OPT_END(),
 	};
 
diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh
index 7269a66..f5ccfb9 100644
--- a/t/t6302-for-each-ref-filter.sh
+++ b/t/t6302-for-each-ref-filter.sh
@@ -36,4 +36,26 @@ test_expect_success 'check signed tags with --points-at' '
 	test_cmp expect actual
 '
 
+test_expect_success 'filtering with --merged' '
+	cat >expect <<-\EOF &&
+	refs/heads/master
+	refs/odd/spot
+	refs/tags/one
+	refs/tags/three
+	refs/tags/two
+	EOF
+	git for-each-ref --format="%(refname)" --merged=master >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'filtering with --no-merged' '
+	cat >expect <<-\EOF &&
+	refs/heads/side
+	refs/tags/four
+	refs/tags/signed-tag
+	EOF
+	git for-each-ref --format="%(refname)" --no-merged=master >actual &&
+	test_cmp expect actual
+'
+
 test_done
-- 
2.4.4

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v6 08/11] parse-option: rename parse_opt_with_commit()
  2015-06-25  8:57 ` [PATCH v6 01/11] t6302: for-each-ref tests for ref-filter APIs Karthik Nayak
                     ` (5 preceding siblings ...)
  2015-06-25  8:57   ` [PATCH v6 07/11] for-each-ref: add " Karthik Nayak
@ 2015-06-25  8:57   ` Karthik Nayak
  2015-06-25  8:57   ` [PATCH v6 09/11] parse-options.h: add macros for '--contains' option Karthik Nayak
                     ` (3 subsequent siblings)
  10 siblings, 0 replies; 25+ messages in thread
From: Karthik Nayak @ 2015-06-25  8:57 UTC (permalink / raw)
  To: git; +Cc: christian.couder, Matthieu.Moy, gitster, Karthik Nayak

Rename parse_opt_with_commit() to parse_opt_commits() to show
that it can be used to obtain a list of commits and is not
constricted to usage of '--contains' option.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
 builtin/branch.c   | 4 ++--
 builtin/tag.c      | 4 ++--
 parse-options-cb.c | 2 +-
 parse-options.h    | 2 +-
 4 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/builtin/branch.c b/builtin/branch.c
index ddd90e6..a008b0d 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -828,13 +828,13 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 			OPTION_CALLBACK, 0, "contains", &with_commit, N_("commit"),
 			N_("print only branches that contain the commit"),
 			PARSE_OPT_LASTARG_DEFAULT,
-			parse_opt_with_commit, (intptr_t)"HEAD",
+			parse_opt_commits, (intptr_t)"HEAD",
 		},
 		{
 			OPTION_CALLBACK, 0, "with", &with_commit, N_("commit"),
 			N_("print only branches that contain the commit"),
 			PARSE_OPT_HIDDEN | PARSE_OPT_LASTARG_DEFAULT,
-			parse_opt_with_commit, (intptr_t) "HEAD",
+			parse_opt_commits, (intptr_t) "HEAD",
 		},
 		OPT__ABBREV(&abbrev),
 
diff --git a/builtin/tag.c b/builtin/tag.c
index 280981f..7af45a0 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -603,13 +603,13 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
 			OPTION_CALLBACK, 0, "contains", &with_commit, N_("commit"),
 			N_("print only tags that contain the commit"),
 			PARSE_OPT_LASTARG_DEFAULT,
-			parse_opt_with_commit, (intptr_t)"HEAD",
+			parse_opt_commits, (intptr_t)"HEAD",
 		},
 		{
 			OPTION_CALLBACK, 0, "with", &with_commit, N_("commit"),
 			N_("print only tags that contain the commit"),
 			PARSE_OPT_HIDDEN | PARSE_OPT_LASTARG_DEFAULT,
-			parse_opt_with_commit, (intptr_t)"HEAD",
+			parse_opt_commits, (intptr_t)"HEAD",
 		},
 		{
 			OPTION_CALLBACK, 0, "points-at", &points_at, N_("object"),
diff --git a/parse-options-cb.c b/parse-options-cb.c
index de75411..632f10f 100644
--- a/parse-options-cb.c
+++ b/parse-options-cb.c
@@ -77,7 +77,7 @@ int parse_opt_verbosity_cb(const struct option *opt, const char *arg,
 	return 0;
 }
 
-int parse_opt_with_commit(const struct option *opt, const char *arg, int unset)
+int parse_opt_commits(const struct option *opt, const char *arg, int unset)
 {
 	unsigned char sha1[20];
 	struct commit *commit;
diff --git a/parse-options.h b/parse-options.h
index 36c71fe..2ffd857 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -221,7 +221,7 @@ extern int parse_opt_expiry_date_cb(const struct option *, const char *, int);
 extern int parse_opt_color_flag_cb(const struct option *, const char *, int);
 extern int parse_opt_verbosity_cb(const struct option *, const char *, int);
 extern int parse_opt_object_name(const struct option *, const char *, int);
-extern int parse_opt_with_commit(const struct option *, const char *, int);
+extern int parse_opt_commits(const struct option *, const char *, int);
 extern int parse_opt_tertiary(const struct option *, const char *, int);
 extern int parse_opt_string_list(const struct option *, const char *, int);
 extern int parse_opt_noop_cb(const struct option *, const char *, int);
-- 
2.4.4

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v6 09/11] parse-options.h: add macros for '--contains' option
  2015-06-25  8:57 ` [PATCH v6 01/11] t6302: for-each-ref tests for ref-filter APIs Karthik Nayak
                     ` (6 preceding siblings ...)
  2015-06-25  8:57   ` [PATCH v6 08/11] parse-option: rename parse_opt_with_commit() Karthik Nayak
@ 2015-06-25  8:57   ` Karthik Nayak
  2015-06-25  8:57   ` [PATCH v6 10/11] ref-filter: implement " Karthik Nayak
                     ` (2 subsequent siblings)
  10 siblings, 0 replies; 25+ messages in thread
From: Karthik Nayak @ 2015-06-25  8:57 UTC (permalink / raw)
  To: git; +Cc: christian.couder, Matthieu.Moy, gitster, Karthik Nayak

Add a macro for using the '--contains' option in parse-options.h
also include an optional '--with' option macro which performs the
same action as '--contains'.

Make tag.c and branch.c use this new macro.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
 builtin/branch.c | 14 ++------------
 builtin/tag.c    | 14 ++------------
 parse-options.h  |  7 +++++++
 3 files changed, 11 insertions(+), 24 deletions(-)

diff --git a/builtin/branch.c b/builtin/branch.c
index a008b0d..b04e341 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -824,18 +824,8 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 		OPT__COLOR(&branch_use_color, N_("use colored output")),
 		OPT_SET_INT('r', "remotes",     &kinds, N_("act on remote-tracking branches"),
 			REF_REMOTE_BRANCH),
-		{
-			OPTION_CALLBACK, 0, "contains", &with_commit, N_("commit"),
-			N_("print only branches that contain the commit"),
-			PARSE_OPT_LASTARG_DEFAULT,
-			parse_opt_commits, (intptr_t)"HEAD",
-		},
-		{
-			OPTION_CALLBACK, 0, "with", &with_commit, N_("commit"),
-			N_("print only branches that contain the commit"),
-			PARSE_OPT_HIDDEN | PARSE_OPT_LASTARG_DEFAULT,
-			parse_opt_commits, (intptr_t) "HEAD",
-		},
+		OPT_CONTAINS(&with_commit, N_("print only branches that contain the commit")),
+		OPT_WITH(&with_commit, N_("print only branches that contain the commit")),
 		OPT__ABBREV(&abbrev),
 
 		OPT_GROUP(N_("Specific git-branch actions:")),
diff --git a/builtin/tag.c b/builtin/tag.c
index 7af45a0..767162e 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -595,23 +595,13 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
 
 		OPT_GROUP(N_("Tag listing options")),
 		OPT_COLUMN(0, "column", &colopts, N_("show tag list in columns")),
+		OPT_CONTAINS(&with_commit, N_("print only tags that contain the commit")),
+		OPT_WITH(&with_commit, N_("print only tags that contain the commit")),
 		{
 			OPTION_CALLBACK, 0, "sort", &tag_sort, N_("type"), N_("sort tags"),
 			PARSE_OPT_NONEG, parse_opt_sort
 		},
 		{
-			OPTION_CALLBACK, 0, "contains", &with_commit, N_("commit"),
-			N_("print only tags that contain the commit"),
-			PARSE_OPT_LASTARG_DEFAULT,
-			parse_opt_commits, (intptr_t)"HEAD",
-		},
-		{
-			OPTION_CALLBACK, 0, "with", &with_commit, N_("commit"),
-			N_("print only tags that contain the commit"),
-			PARSE_OPT_HIDDEN | PARSE_OPT_LASTARG_DEFAULT,
-			parse_opt_commits, (intptr_t)"HEAD",
-		},
-		{
 			OPTION_CALLBACK, 0, "points-at", &points_at, N_("object"),
 			N_("print only tags of the object"), 0, parse_opt_object_name
 		},
diff --git a/parse-options.h b/parse-options.h
index 2ffd857..627423f 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -243,5 +243,12 @@ extern int parse_opt_noop_cb(const struct option *, const char *, int);
 	OPT_COLOR_FLAG(0, "color", (var), (h))
 #define OPT_COLUMN(s, l, v, h) \
 	{ OPTION_CALLBACK, (s), (l), (v), N_("style"), (h), PARSE_OPT_OPTARG, parseopt_column_callback }
+#define _OPT_CONTAINS_OR_WITH(name, variable, help, flag)		      \
+	{ OPTION_CALLBACK, 0, name, (variable), N_("commit"), (help), \
+	  PARSE_OPT_LASTARG_DEFAULT | flag, \
+	  parse_opt_commits, (intptr_t) "HEAD" \
+	}
+#define OPT_CONTAINS(v, h) _OPT_CONTAINS_OR_WITH("contains", v, h, 0)
+#define OPT_WITH(v, h) _OPT_CONTAINS_OR_WITH("with", v, h, PARSE_OPT_HIDDEN)
 
 #endif
-- 
2.4.4

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v6 10/11] ref-filter: implement '--contains' option
  2015-06-25  8:57 ` [PATCH v6 01/11] t6302: for-each-ref tests for ref-filter APIs Karthik Nayak
                     ` (7 preceding siblings ...)
  2015-06-25  8:57   ` [PATCH v6 09/11] parse-options.h: add macros for '--contains' option Karthik Nayak
@ 2015-06-25  8:57   ` Karthik Nayak
  2015-06-25  8:57   ` [PATCH v6 11/11] for-each-ref: add " Karthik Nayak
  2015-06-29 18:14   ` [PATCH v6 01/11] t6302: for-each-ref tests for ref-filter APIs Junio C Hamano
  10 siblings, 0 replies; 25+ messages in thread
From: Karthik Nayak @ 2015-06-25  8:57 UTC (permalink / raw)
  To: git; +Cc: christian.couder, Matthieu.Moy, gitster, Karthik Nayak

'tag -l' and 'branch -l' have two different ways of finding
out if a certain ref contains a commit. Implement both these
methods in ref-filter and give the caller of ref-filter API
the option to pick which implementation to be used.

'branch -l' uses 'is_descendant_of()' from commit.c which is
left as the default implementation to be used.

'tag -l' uses a more specific algorithm since ffc4b80. This
implementation is used whenever the 'with_commit_tag_algo' bit
is set in 'struct ref_filter'.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
 ref-filter.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 ref-filter.h |   3 ++
 2 files changed, 116 insertions(+), 1 deletion(-)

diff --git a/ref-filter.c b/ref-filter.c
index 2f20cb3..f793386 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -818,6 +818,114 @@ static void get_ref_atom_value(struct ref_array_item *ref, int atom, struct atom
 	*v = &ref->value[atom];
 }
 
+enum contains_result {
+	CONTAINS_UNKNOWN = -1,
+	CONTAINS_NO = 0,
+	CONTAINS_YES = 1
+};
+
+/*
+ * Mimicking the real stack, this stack lives on the heap, avoiding stack
+ * overflows.
+ *
+ * At each recursion step, the stack items points to the commits whose
+ * ancestors are to be inspected.
+ */
+struct contains_stack {
+	int nr, alloc;
+	struct contains_stack_entry {
+		struct commit *commit;
+		struct commit_list *parents;
+	} *contains_stack;
+};
+
+static int in_commit_list(const struct commit_list *want, struct commit *c)
+{
+	for (; want; want = want->next)
+		if (!hashcmp(want->item->object.sha1, c->object.sha1))
+			return 1;
+	return 0;
+}
+
+/*
+ * Test whether the candidate or one of its parents is contained in the list.
+ * Do not recurse to find out, though, but return -1 if inconclusive.
+ */
+static enum contains_result contains_test(struct commit *candidate,
+			    const struct commit_list *want)
+{
+	/* was it previously marked as containing a want commit? */
+	if (candidate->object.flags & TMP_MARK)
+		return 1;
+	/* or marked as not possibly containing a want commit? */
+	if (candidate->object.flags & UNINTERESTING)
+		return 0;
+	/* or are we it? */
+	if (in_commit_list(want, candidate)) {
+		candidate->object.flags |= TMP_MARK;
+		return 1;
+	}
+
+	if (parse_commit(candidate) < 0)
+		return 0;
+
+	return -1;
+}
+
+static void push_to_contains_stack(struct commit *candidate, struct contains_stack *contains_stack)
+{
+	ALLOC_GROW(contains_stack->contains_stack, contains_stack->nr + 1, contains_stack->alloc);
+	contains_stack->contains_stack[contains_stack->nr].commit = candidate;
+	contains_stack->contains_stack[contains_stack->nr++].parents = candidate->parents;
+}
+
+static enum contains_result contains_tag_algo(struct commit *candidate,
+		const struct commit_list *want)
+{
+	struct contains_stack contains_stack = { 0, 0, NULL };
+	int result = contains_test(candidate, want);
+
+	if (result != CONTAINS_UNKNOWN)
+		return result;
+
+	push_to_contains_stack(candidate, &contains_stack);
+	while (contains_stack.nr) {
+		struct contains_stack_entry *entry = &contains_stack.contains_stack[contains_stack.nr - 1];
+		struct commit *commit = entry->commit;
+		struct commit_list *parents = entry->parents;
+
+		if (!parents) {
+			commit->object.flags |= UNINTERESTING;
+			contains_stack.nr--;
+		}
+		/*
+		 * If we just popped the stack, parents->item has been marked,
+		 * therefore contains_test will return a meaningful 0 or 1.
+		 */
+		else switch (contains_test(parents->item, want)) {
+		case CONTAINS_YES:
+			commit->object.flags |= TMP_MARK;
+			contains_stack.nr--;
+			break;
+		case CONTAINS_NO:
+			entry->parents = parents->next;
+			break;
+		case CONTAINS_UNKNOWN:
+			push_to_contains_stack(parents->item, &contains_stack);
+			break;
+		}
+	}
+	free(contains_stack.contains_stack);
+	return contains_test(candidate, want);
+}
+
+static int commit_contains(struct ref_filter *filter, struct commit *commit)
+{
+	if (filter->with_commit_tag_algo)
+		return contains_tag_algo(commit, filter->with_commit);
+	return is_descendant_of(commit, filter->with_commit);
+}
+
 /*
  * Return 1 if the refname matches one of the patterns, otherwise 0.
  * A pattern can be path prefix (e.g. a refname "refs/heads/master"
@@ -908,10 +1016,14 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,
 	 * obtain the commit using the 'oid' available and discard all
 	 * non-commits early. The actual filtering is done later.
 	 */
-	if (filter->merge_commit) {
+	if (filter->merge_commit || filter->with_commit) {
 		commit = lookup_commit_reference_gently(oid->hash, 1);
 		if (!commit)
 			return 0;
+		/* We perform the filtering for the '--contains' option */
+		if (filter->with_commit &&
+		    !commit_contains(filter, commit))
+			return 0;
 	}
 
 	/*
diff --git a/ref-filter.h b/ref-filter.h
index 7241a1d..3c59431 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -44,6 +44,7 @@ struct ref_array {
 struct ref_filter {
 	const char **name_patterns;
 	struct sha1_array points_at;
+	struct commit_list *with_commit;
 
 	enum {
 		REF_FILTER_MERGED_NONE = 0,
@@ -51,6 +52,8 @@ struct ref_filter {
 		REF_FILTER_MERGED_OMIT
 	} merge;
 	struct commit *merge_commit;
+
+	unsigned int with_commit_tag_algo: 1;
 };
 
 struct ref_filter_cbdata {
-- 
2.4.4

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v6 11/11] for-each-ref: add '--contains' option
  2015-06-25  8:57 ` [PATCH v6 01/11] t6302: for-each-ref tests for ref-filter APIs Karthik Nayak
                     ` (8 preceding siblings ...)
  2015-06-25  8:57   ` [PATCH v6 10/11] ref-filter: implement " Karthik Nayak
@ 2015-06-25  8:57   ` Karthik Nayak
  2015-06-29 18:14   ` [PATCH v6 01/11] t6302: for-each-ref tests for ref-filter APIs Junio C Hamano
  10 siblings, 0 replies; 25+ messages in thread
From: Karthik Nayak @ 2015-06-25  8:57 UTC (permalink / raw)
  To: git; +Cc: christian.couder, Matthieu.Moy, gitster, Karthik Nayak

Add the '--contains' option provided by 'ref-filter'. The '--contains'
option lists only refs which contain the mentioned commit (HEAD if no
commit is explicitly given).

Add documentation and tests for the same.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
 Documentation/git-for-each-ref.txt |  5 +++++
 builtin/for-each-ref.c             |  2 ++
 t/t6302-for-each-ref-filter.sh     | 14 ++++++++++++++
 3 files changed, 21 insertions(+)

diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index 290a5c1..94bb5bd 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -11,6 +11,7 @@ SYNOPSIS
 'git for-each-ref' [--count=<count>] [--shell|--perl|--python|--tcl]
 		   [(--sort=<key>)...] [--format=<format>] [<pattern>...]
 		   [--points-at <object>] [(--merged | --no-merged) [<object>]]
+		   [--contains [<object>]]
 
 DESCRIPTION
 -----------
@@ -74,6 +75,10 @@ OPTIONS
 	Only list refs whose tips are not reachable from the
 	specified commit (HEAD if not specified).
 
+--contains [<object>]::
+	Only list tags which contain the specified commit (HEAD if not
+	specified).
+
 FIELD NAMES
 -----------
 
diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c
index ba70798..5868c48 100644
--- a/builtin/for-each-ref.c
+++ b/builtin/for-each-ref.c
@@ -9,6 +9,7 @@ static char const * const for_each_ref_usage[] = {
 	N_("git for-each-ref [<options>] [<pattern>]"),
 	N_("git for-each-ref [--points-at <object>]"),
 	N_("git for-each-ref [(--merged | --no-merged) [<object>]]"),
+	N_("git for-each-ref [--contains [<object>]]"),
 	NULL
 };
 
@@ -41,6 +42,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
 			     parse_opt_object_name),
 		OPT_MERGED(&filter, N_("print only refs that are merged")),
 		OPT_NO_MERGED(&filter, N_("print only refs that are not merged")),
+		OPT_CONTAINS(&filter.with_commit, N_("print only refs which contain the commit")),
 		OPT_END(),
 	};
 
diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh
index f5ccfb9..50ee115 100644
--- a/t/t6302-for-each-ref-filter.sh
+++ b/t/t6302-for-each-ref-filter.sh
@@ -58,4 +58,18 @@ test_expect_success 'filtering with --no-merged' '
 	test_cmp expect actual
 '
 
+test_expect_success 'filtering with --contains' '
+	cat >expect <<-\EOF &&
+	refs/heads/master
+	refs/heads/side
+	refs/odd/spot
+	refs/tags/four
+	refs/tags/signed-tag
+	refs/tags/three
+	refs/tags/two
+	EOF
+	git for-each-ref --format="%(refname)" --contains=two >actual &&
+	test_cmp expect actual
+'
+
 test_done
-- 
2.4.4

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [PATCH v6 03/11] ref-filter: implement '--points-at' option
  2015-06-25  8:57   ` [PATCH v6 03/11] ref-filter: implement '--points-at' option Karthik Nayak
@ 2015-06-29 17:40     ` Junio C Hamano
  2015-06-29 19:37       ` Karthik Nayak
  0 siblings, 1 reply; 25+ messages in thread
From: Junio C Hamano @ 2015-06-29 17:40 UTC (permalink / raw)
  To: Karthik Nayak; +Cc: git, christian.couder, Matthieu.Moy

Karthik Nayak <karthik.188@gmail.com> writes:

> +/*
> + * Given a ref (sha1, refname) see if it points to one of the sha1s
> + * in a sha1_array.
> + */
> +static int match_points_at(struct sha1_array *points_at, const unsigned char *sha1,
> +			   const char *refname)
> +{
> +	struct object *obj;
> +
> +	if (!points_at || !points_at->nr)
> +		return 1;
> +
> +	if (sha1_array_lookup(points_at, sha1) >= 0)
> +		return 1;
> +
> +	obj = parse_object_or_die(sha1, refname);
> +	if (obj->type == OBJ_TAG &&
> +	    sha1_array_lookup(points_at, ((struct tag *)obj)->tagged->sha1) >= 0)
> +		return 1;
> +
> +	return 0;
> +}
> +

Interesting.  I think the change done while copying the code does
not change anything from the original (other than that the helper
lost its ability to return the peeled object name), and I think you
shouldn't make any change while copying the code that would change
the benaviour, but I notice a few things that we might want to keep
in mind and revisit them later (i.e. might be a good idea to add
NEEDSWORK comment to record them near the function):

 - The original only peeled one level of indirection, so does this
   implementation.  But is that really what we want, I wonder?

   After doing:

   $ git tag -a -m 'annotated' atag $commit
   $ git tag -a -m 'annotated doubly' dtag atag

   atag^0, dtag^0 and $commit all refer to the same commit object.
   Do we want to miss dtag with --point-at=$commit?

 - As we are in for-each-ref (or eventually tag -l) that is walking
   the cached refs, we may know what refname peels to without
   parsing the object at all.  Could it be more efficient to ask
   peel_ref() for the pointee without doing parse_object()
   ourselves?

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v6 04/11] for-each-ref: add '--points-at' option
  2015-06-25  8:57   ` [PATCH v6 04/11] for-each-ref: add " Karthik Nayak
@ 2015-06-29 17:46     ` Junio C Hamano
  2015-06-29 19:55       ` Karthik Nayak
  2015-06-29 18:38     ` Junio C Hamano
  1 sibling, 1 reply; 25+ messages in thread
From: Junio C Hamano @ 2015-06-29 17:46 UTC (permalink / raw)
  To: Karthik Nayak; +Cc: git, christian.couder, Matthieu.Moy

Karthik Nayak <karthik.188@gmail.com> writes:

> Add the '--points-at' option provided by 'ref-filter'. The option
> lets the user to pick only refs which point to a particular
> commit.

It somehow feels strange that the option name is points-at and all
the explanation (like the above and also in the doc) talks about
pointing to an object.  Not limited to this patch but the previous
one had the same, I think.

> diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh
> index b1fa8d4..7269a66 100644
> --- a/t/t6302-for-each-ref-filter.sh
> +++ b/t/t6302-for-each-ref-filter.sh
> @@ -16,4 +16,24 @@ test_expect_success 'setup some history and refs' '
>  	git update-ref refs/odd/spot master
>  '
>  
> +test_expect_success 'filtering with --points-at' '
> +	cat >expect <<-\EOF &&
> +	refs/heads/master
> +	refs/odd/spot
> +	refs/tags/three
> +	EOF
> +	git for-each-ref --format="%(refname)" --points-at=master >actual &&
> +	test_cmp expect actual
> +'
> +
> +test_expect_success 'check signed tags with --points-at' '
> +	cat >expect <<-\EOF &&
> +	refs/heads/side
> +	refs/tags/four
> +	refs/tags/signed-tag four
> +	EOF
> +	git for-each-ref --format="%(refname) %(*subject)" --points-at=side >actual &&
> +	test_cmp expect actual
> +'

This shows that we would want to add a "annotated doubly" tag in the
preparation step 01/11; the expected outcome is that it will not
show in the output, I think.

Thanks.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v6 06/11] ref-filter: implement '--merged' and '--no-merged' options
  2015-06-25  8:57   ` [PATCH v6 06/11] ref-filter: implement '--merged' and '--no-merged' options Karthik Nayak
@ 2015-06-29 18:03     ` Junio C Hamano
  2015-06-29 18:28       ` Junio C Hamano
  2015-06-30 13:38       ` Karthik Nayak
  0 siblings, 2 replies; 25+ messages in thread
From: Junio C Hamano @ 2015-06-29 18:03 UTC (permalink / raw)
  To: Karthik Nayak; +Cc: git, christian.couder, Matthieu.Moy

Karthik Nayak <karthik.188@gmail.com> writes:

> +static void do_merge_filter(struct ref_filter_cbdata *ref_cbdata)
> +{
> +	struct rev_info revs;
> +	int i, old_nr;
> +	struct ref_filter *filter = ref_cbdata->filter;
> +	struct ref_array *array = ref_cbdata->array;
> +	struct commit **to_clear = xcalloc(sizeof(struct commit *), array->nr);
> +
> +	init_revisions(&revs, NULL);
> +
> +	for (i = 0; i < array->nr; i++) {
> +		struct ref_array_item *item = array->items[i];
> +		add_pending_object(&revs, &item->commit->object, item->refname);
> +		to_clear[i] = item->commit;
> +	}
> +
> +	filter->merge_commit->object.flags |= UNINTERESTING;
> +	add_pending_object(&revs, &filter->merge_commit->object, "");
> +
> +	revs.limited = 1;
> +	if (prepare_revision_walk(&revs))
> +		die(_("revision walk setup failed"));
> +
> +	old_nr = array->nr;
> +	array->nr = 0;
> +
> +	for (i = 0; i < old_nr; i++) {
> +		struct ref_array_item *item = array->items[i];
> +		struct commit *commit = item->commit;
> +
> +		int is_merged = !!(commit->object.flags & UNINTERESTING);
> +
> +		if (is_merged == (filter->merge == REF_FILTER_MERGED_INCLUDE))
> +			array->items[array->nr++] = array->items[i];
> +		else
> +			free_array_item(item);
> +	}
> +
> +	for (i = 0; i < old_nr; i++)
> +		clear_commit_marks(to_clear[i], ALL_REV_FLAGS);
> +	clear_commit_marks(filter->merge_commit, ALL_REV_FLAGS);
> +	free(to_clear);
> +}

Did this come from somewhere else (e.g. tag -l or branch -l)?  If
so, you'd need a note similar to what you added in [02/11] to the
original.

I also have a feeling that compared to an implementation based on
paint_down_to_common(), including is_descendant_of(), this may be
less precise (e.g. it would be confused with clock skew that lasts
more than SLOP commits).  If we are inventing a new helper (as
opposed to moving an existing one), we'd probably be better off
doing a thin wrapper around paint_down_to_common() than calling
revision-walk machinery.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v6 01/11] t6302: for-each-ref tests for ref-filter APIs
  2015-06-25  8:57 ` [PATCH v6 01/11] t6302: for-each-ref tests for ref-filter APIs Karthik Nayak
                     ` (9 preceding siblings ...)
  2015-06-25  8:57   ` [PATCH v6 11/11] for-each-ref: add " Karthik Nayak
@ 2015-06-29 18:14   ` Junio C Hamano
  2015-06-29 18:43     ` Karthik Nayak
  10 siblings, 1 reply; 25+ messages in thread
From: Junio C Hamano @ 2015-06-29 18:14 UTC (permalink / raw)
  To: Karthik Nayak; +Cc: git, christian.couder, Matthieu.Moy

Karthik Nayak <karthik.188@gmail.com> writes:

>  t/t6302-for-each-ref-filter.sh | 19 +++++++++++++++++++
>  1 file changed, 19 insertions(+)
>  create mode 100644 t/t6302-for-each-ref-filter.sh

non-executable tests: t6302-for-each-ref-filter.sh

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v6 06/11] ref-filter: implement '--merged' and '--no-merged' options
  2015-06-29 18:03     ` Junio C Hamano
@ 2015-06-29 18:28       ` Junio C Hamano
  2015-06-30 13:38       ` Karthik Nayak
  1 sibling, 0 replies; 25+ messages in thread
From: Junio C Hamano @ 2015-06-29 18:28 UTC (permalink / raw)
  To: Karthik Nayak; +Cc: git, christian.couder, Matthieu.Moy

Junio C Hamano <gitster@pobox.com> writes:

> Karthik Nayak <karthik.188@gmail.com> writes:
>
>> +static void do_merge_filter(struct ref_filter_cbdata *ref_cbdata)
>> +{
>> ...
>> +	for (i = 0; i < array->nr; i++) {
>> +		struct ref_array_item *item = array->items[i];
>> +		add_pending_object(&revs, &item->commit->object, item->refname);
>> +		to_clear[i] = item->commit;
>> +	}
>> +
>> +	filter->merge_commit->object.flags |= UNINTERESTING;
>> +	add_pending_object(&revs, &filter->merge_commit->object, "");
>> +
>> +	revs.limited = 1;
>> +	if (prepare_revision_walk(&revs))
>> +		die(_("revision walk setup failed"));
>> + ...
>
> Did this come from somewhere else (e.g. tag -l or branch -l)?  If
> so, you'd need a note similar to what you added in [02/11] to the
> original.

Ah, now I see this came from a part of print_ref_list in
builtin/branch.c; you would want to leave a note there.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v6 04/11] for-each-ref: add '--points-at' option
  2015-06-25  8:57   ` [PATCH v6 04/11] for-each-ref: add " Karthik Nayak
  2015-06-29 17:46     ` Junio C Hamano
@ 2015-06-29 18:38     ` Junio C Hamano
  2015-06-29 19:11       ` Karthik Nayak
  1 sibling, 1 reply; 25+ messages in thread
From: Junio C Hamano @ 2015-06-29 18:38 UTC (permalink / raw)
  To: Karthik Nayak; +Cc: git, christian.couder, Matthieu.Moy

Karthik Nayak <karthik.188@gmail.com> writes:

> +test_expect_success 'check signed tags with --points-at' '
> +	cat >expect <<-\EOF &&
> +	refs/heads/side
> +	refs/tags/four
> +	refs/tags/signed-tag four
> +	EOF
> +	git for-each-ref --format="%(refname) %(*subject)" --points-at=side >actual &&
> +	test_cmp expect actual
> +'

This piece seems to fail without a trailing whitespace in the
expected file.  I initially suspected that they were dropped
on my end while applying with "git am --whitespace=fix", but going
back to my mailbox, it seems that what gmane received does not have
them in the first place:

	sed -e "s/Z$//" <<-\EOF &&
        refs/heads/side Z
        refs/tags/four Z
        refs/tags/signed-tag four
        EOF

or something like that to make the EOL more visible to those who are
reading the tests, perhaps?

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v6 01/11] t6302: for-each-ref tests for ref-filter APIs
  2015-06-29 18:14   ` [PATCH v6 01/11] t6302: for-each-ref tests for ref-filter APIs Junio C Hamano
@ 2015-06-29 18:43     ` Karthik Nayak
  0 siblings, 0 replies; 25+ messages in thread
From: Karthik Nayak @ 2015-06-29 18:43 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Git, Christian Couder, Matthieu Moy

On Mon, Jun 29, 2015 at 11:44 PM, Junio C Hamano <gitster@pobox.com> wrote:
> Karthik Nayak <karthik.188@gmail.com> writes:
>
>>  t/t6302-for-each-ref-filter.sh | 19 +++++++++++++++++++
>>  1 file changed, 19 insertions(+)
>>  create mode 100644 t/t6302-for-each-ref-filter.sh
>
> non-executable tests: t6302-for-each-ref-filter.sh

Renaming it defaulted to 644, will change, thanks :)

-- 
Regards,
Karthik Nayak

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v6 04/11] for-each-ref: add '--points-at' option
  2015-06-29 18:38     ` Junio C Hamano
@ 2015-06-29 19:11       ` Karthik Nayak
  0 siblings, 0 replies; 25+ messages in thread
From: Karthik Nayak @ 2015-06-29 19:11 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Git, Christian Couder, Matthieu Moy

On Tue, Jun 30, 2015 at 12:08 AM, Junio C Hamano <gitster@pobox.com> wrote:
> Karthik Nayak <karthik.188@gmail.com> writes:
>
>> +test_expect_success 'check signed tags with --points-at' '
>> +     cat >expect <<-\EOF &&
>> +     refs/heads/side
>> +     refs/tags/four
>> +     refs/tags/signed-tag four
>> +     EOF
>> +     git for-each-ref --format="%(refname) %(*subject)" --points-at=side >actual &&
>> +     test_cmp expect actual
>> +'
>
> This piece seems to fail without a trailing whitespace in the
> expected file.  I initially suspected that they were dropped
> on my end while applying with "git am --whitespace=fix", but going
> back to my mailbox, it seems that what gmane received does not have
> them in the first place:
>
>         sed -e "s/Z$//" <<-\EOF &&
>         refs/heads/side Z
>         refs/tags/four Z
>         refs/tags/signed-tag four
>         EOF
>
> or something like that to make the EOL more visible to those who are
> reading the tests, perhaps?

Thanks, will use sed like you suggested.

-- 
Regards,
Karthik Nayak

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v6 03/11] ref-filter: implement '--points-at' option
  2015-06-29 17:40     ` Junio C Hamano
@ 2015-06-29 19:37       ` Karthik Nayak
  0 siblings, 0 replies; 25+ messages in thread
From: Karthik Nayak @ 2015-06-29 19:37 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Git, Christian Couder, Matthieu Moy

On Mon, Jun 29, 2015 at 11:10 PM, Junio C Hamano <gitster@pobox.com> wrote:
> Karthik Nayak <karthik.188@gmail.com> writes:
>
>> +/*
>> + * Given a ref (sha1, refname) see if it points to one of the sha1s
>> + * in a sha1_array.
>> + */
>> +static int match_points_at(struct sha1_array *points_at, const unsigned char *sha1,
>> +                        const char *refname)
>> +{
>> +     struct object *obj;
>> +
>> +     if (!points_at || !points_at->nr)
>> +             return 1;
>> +
>> +     if (sha1_array_lookup(points_at, sha1) >= 0)
>> +             return 1;
>> +
>> +     obj = parse_object_or_die(sha1, refname);
>> +     if (obj->type == OBJ_TAG &&
>> +         sha1_array_lookup(points_at, ((struct tag *)obj)->tagged->sha1) >= 0)
>> +             return 1;
>> +
>> +     return 0;
>> +}
>> +
>
> Interesting.  I think the change done while copying the code does
> not change anything from the original (other than that the helper
> lost its ability to return the peeled object name), and I think you
> shouldn't make any change while copying the code that would change
> the benaviour, but I notice a few things that we might want to keep
> in mind and revisit them later (i.e. might be a good idea to add
> NEEDSWORK comment to record them near the function):

Reverted the change.
OK will do and add this, I will work on this after GSoC is done.
But like you said I'll add a comment so if someone wants to they can
work on it for now.

>
>  - The original only peeled one level of indirection, so does this
>    implementation.  But is that really what we want, I wonder?
>
>    After doing:
>
>    $ git tag -a -m 'annotated' atag $commit
>    $ git tag -a -m 'annotated doubly' dtag atag
>
>    atag^0, dtag^0 and $commit all refer to the same commit object.
>    Do we want to miss dtag with --point-at=$commit?
>
>  - As we are in for-each-ref (or eventually tag -l) that is walking
>    the cached refs, we may know what refname peels to without
>    parsing the object at all.  Could it be more efficient to ask
>    peel_ref() for the pointee without doing parse_object()
>    ourselves?
>

Shouldn't both these scenarios be solved together by using peel_ref()?

After what you said I just tried a hacked up version of using peel_ref()
rather than parsing the object, tried it out on the Linux tree.

$time git tag -l --points-at=HEAD~501
git tag -l --points-at=HEAD~501  0.03s user 0.01s system 97% cpu 0.044 total

*Using the modified version which uses peel_ref() *
$time ../git/git tag -l --points-at=HEAD~501
../git/git tag -l --points-at=HEAD~501  0.01s user 0.02s system 90%
cpu 0.033 total

This was the average of around 5 tests, Might not be the best way to check, but
I'm sure there's an improvement.

Thanks :)

-- 
Regards,
Karthik Nayak

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v6 04/11] for-each-ref: add '--points-at' option
  2015-06-29 17:46     ` Junio C Hamano
@ 2015-06-29 19:55       ` Karthik Nayak
  0 siblings, 0 replies; 25+ messages in thread
From: Karthik Nayak @ 2015-06-29 19:55 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Git, Christian Couder, Matthieu Moy

On Mon, Jun 29, 2015 at 11:16 PM, Junio C Hamano <gitster@pobox.com> wrote:
> Karthik Nayak <karthik.188@gmail.com> writes:
>
>> Add the '--points-at' option provided by 'ref-filter'. The option
>> lets the user to pick only refs which point to a particular
>> commit.
>
> It somehow feels strange that the option name is points-at and all
> the explanation (like the above and also in the doc) talks about
> pointing to an object.  Not limited to this patch but the previous
> one had the same, I think.
>

Will have a look and change, thanks :)

>> diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh
>> index b1fa8d4..7269a66 100644
>> --- a/t/t6302-for-each-ref-filter.sh
>> +++ b/t/t6302-for-each-ref-filter.sh
>> @@ -16,4 +16,24 @@ test_expect_success 'setup some history and refs' '
>>       git update-ref refs/odd/spot master
>>  '
>>
>> +test_expect_success 'filtering with --points-at' '
>> +     cat >expect <<-\EOF &&
>> +     refs/heads/master
>> +     refs/odd/spot
>> +     refs/tags/three
>> +     EOF
>> +     git for-each-ref --format="%(refname)" --points-at=master >actual &&
>> +     test_cmp expect actual
>> +'
>> +
>> +test_expect_success 'check signed tags with --points-at' '
>> +     cat >expect <<-\EOF &&
>> +     refs/heads/side
>> +     refs/tags/four
>> +     refs/tags/signed-tag four
>> +     EOF
>> +     git for-each-ref --format="%(refname) %(*subject)" --points-at=side >actual &&
>> +     test_cmp expect actual
>> +'
>
> This shows that we would want to add a "annotated doubly" tag in the
> preparation step 01/11; the expected outcome is that it will not
> show in the output, I think.
>
> Thanks.

Will add!

-- 
Regards,
Karthik Nayak

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v6 06/11] ref-filter: implement '--merged' and '--no-merged' options
  2015-06-29 18:03     ` Junio C Hamano
  2015-06-29 18:28       ` Junio C Hamano
@ 2015-06-30 13:38       ` Karthik Nayak
  2015-06-30 15:58         ` Junio C Hamano
  1 sibling, 1 reply; 25+ messages in thread
From: Karthik Nayak @ 2015-06-30 13:38 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Git, Christian Couder, Matthieu Moy

On Mon, Jun 29, 2015 at 11:33 PM, Junio C Hamano <gitster@pobox.com> wrote:
> Karthik Nayak <karthik.188@gmail.com> writes:
>
>> +static void do_merge_filter(struct ref_filter_cbdata *ref_cbdata)
>> +{
>> +     struct rev_info revs;
>> +     int i, old_nr;
>> +     struct ref_filter *filter = ref_cbdata->filter;
>> +     struct ref_array *array = ref_cbdata->array;
>> +     struct commit **to_clear = xcalloc(sizeof(struct commit *), array->nr);
>> +
>> +     init_revisions(&revs, NULL);
>> +
>> +     for (i = 0; i < array->nr; i++) {
>> +             struct ref_array_item *item = array->items[i];
>> +             add_pending_object(&revs, &item->commit->object, item->refname);
>> +             to_clear[i] = item->commit;
>> +     }
>> +
>> +     filter->merge_commit->object.flags |= UNINTERESTING;
>> +     add_pending_object(&revs, &filter->merge_commit->object, "");
>> +
>> +     revs.limited = 1;
>> +     if (prepare_revision_walk(&revs))
>> +             die(_("revision walk setup failed"));
>> +
>> +     old_nr = array->nr;
>> +     array->nr = 0;
>> +
>> +     for (i = 0; i < old_nr; i++) {
>> +             struct ref_array_item *item = array->items[i];
>> +             struct commit *commit = item->commit;
>> +
>> +             int is_merged = !!(commit->object.flags & UNINTERESTING);
>> +
>> +             if (is_merged == (filter->merge == REF_FILTER_MERGED_INCLUDE))
>> +                     array->items[array->nr++] = array->items[i];
>> +             else
>> +                     free_array_item(item);
>> +     }
>> +
>> +     for (i = 0; i < old_nr; i++)
>> +             clear_commit_marks(to_clear[i], ALL_REV_FLAGS);
>> +     clear_commit_marks(filter->merge_commit, ALL_REV_FLAGS);
>> +     free(to_clear);
>> +}
>
> Did this come from somewhere else (e.g. tag -l or branch -l)?  If
> so, you'd need a note similar to what you added in [02/11] to the
> original.
>

Will do this, thanks.

> I also have a feeling that compared to an implementation based on
> paint_down_to_common(), including is_descendant_of(), this may be
> less precise (e.g. it would be confused with clock skew that lasts
> more than SLOP commits).  If we are inventing a new helper (as
> opposed to moving an existing one), we'd probably be better off
> doing a thin wrapper around paint_down_to_common() than calling
> revision-walk machinery.
>

I'll have a look and get back to you.

-- 
Regards,
Karthik Nayak

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v6 06/11] ref-filter: implement '--merged' and '--no-merged' options
  2015-06-30 13:38       ` Karthik Nayak
@ 2015-06-30 15:58         ` Junio C Hamano
  2015-06-30 16:04           ` Karthik Nayak
  0 siblings, 1 reply; 25+ messages in thread
From: Junio C Hamano @ 2015-06-30 15:58 UTC (permalink / raw)
  To: Karthik Nayak; +Cc: Git, Christian Couder, Matthieu Moy

Karthik Nayak <karthik.188@gmail.com> writes:

>> I also have a feeling that compared to an implementation based on
>> paint_down_to_common(), including is_descendant_of(), this may be
>> less precise (e.g. it would be confused with clock skew that lasts
>> more than SLOP commits).  If we are inventing a new helper (as
>> opposed to moving an existing one), we'd probably be better off
>> doing a thin wrapper around paint_down_to_common() than calling
>> revision-walk machinery.
>
> I'll have a look and get back to you.

Not as part of this series, now I know it is a straight-forward port
of what we already have for "branch --merged".  This series is not
yet about improving counting logic but first unifying the three.

Thanks.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v6 06/11] ref-filter: implement '--merged' and '--no-merged' options
  2015-06-30 15:58         ` Junio C Hamano
@ 2015-06-30 16:04           ` Karthik Nayak
  0 siblings, 0 replies; 25+ messages in thread
From: Karthik Nayak @ 2015-06-30 16:04 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Git, Christian Couder, Matthieu Moy

On Tue, Jun 30, 2015 at 9:28 PM, Junio C Hamano <gitster@pobox.com> wrote:
> Karthik Nayak <karthik.188@gmail.com> writes:
>
>>> I also have a feeling that compared to an implementation based on
>>> paint_down_to_common(), including is_descendant_of(), this may be
>>> less precise (e.g. it would be confused with clock skew that lasts
>>> more than SLOP commits).  If we are inventing a new helper (as
>>> opposed to moving an existing one), we'd probably be better off
>>> doing a thin wrapper around paint_down_to_common() than calling
>>> revision-walk machinery.
>>
>> I'll have a look and get back to you.
>
> Not as part of this series, now I know it is a straight-forward port
> of what we already have for "branch --merged".  This series is not
> yet about improving counting logic but first unifying the three.
>
> Thanks.
>

Sure, added this to my personal TODO :)

-- 
Regards,
Karthik Nayak

^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2015-06-30 16:05 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-06-25  8:46 [PATCH v6 00/11] add options to for-each-ref Karthik Nayak
2015-06-25  8:57 ` [PATCH v6 01/11] t6302: for-each-ref tests for ref-filter APIs Karthik Nayak
2015-06-25  8:57   ` [PATCH v6 02/11] tag: libify parse_opt_points_at() Karthik Nayak
2015-06-25  8:57   ` [PATCH v6 03/11] ref-filter: implement '--points-at' option Karthik Nayak
2015-06-29 17:40     ` Junio C Hamano
2015-06-29 19:37       ` Karthik Nayak
2015-06-25  8:57   ` [PATCH v6 04/11] for-each-ref: add " Karthik Nayak
2015-06-29 17:46     ` Junio C Hamano
2015-06-29 19:55       ` Karthik Nayak
2015-06-29 18:38     ` Junio C Hamano
2015-06-29 19:11       ` Karthik Nayak
2015-06-25  8:57   ` [PATCH v6 05/11] ref-filter: add parse_opt_merge_filter() Karthik Nayak
2015-06-25  8:57   ` [PATCH v6 06/11] ref-filter: implement '--merged' and '--no-merged' options Karthik Nayak
2015-06-29 18:03     ` Junio C Hamano
2015-06-29 18:28       ` Junio C Hamano
2015-06-30 13:38       ` Karthik Nayak
2015-06-30 15:58         ` Junio C Hamano
2015-06-30 16:04           ` Karthik Nayak
2015-06-25  8:57   ` [PATCH v6 07/11] for-each-ref: add " Karthik Nayak
2015-06-25  8:57   ` [PATCH v6 08/11] parse-option: rename parse_opt_with_commit() Karthik Nayak
2015-06-25  8:57   ` [PATCH v6 09/11] parse-options.h: add macros for '--contains' option Karthik Nayak
2015-06-25  8:57   ` [PATCH v6 10/11] ref-filter: implement " Karthik Nayak
2015-06-25  8:57   ` [PATCH v6 11/11] for-each-ref: add " Karthik Nayak
2015-06-29 18:14   ` [PATCH v6 01/11] t6302: for-each-ref tests for ref-filter APIs Junio C Hamano
2015-06-29 18:43     ` Karthik Nayak

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).