* [PATCH v8 00/11] add options to for-each-ref
@ 2015-07-07 16:05 Karthik Nayak
2015-07-07 16:06 ` [PATCH v8 01/11] t6302: for-each-ref tests for ref-filter APIs Karthik Nayak
0 siblings, 1 reply; 18+ messages in thread
From: Karthik Nayak @ 2015-07-07 16:05 UTC (permalink / raw)
To: Git; +Cc: Junio C Hamano, Matthieu Moy, Christian Couder
v7 of this patch series can be found here :
http://article.gmane.org/gmane.comp.version-control.git/273233
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 v8:
[04/11]: Change "pertain to" to "points at", Grammatical change.
[05/11], [04/11]: Random spaces left in macro definition
[10/11]: Mention the movement of code from tag.c
Thanks to Matthieu Moy for suggestions on the previous versions.
--
Regards,
Karthik Nayak
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v8 01/11] t6302: for-each-ref tests for ref-filter APIs
2015-07-07 16:05 [PATCH v8 00/11] add options to for-each-ref Karthik Nayak
@ 2015-07-07 16:06 ` Karthik Nayak
2015-07-07 16:06 ` [PATCH v8 02/11] tag: libify parse_opt_points_at() Karthik Nayak
` (11 more replies)
0 siblings, 12 replies; 18+ messages in thread
From: Karthik Nayak @ 2015-07-07 16:06 UTC (permalink / raw)
To: git; +Cc: christian.couder, Matthieu.Moy, 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 | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
create mode 100755 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 100755
index 0000000..44d2f24
--- /dev/null
+++ b/t/t6302-for-each-ref-filter.sh
@@ -0,0 +1,20 @@
+#!/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 tag -s -m "Annonated doubly" double-tag signed-tag &&
+ git checkout master &&
+ git update-ref refs/odd/spot master
+'
+
+test_done
--
2.4.5
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v8 02/11] tag: libify parse_opt_points_at()
2015-07-07 16:06 ` [PATCH v8 01/11] t6302: for-each-ref tests for ref-filter APIs Karthik Nayak
@ 2015-07-07 16:06 ` Karthik Nayak
2015-07-07 16:06 ` [PATCH v8 03/11] ref-filter: implement '--points-at' option Karthik Nayak
` (10 subsequent siblings)
11 siblings, 0 replies; 18+ messages in thread
From: Karthik Nayak @ 2015-07-07 16:06 UTC (permalink / raw)
To: git; +Cc: christian.couder, Matthieu.Moy, 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 ca865f6..1478818 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -223,6 +223,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.5
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v8 03/11] ref-filter: implement '--points-at' option
2015-07-07 16:06 ` [PATCH v8 01/11] t6302: for-each-ref tests for ref-filter APIs Karthik Nayak
2015-07-07 16:06 ` [PATCH v8 02/11] tag: libify parse_opt_points_at() Karthik Nayak
@ 2015-07-07 16:06 ` Karthik Nayak
2015-07-07 16:06 ` [PATCH v8 04/11] for-each-ref: add " Karthik Nayak
` (9 subsequent siblings)
11 siblings, 0 replies; 18+ messages in thread
From: Karthik Nayak @ 2015-07-07 16:06 UTC (permalink / raw)
To: git; +Cc: christian.couder, Matthieu.Moy, Karthik Nayak
In 'tag -l' we have '--points-at' option which lets users
list only tags of a given object. 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 | 35 +++++++++++++++++++++++++++++++++++
ref-filter.h | 1 +
3 files changed, 40 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 c4004db..58e532c 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -842,6 +842,38 @@ static int match_name_as_path(const char **pattern, const char *refname)
return 0;
}
+/*
+ * Given a ref (sha1, refname), check if the ref belongs to the array
+ * of sha1s. If the given ref is a tag, check if the given tag points
+ * at one of the sha1s in the given sha1 array.
+ * the given sha1_array.
+ * NEEDSWORK:
+ * 1. Only a single level of inderection is obtained, we might want to
+ * change this to account for multiple levels (e.g. annotated tags
+ * pointing to annotated tags pointing to a commit.)
+ * 2. As the refs are cached we might know what refname peels to without
+ * the need to parse the object via parse_object(). peel_ref() might be a
+ * more efficient alternative to obtain the pointee.
+ */
+static const unsigned char *match_points_at(struct sha1_array *points_at,
+ const unsigned char *sha1,
+ const char *refname)
+{
+ const unsigned char *tagged_sha1 = NULL;
+ struct object *obj;
+
+ if (sha1_array_lookup(points_at, sha1) >= 0)
+ return sha1;
+ obj = parse_object(sha1);
+ if (!obj)
+ die(_("malformed object at '%s'"), refname);
+ if (obj->type == OBJ_TAG)
+ tagged_sha1 = ((struct tag *)obj)->tagged->sha1;
+ if (tagged_sha1 && sha1_array_lookup(points_at, tagged_sha1) >= 0)
+ return tagged_sha1;
+ return NULL;
+}
+
/* 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,
@@ -880,6 +912,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 (filter->points_at.nr && !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.5
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v8 04/11] for-each-ref: add '--points-at' option
2015-07-07 16:06 ` [PATCH v8 01/11] t6302: for-each-ref tests for ref-filter APIs Karthik Nayak
2015-07-07 16:06 ` [PATCH v8 02/11] tag: libify parse_opt_points_at() Karthik Nayak
2015-07-07 16:06 ` [PATCH v8 03/11] ref-filter: implement '--points-at' option Karthik Nayak
@ 2015-07-07 16:06 ` Karthik Nayak
2015-07-07 16:06 ` [PATCH v8 05/11] ref-filter: add parse_opt_merge_filter() Karthik Nayak
` (8 subsequent siblings)
11 siblings, 0 replies; 18+ messages in thread
From: Karthik Nayak @ 2015-07-07 16:06 UTC (permalink / raw)
To: git; +Cc: christian.couder, Matthieu.Moy, Karthik Nayak
Add the '--points-at' option provided by 'ref-filter'. The
option lets the user to list only refs which points at the
given object.
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..ff0283b 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 which points at the given object.
FIELD NAMES
-----------
diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c
index 7919206..ae5419e 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 which points at 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 44d2f24..457991f 100755
--- a/t/t6302-for-each-ref-filter.sh
+++ b/t/t6302-for-each-ref-filter.sh
@@ -17,4 +17,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' '
+ sed -e "s/Z$//" >expect <<-\EOF &&
+ refs/heads/side Z
+ refs/tags/four Z
+ 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.5
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v8 05/11] ref-filter: add parse_opt_merge_filter()
2015-07-07 16:06 ` [PATCH v8 01/11] t6302: for-each-ref tests for ref-filter APIs Karthik Nayak
` (2 preceding siblings ...)
2015-07-07 16:06 ` [PATCH v8 04/11] for-each-ref: add " Karthik Nayak
@ 2015-07-07 16:06 ` Karthik Nayak
2015-07-07 16:06 ` [PATCH v8 06/11] ref-filter: implement '--merged' and '--no-merged' options Karthik Nayak
` (7 subsequent siblings)
11 siblings, 0 replies; 18+ messages in thread
From: Karthik Nayak @ 2015-07-07 16:06 UTC (permalink / raw)
To: git; +Cc: christian.couder, Matthieu.Moy, 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 58e532c..b4753ab 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -1139,3 +1139,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..443cfa7 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.5
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v8 06/11] ref-filter: implement '--merged' and '--no-merged' options
2015-07-07 16:06 ` [PATCH v8 01/11] t6302: for-each-ref tests for ref-filter APIs Karthik Nayak
` (3 preceding siblings ...)
2015-07-07 16:06 ` [PATCH v8 05/11] ref-filter: add parse_opt_merge_filter() Karthik Nayak
@ 2015-07-07 16:06 ` Karthik Nayak
2015-07-07 16:06 ` [PATCH v8 07/11] for-each-ref: add " Karthik Nayak
` (6 subsequent siblings)
11 siblings, 0 replies; 18+ messages in thread
From: Karthik Nayak @ 2015-07-07 16:06 UTC (permalink / raw)
To: git; +Cc: christian.couder, Matthieu.Moy, 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>
---
builtin/branch.c | 4 ++++
ref-filter.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++----
ref-filter.h | 8 +++++++
3 files changed, 81 insertions(+), 4 deletions(-)
diff --git a/builtin/branch.c b/builtin/branch.c
index ddd90e6..e63102e 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -635,6 +635,10 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru
cb.pattern = pattern;
cb.ret = 0;
for_each_rawref(append_ref, &cb);
+ /*
+ * The following implementation is currently duplicated in ref-filter. It
+ * will eventually be removed when we port branch.c to use ref-filter APIs.
+ */
if (merge_filter != NO_FILTER) {
struct commit *filter;
filter = lookup_commit_reference_gently(merge_filter_ref, 0);
diff --git a/ref-filter.c b/ref-filter.c
index b4753ab..148b7cd 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;
@@ -898,6 +899,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);
@@ -916,11 +918,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;
@@ -946,6 +960,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
@@ -955,17 +1013,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 443cfa7..f115174 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.5
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v8 07/11] for-each-ref: add '--merged' and '--no-merged' options
2015-07-07 16:06 ` [PATCH v8 01/11] t6302: for-each-ref tests for ref-filter APIs Karthik Nayak
` (4 preceding siblings ...)
2015-07-07 16:06 ` [PATCH v8 06/11] ref-filter: implement '--merged' and '--no-merged' options Karthik Nayak
@ 2015-07-07 16:06 ` Karthik Nayak
2015-07-07 16:06 ` [PATCH v8 08/11] parse-option: rename parse_opt_with_commit() Karthik Nayak
` (5 subsequent siblings)
11 siblings, 0 replies; 18+ messages in thread
From: Karthik Nayak @ 2015-07-07 16:06 UTC (permalink / raw)
To: git; +Cc: christian.couder, Matthieu.Moy, 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 | 23 +++++++++++++++++++++++
3 files changed, 35 insertions(+), 1 deletion(-)
diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index ff0283b..2842195 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 which points at 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 ae5419e..7521850 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 which points at 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 457991f..73dbf53 100755
--- a/t/t6302-for-each-ref-filter.sh
+++ b/t/t6302-for-each-ref-filter.sh
@@ -37,4 +37,27 @@ 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/double-tag
+ 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.5
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v8 08/11] parse-option: rename parse_opt_with_commit()
2015-07-07 16:06 ` [PATCH v8 01/11] t6302: for-each-ref tests for ref-filter APIs Karthik Nayak
` (5 preceding siblings ...)
2015-07-07 16:06 ` [PATCH v8 07/11] for-each-ref: add " Karthik Nayak
@ 2015-07-07 16:06 ` Karthik Nayak
2015-07-07 16:06 ` [PATCH v8 09/11] parse-options.h: add macros for '--contains' option Karthik Nayak
` (4 subsequent siblings)
11 siblings, 0 replies; 18+ messages in thread
From: Karthik Nayak @ 2015-07-07 16:06 UTC (permalink / raw)
To: git; +Cc: christian.couder, Matthieu.Moy, 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 e63102e..ae9a0eb 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -832,13 +832,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 1478818..583690c 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -224,7 +224,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.5
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v8 09/11] parse-options.h: add macros for '--contains' option
2015-07-07 16:06 ` [PATCH v8 01/11] t6302: for-each-ref tests for ref-filter APIs Karthik Nayak
` (6 preceding siblings ...)
2015-07-07 16:06 ` [PATCH v8 08/11] parse-option: rename parse_opt_with_commit() Karthik Nayak
@ 2015-07-07 16:06 ` Karthik Nayak
2015-07-07 16:06 ` [PATCH v8 10/11] ref-filter: implement " Karthik Nayak
` (3 subsequent siblings)
11 siblings, 0 replies; 18+ messages in thread
From: Karthik Nayak @ 2015-07-07 16:06 UTC (permalink / raw)
To: git; +Cc: christian.couder, Matthieu.Moy, 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 ae9a0eb..c443cd8 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -828,18 +828,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 583690c..7ea22b2 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -246,5 +246,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.5
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v8 10/11] ref-filter: implement '--contains' option
2015-07-07 16:06 ` [PATCH v8 01/11] t6302: for-each-ref tests for ref-filter APIs Karthik Nayak
` (7 preceding siblings ...)
2015-07-07 16:06 ` [PATCH v8 09/11] parse-options.h: add macros for '--contains' option Karthik Nayak
@ 2015-07-07 16:06 ` Karthik Nayak
2015-07-07 16:06 ` [PATCH v8 11/11] for-each-ref: add " Karthik Nayak
` (2 subsequent siblings)
11 siblings, 0 replies; 18+ messages in thread
From: Karthik Nayak @ 2015-07-07 16:06 UTC (permalink / raw)
To: git; +Cc: christian.couder, Matthieu.Moy, 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>
---
builtin/tag.c | 5 +++
ref-filter.c | 114 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
ref-filter.h | 3 ++
3 files changed, 121 insertions(+), 1 deletion(-)
diff --git a/builtin/tag.c b/builtin/tag.c
index 767162e..071d001 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -86,6 +86,11 @@ static int in_commit_list(const struct commit_list *want, struct commit *c)
return 0;
}
+/*
+ * The entire code segment for supporting the --contains option has been
+ * copied over to ref-filter.{c,h}. This will be deleted evetually when
+ * we port tag.c to use ref-filter APIs.
+ */
enum contains_result {
CONTAINS_UNKNOWN = -1,
CONTAINS_NO = 0,
diff --git a/ref-filter.c b/ref-filter.c
index 148b7cd..dd0709d 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"
@@ -922,10 +1030,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 f115174..6bf27d8 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.5
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v8 11/11] for-each-ref: add '--contains' option
2015-07-07 16:06 ` [PATCH v8 01/11] t6302: for-each-ref tests for ref-filter APIs Karthik Nayak
` (8 preceding siblings ...)
2015-07-07 16:06 ` [PATCH v8 10/11] ref-filter: implement " Karthik Nayak
@ 2015-07-07 16:06 ` Karthik Nayak
2015-07-08 8:09 ` [PATCH v8 01/11] t6302: for-each-ref tests for ref-filter APIs Torsten Bögershausen
2015-07-09 6:03 ` Karthik Nayak
11 siblings, 0 replies; 18+ messages in thread
From: Karthik Nayak @ 2015-07-07 16:06 UTC (permalink / raw)
To: git; +Cc: christian.couder, Matthieu.Moy, 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 | 15 +++++++++++++++
3 files changed, 22 insertions(+)
diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index 2842195..e49d578 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 7521850..40f343b 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 73dbf53..9969a08 100755
--- a/t/t6302-for-each-ref-filter.sh
+++ b/t/t6302-for-each-ref-filter.sh
@@ -60,4 +60,19 @@ 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/double-tag
+ 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.5
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH v8 01/11] t6302: for-each-ref tests for ref-filter APIs
2015-07-07 16:06 ` [PATCH v8 01/11] t6302: for-each-ref tests for ref-filter APIs Karthik Nayak
` (9 preceding siblings ...)
2015-07-07 16:06 ` [PATCH v8 11/11] for-each-ref: add " Karthik Nayak
@ 2015-07-08 8:09 ` Torsten Bögershausen
2015-07-08 9:07 ` Matthieu Moy
2015-07-09 6:03 ` Karthik Nayak
11 siblings, 1 reply; 18+ messages in thread
From: Torsten Bögershausen @ 2015-07-08 8:09 UTC (permalink / raw)
To: Karthik Nayak, git; +Cc: christian.couder, Matthieu.Moy
On 2015-07-07 18.06, Karthik Nayak wrote:
> 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 | 20 ++++++++++++++++++++
> 1 file changed, 20 insertions(+)
> create mode 100755 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 100755
> index 0000000..44d2f24
> --- /dev/null
> +++ b/t/t6302-for-each-ref-filter.sh
> @@ -0,0 +1,20 @@
> +#!/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 tag -s -m "Annonated doubly" double-tag signed-tag &&
> + git checkout master &&
> + git update-ref refs/odd/spot master
> +'
> +
> +test_done
>
Could we have a tweak for people without gpg?
error: cannot run gpg: No such file or directory
error: could not run gpg.
error: unable to sign the tag
not ok 1 - setup some history and refs
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v8 01/11] t6302: for-each-ref tests for ref-filter APIs
2015-07-08 8:09 ` [PATCH v8 01/11] t6302: for-each-ref tests for ref-filter APIs Torsten Bögershausen
@ 2015-07-08 9:07 ` Matthieu Moy
2015-07-08 13:59 ` Karthik Nayak
0 siblings, 1 reply; 18+ messages in thread
From: Matthieu Moy @ 2015-07-08 9:07 UTC (permalink / raw)
To: Torsten Bögershausen; +Cc: Karthik Nayak, git, christian.couder
Torsten Bögershausen <tboegi@web.de> writes:
> Could we have a tweak for people without gpg?
I guess we need stg like
if ! test_have_prereq GPG; then
skip_all='skipping for-each-ref tests, gpg not available'
test_done
fi
since we need GPG in the setup test and almost all other tests will rely
on it.
--
Matthieu Moy
http://www-verimag.imag.fr/~moy/
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v8 01/11] t6302: for-each-ref tests for ref-filter APIs
2015-07-08 9:07 ` Matthieu Moy
@ 2015-07-08 13:59 ` Karthik Nayak
2015-07-08 15:46 ` Matthieu Moy
0 siblings, 1 reply; 18+ messages in thread
From: Karthik Nayak @ 2015-07-08 13:59 UTC (permalink / raw)
To: Matthieu Moy; +Cc: Torsten Bögershausen, Git, Christian Couder
On Wed, Jul 8, 2015 at 2:37 PM, Matthieu Moy
<Matthieu.Moy@grenoble-inp.fr> wrote:
> Torsten Bögershausen <tboegi@web.de> writes:
>
>> Could we have a tweak for people without gpg?
>
> I guess we need stg like
>
> if ! test_have_prereq GPG; then
> skip_all='skipping for-each-ref tests, gpg not available'
> test_done
> fi
>
> since we need GPG in the setup test and almost all other tests will rely
> on it.
>
Does this need to be there? I see a lot of test files which need GPG, and since
this test file contains tests which rely on it, without it, it would
be kinda useless
anyways?
--
Regards,
Karthik Nayak
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v8 01/11] t6302: for-each-ref tests for ref-filter APIs
2015-07-08 13:59 ` Karthik Nayak
@ 2015-07-08 15:46 ` Matthieu Moy
2015-07-09 5:52 ` Karthik Nayak
0 siblings, 1 reply; 18+ messages in thread
From: Matthieu Moy @ 2015-07-08 15:46 UTC (permalink / raw)
To: Karthik Nayak; +Cc: Torsten Bögershausen, Git, Christian Couder
Karthik Nayak <karthik.188@gmail.com> writes:
> On Wed, Jul 8, 2015 at 2:37 PM, Matthieu Moy
> <Matthieu.Moy@grenoble-inp.fr> wrote:
>> Torsten Bögershausen <tboegi@web.de> writes:
>>
>>> Could we have a tweak for people without gpg?
>>
>> I guess we need stg like
>>
>> if ! test_have_prereq GPG; then
>> skip_all='skipping for-each-ref tests, gpg not available'
>> test_done
>> fi
>>
>> since we need GPG in the setup test and almost all other tests will rely
>> on it.
>>
>
> Does this need to be there? I see a lot of test files which need GPG, and since
> this test file contains tests which rely on it, without it, it would
> be kinda useless
> anyways?
In many cases, the tests look like
. lib-gpg.sh
test_expect_success 'test that does not use GPG' '
...
'
test_expect_success GPG 'test that does use GPG' '
...
'
so you can't decide in lib-gpg.sh that you'll skip all tests, because
you would skip some tests that could be ran without gpg.
--
Matthieu Moy
http://www-verimag.imag.fr/~moy/
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v8 01/11] t6302: for-each-ref tests for ref-filter APIs
2015-07-08 15:46 ` Matthieu Moy
@ 2015-07-09 5:52 ` Karthik Nayak
0 siblings, 0 replies; 18+ messages in thread
From: Karthik Nayak @ 2015-07-09 5:52 UTC (permalink / raw)
To: Matthieu Moy; +Cc: Torsten Bögershausen, Git, Christian Couder
On Wed, Jul 8, 2015 at 9:16 PM, Matthieu Moy
<Matthieu.Moy@grenoble-inp.fr> wrote:
> Karthik Nayak <karthik.188@gmail.com> writes:
>
>> On Wed, Jul 8, 2015 at 2:37 PM, Matthieu Moy
>> <Matthieu.Moy@grenoble-inp.fr> wrote:
>>> Torsten Bögershausen <tboegi@web.de> writes:
>>>
>>>> Could we have a tweak for people without gpg?
>>>
>>> I guess we need stg like
>>>
>>> if ! test_have_prereq GPG; then
>>> skip_all='skipping for-each-ref tests, gpg not available'
>>> test_done
>>> fi
>>>
>>> since we need GPG in the setup test and almost all other tests will rely
>>> on it.
>>>
>>
>> Does this need to be there? I see a lot of test files which need GPG, and since
>> this test file contains tests which rely on it, without it, it would
>> be kinda useless
>> anyways?
>
> In many cases, the tests look like
>
> . lib-gpg.sh
>
> test_expect_success 'test that does not use GPG' '
> ...
> '
>
> test_expect_success GPG 'test that does use GPG' '
> ...
> '
>
> so you can't decide in lib-gpg.sh that you'll skip all tests, because
> you would skip some tests that could be ran without gpg.
>
Ah! Thanks. Will reply here with your fix included :)
--
Regards,
Karthik Nayak
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v8 01/11] t6302: for-each-ref tests for ref-filter APIs
2015-07-07 16:06 ` [PATCH v8 01/11] t6302: for-each-ref tests for ref-filter APIs Karthik Nayak
` (10 preceding siblings ...)
2015-07-08 8:09 ` [PATCH v8 01/11] t6302: for-each-ref tests for ref-filter APIs Torsten Bögershausen
@ 2015-07-09 6:03 ` Karthik Nayak
11 siblings, 0 replies; 18+ messages in thread
From: Karthik Nayak @ 2015-07-09 6:03 UTC (permalink / raw)
To: git; +Cc: christian.couder, Matthieu.Moy, 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 | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
create mode 100755 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 100755
index 0000000..ae75116
--- /dev/null
+++ b/t/t6302-for-each-ref-filter.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+test_description='test for-each-refs usage of ref-filter APIs'
+
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-gpg.sh
+
+if ! test_have_prereq GPG
+then
+ skip_all="skipping for-each-ref tests, GPG not available"
+ test_done
+fi
+
+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 tag -s -m "Annonated doubly" double-tag signed-tag &&
+ git checkout master &&
+ git update-ref refs/odd/spot master
+'
+
+test_done
--
2.4.5
^ permalink raw reply related [flat|nested] 18+ messages in thread
end of thread, other threads:[~2015-07-09 6:03 UTC | newest]
Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-07-07 16:05 [PATCH v8 00/11] add options to for-each-ref Karthik Nayak
2015-07-07 16:06 ` [PATCH v8 01/11] t6302: for-each-ref tests for ref-filter APIs Karthik Nayak
2015-07-07 16:06 ` [PATCH v8 02/11] tag: libify parse_opt_points_at() Karthik Nayak
2015-07-07 16:06 ` [PATCH v8 03/11] ref-filter: implement '--points-at' option Karthik Nayak
2015-07-07 16:06 ` [PATCH v8 04/11] for-each-ref: add " Karthik Nayak
2015-07-07 16:06 ` [PATCH v8 05/11] ref-filter: add parse_opt_merge_filter() Karthik Nayak
2015-07-07 16:06 ` [PATCH v8 06/11] ref-filter: implement '--merged' and '--no-merged' options Karthik Nayak
2015-07-07 16:06 ` [PATCH v8 07/11] for-each-ref: add " Karthik Nayak
2015-07-07 16:06 ` [PATCH v8 08/11] parse-option: rename parse_opt_with_commit() Karthik Nayak
2015-07-07 16:06 ` [PATCH v8 09/11] parse-options.h: add macros for '--contains' option Karthik Nayak
2015-07-07 16:06 ` [PATCH v8 10/11] ref-filter: implement " Karthik Nayak
2015-07-07 16:06 ` [PATCH v8 11/11] for-each-ref: add " Karthik Nayak
2015-07-08 8:09 ` [PATCH v8 01/11] t6302: for-each-ref tests for ref-filter APIs Torsten Bögershausen
2015-07-08 9:07 ` Matthieu Moy
2015-07-08 13:59 ` Karthik Nayak
2015-07-08 15:46 ` Matthieu Moy
2015-07-09 5:52 ` Karthik Nayak
2015-07-09 6:03 ` 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).