{"thread":{"id":"39720","subject":"[RFC/PATCH 0/9] port tag.c to use ref-filter library","startedAt":"2015-06-25T09:55:41Z","lastAt":"2015-07-12T13:37:46Z","messageCount":23,"participants":["Karthik Nayak","Christian Couder","Duy Nguyen","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":9},"messages":[{"id":"264826","messageId":"CAOLa=ZSsVqFy4OrSt295qAZdjKTC7z44EVsx3cPEd2jb8Y-sHw@mail.gmail.com","threadId":"39720","inReplyTo":null,"subject":"[RFC/PATCH 0/9] port tag.c to use ref-filter library","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-06-25T09:55:41Z","receivedAt":"2015-06-25T09:55:41Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"This is part of the GSoC project to unify the commands `git tag -l`,\n`git branch -l`\nand `git for-each-ref`.\n\nThis is a follow up to\nhttp://article.gmane.org/gmane.comp.version-control.git/272641 which\nis still in the 6th iteration.\n\nThis ports over tag.c to use ref-filter APIs and adds --format,\n--sort, --merged and --no-merged options to the same.\n\n Documentation/git-tag.txt |  39 ++++++++++---\n builtin/for-each-ref.c    |   3 +-\n builtin/tag.c             | 362\n++++++++++++++++++++------------------------------------------------------------------------------------------------\n ref-filter.c              | 100 ++++++++++++++++++++++++++++----\n ref-filter.h              |   7 ++-\n t/t7004-tag.sh            |  51 ++++++++++++++---\n 6 files changed, 233 insertions(+), 329 deletions(-)\n\n-- \nRegards,\nKarthik Nayak\n"},{"id":"264831","messageId":"1435232596-27466-1-git-send-email-karthik.188@gmail.com","threadId":"39720","inReplyTo":"CAOLa=ZSsVqFy4OrSt295qAZdjKTC7z44EVsx3cPEd2jb8Y-sHw@mail.gmail.com","subject":"[RFC/PATCH 1/9] ref-filter: add %(refname:lalignX) option","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-06-25T11:43:08Z","receivedAt":"2015-06-25T11:43:08Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"Add support for %(refname:lalignX) where X is a number.\nThis will print a shortened refname aligned to the left\nfollowed by spaces for a total length of X characters.\nIf X is less than the shortened refname size, the entire\nshortened refname is printed.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>\nSigned-off-by: Karthik Nayak <karthik.188@gmail.com>\n---\n ref-filter.c | 17 ++++++++++++++++-\n 1 file changed, 16 insertions(+), 1 deletion(-)\n\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 00d06bf..299b048 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -695,7 +695,22 @@ static void populate_value(struct ref_array_item *ref)\n \t\t\tint num_ours, num_theirs;\n \n \t\t\tformatp++;\n-\t\t\tif (!strcmp(formatp, \"short\"))\n+\t\t\tif (starts_with(formatp, \"lalign\")) {\n+\t\t\t\tconst char *valp;\n+\t\t\t\tint val;\n+\n+\t\t\t\tskip_prefix(formatp, \"lalign\", &valp);\n+\t\t\t\tval = atoi(valp);\n+\t\t\t\trefname = shorten_unambiguous_ref(refname,\n+\t\t\t\t\t\t\t\t  warn_ambiguous_refs);\n+\t\t\t\tif (val > strlen(refname)) {\n+\t\t\t\t\tstruct strbuf buf = STRBUF_INIT;\n+\t\t\t\t\tstrbuf_addstr(&buf, refname);\n+\t\t\t\t\tstrbuf_addchars(&buf, ' ', val - strlen(refname));\n+\t\t\t\t\tfree((char *)refname);\n+\t\t\t\t\trefname = strbuf_detach(&buf, NULL);\n+\t\t\t\t}\n+\t\t\t} else if (!strcmp(formatp, \"short\"))\n \t\t\t\trefname = shorten_unambiguous_ref(refname,\n \t\t\t\t\t\t      warn_ambiguous_refs);\n \t\t\telse if (!strcmp(formatp, \"track\") &&\n-- \n2.4.4\n"},{"id":"264833","messageId":"1435232596-27466-2-git-send-email-karthik.188@gmail.com","threadId":"39720","inReplyTo":"1435232596-27466-1-git-send-email-karthik.188@gmail.com","subject":"[RFC/PATCH 2/9] ref-filter: add option to filter only tags","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-06-25T11:43:09Z","receivedAt":"2015-06-25T11:43:09Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"Add an option in 'filter_refs()' to use 'for_each_tag_ref()'\nand filter refs. This type checking is done by adding a\n'FILTER_REFS_TAGS' in 'ref-filter.h'\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>\nSigned-off-by: Karthik Nayak <karthik.188@gmail.com>\n---\n ref-filter.c | 2 ++\n ref-filter.h | 1 +\n 2 files changed, 3 insertions(+)\n\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 299b048..97432d1 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -1141,6 +1141,8 @@ int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int\n \t\tret = for_each_rawref(ref_filter_handler, &ref_cbdata);\n \telse if (type & FILTER_REFS_ALL)\n \t\tret = for_each_ref(ref_filter_handler, &ref_cbdata);\n+\telse if (type & FILTER_REFS_TAGS)\n+\t\tret = for_each_tag_ref(ref_filter_handler, &ref_cbdata);\n \telse if (type)\n \t\tdie(\"filter_refs: invalid type\");\n \ndiff --git a/ref-filter.h b/ref-filter.h\nindex 3c59431..dd28d17 100644\n--- a/ref-filter.h\n+++ b/ref-filter.h\n@@ -15,6 +15,7 @@\n \n #define FILTER_REFS_INCLUDE_BROKEN 0x1\n #define FILTER_REFS_ALL 0x2\n+#define FILTER_REFS_TAGS 0x4\n \n struct atom_value {\n \tconst char *s;\n-- \n2.4.4\n"},{"id":"264832","messageId":"1435232596-27466-3-git-send-email-karthik.188@gmail.com","threadId":"39720","inReplyTo":"1435232596-27466-1-git-send-email-karthik.188@gmail.com","subject":"[RFC/PATCH 3/9] ref-filter: support printing N lines from tag annotation","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-06-25T11:43:10Z","receivedAt":"2015-06-25T11:43:10Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"In 'tag.c' we can print N lines from the annotation of the tag\nusing the '-n<num>' option. Copy code from 'tag.c' to 'ref-filter'\nand modify 'ref-filter' to support printing of N lines from the\nannotation of tags.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>\nSigned-off-by: Karthik Nayak <karthik.188@gmail.com>\n---\n builtin/for-each-ref.c |  2 +-\n builtin/tag.c          |  4 ++++\n ref-filter.c           | 48 +++++++++++++++++++++++++++++++++++++++++++++++-\n ref-filter.h           |  3 ++-\n 4 files changed, 54 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c\nindex 5868c48..c318e33 100644\n--- a/builtin/for-each-ref.c\n+++ b/builtin/for-each-ref.c\n@@ -74,7 +74,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)\n \tif (!maxcount || array.nr < maxcount)\n \t\tmaxcount = array.nr;\n \tfor (i = 0; i < maxcount; i++)\n-\t\tshow_ref_array_item(array.items[i], format, quote_style);\n+\t\tshow_ref_array_item(array.items[i], format, quote_style, 0);\n \tref_array_clear(&array);\n \treturn 0;\n }\ndiff --git a/builtin/tag.c b/builtin/tag.c\nindex 767162e..9f300e0 100644\n--- a/builtin/tag.c\n+++ b/builtin/tag.c\n@@ -180,6 +180,10 @@ static enum contains_result contains(struct commit *candidate,\n \treturn contains_test(candidate, want);\n }\n \n+/*\n+ * Currently dupplicated in ref-filter, will eventually be removed as\n+ * we port tag.c to use ref-filter APIs.\n+ */\n static void show_tag_lines(const struct object_id *oid, int lines)\n {\n \tint i;\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 97432d1..57a5cfb 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -1262,7 +1262,48 @@ static void emit(const char *cp, const char *ep)\n \t}\n }\n \n-void show_ref_array_item(struct ref_array_item *info, const char *format, int quote_style)\n+/* Print 'lines' no of lines of a given oid */\n+static void show_tag_lines(const struct object_id *oid, int lines)\n+{\n+\tint i;\n+\tunsigned long size;\n+\tenum object_type type;\n+\tchar *buf, *sp, *eol;\n+\tsize_t len;\n+\n+\tbuf = read_sha1_file(oid->hash, &type, &size);\n+\tif (!buf)\n+\t\tdie_errno(\"unable to read object %s\", oid_to_hex(oid));\n+\tif (type != OBJ_COMMIT && type != OBJ_TAG)\n+\t\tgoto free_return;\n+\tif (!size)\n+\t\tdie(\"an empty %s object %s?\",\n+\t\t    typename(type), oid_to_hex(oid));\n+\n+\t/* skip header */\n+\tsp = strstr(buf, \"\\n\\n\");\n+\tif (!sp)\n+\t\tgoto free_return;\n+\n+\t/* only take up to \"lines\" lines, and strip the signature from a tag */\n+\tif (type == OBJ_TAG)\n+\t\tsize = parse_signature(buf, size);\n+\tfor (i = 0, sp += 2; i < lines && sp < buf + size; i++) {\n+\t\tif (i)\n+\t\t\tprintf(\"\\n    \");\n+\t\teol = memchr(sp, '\\n', size - (sp - buf));\n+\t\tlen = eol ? eol - sp : size - (sp - buf);\n+\t\tfwrite(sp, len, 1, stdout);\n+\t\tif (!eol)\n+\t\t\tbreak;\n+\t\tsp = eol + 1;\n+\t}\n+free_return:\n+\tfree(buf);\n+}\n+\n+void show_ref_array_item(struct ref_array_item *info, const char *format,\n+\t\t\t int quote_style, unsigned int lines)\n {\n \tconst char *cp, *sp, *ep;\n \n@@ -1288,6 +1329,11 @@ void show_ref_array_item(struct ref_array_item *info, const char *format, int qu\n \t\tresetv.s = color;\n \t\tprint_value(&resetv, quote_style);\n \t}\n+\tif (lines > 0) {\n+\t\tstruct object_id oid;\n+\t\thashcpy(oid.hash, info->objectname);\n+\t\tshow_tag_lines(&oid, lines);\n+\t}\n \tputchar('\\n');\n }\n \ndiff --git a/ref-filter.h b/ref-filter.h\nindex dd28d17..6b6fb96 100644\n--- a/ref-filter.h\n+++ b/ref-filter.h\n@@ -55,6 +55,7 @@ struct ref_filter {\n \tstruct commit *merge_commit;\n \n \tunsigned int with_commit_tag_algo: 1;\n+\tunsigned int lines;\n };\n \n struct ref_filter_cbdata {\n@@ -87,7 +88,7 @@ int verify_ref_format(const char *format);\n /*  Sort the given ref_array as per the ref_sorting provided */\n void ref_array_sort(struct ref_sorting *sort, struct ref_array *array);\n /*  Print the ref using the given format and quote_style */\n-void show_ref_array_item(struct ref_array_item *info, const char *format, int quote_style);\n+void show_ref_array_item(struct ref_array_item *info, const char *format, int quote_style, unsigned int lines);\n /*  Callback function for parsing the sort option */\n int parse_opt_ref_sorting(const struct option *opt, const char *arg, int unset);\n /*  Default sort option based on refname */\n-- \n2.4.4\n"},{"id":"264834","messageId":"1435232596-27466-4-git-send-email-karthik.188@gmail.com","threadId":"39720","inReplyTo":"1435232596-27466-1-git-send-email-karthik.188@gmail.com","subject":"[RFC/PATCH 4/9] ref-filter: add support to sort by version","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-06-25T11:43:11Z","receivedAt":"2015-06-25T11:43:11Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"Add support to sort by version using the \"v:refname\" and\n\"version:refname\" option. This is achieved by using the\n'version_cmp()' function as the comparing function for qsort.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>\nSigned-off-by: Karthik Nayak <karthik.188@gmail.com>\n---\n ref-filter.c | 20 +++++++++++++++++---\n 1 file changed, 17 insertions(+), 3 deletions(-)\n\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 57a5cfb..e307fab 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -10,8 +10,9 @@\n #include \"quote.h\"\n #include \"ref-filter.h\"\n #include \"revision.h\"\n+#include \"version.h\"\n \n-typedef enum { FIELD_STR, FIELD_ULONG, FIELD_TIME } cmp_type;\n+typedef enum { FIELD_STR, FIELD_ULONG, FIELD_TIME, FIELD_VER } cmp_type;\n \n static struct {\n \tconst char *name;\n@@ -53,6 +54,8 @@ static struct {\n \t{ \"flag\" },\n \t{ \"HEAD\" },\n \t{ \"color\" },\n+\t{ \"version\", FIELD_VER },\n+\t{ \"v\", FIELD_VER },\n };\n \n /*\n@@ -629,7 +632,9 @@ static void populate_value(struct ref_array_item *ref)\n \t\t\tname++;\n \t\t}\n \n-\t\tif (starts_with(name, \"refname\"))\n+\t\tif (starts_with(name, \"refname\") ||\n+\t\t    starts_with(name, \"version:\") ||\n+\t\t    starts_with(name, \"v:\"))\n \t\t\trefname = ref->refname;\n \t\telse if (starts_with(name, \"symref\"))\n \t\t\trefname = ref->symref ? ref->symref : \"\";\n@@ -695,7 +700,13 @@ static void populate_value(struct ref_array_item *ref)\n \t\t\tint num_ours, num_theirs;\n \n \t\t\tformatp++;\n-\t\t\tif (starts_with(formatp, \"lalign\")) {\n+\t\t\tif (starts_with(name, \"version\") || starts_with(name, \"v\")) {\n+\t\t\t\tif (strcmp(formatp, \"refname\"))\n+\t\t\t\t\tdie(\"unknown %.*s format %s\",\n+\t\t\t\t\t    (int)(formatp - name), name, formatp);\n+\t\t\t\tv->s = refname;\n+\t\t\t\tcontinue;\n+\t\t\t} else if (starts_with(formatp, \"lalign\")) {\n \t\t\t\tconst char *valp;\n \t\t\t\tint val;\n \n@@ -1165,6 +1176,9 @@ static int cmp_ref_sorting(struct ref_sorting *s, struct ref_array_item *a, stru\n \tcase FIELD_STR:\n \t\tcmp = strcmp(va->s, vb->s);\n \t\tbreak;\n+\tcase FIELD_VER:\n+\t\tcmp = versioncmp(va->s, vb->s);\n+\t\tbreak;\n \tdefault:\n \t\tif (va->ul < vb->ul)\n \t\t\tcmp = -1;\n-- \n2.4.4\n"},{"id":"264835","messageId":"1435232596-27466-5-git-send-email-karthik.188@gmail.com","threadId":"39720","inReplyTo":"1435232596-27466-1-git-send-email-karthik.188@gmail.com","subject":"[RFC/PATCH 5/9] ref-filter: add option to match literal pattern","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-06-25T11:43:12Z","receivedAt":"2015-06-25T11:43:12Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"Since 'ref-filter' only has an option to match path names.\nAdd an option for regular pattern matching.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>\nSigned-off-by: Karthik Nayak <karthik.188@gmail.com>\n---\n builtin/for-each-ref.c |  1 +\n ref-filter.c           | 30 ++++++++++++++++++++++++------\n ref-filter.h           |  3 ++-\n 3 files changed, 27 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c\nindex c318e33..01d5363 100644\n--- a/builtin/for-each-ref.c\n+++ b/builtin/for-each-ref.c\n@@ -68,6 +68,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)\n \tgit_config(git_default_config, NULL);\n \n \tfilter.name_patterns = argv;\n+\tfilter.match_as_path = 1;\n \tfilter_refs(&array, &filter, FILTER_REFS_ALL | FILTER_REFS_INCLUDE_BROKEN);\n \tref_array_sort(sorting, &array);\n \ndiff --git a/ref-filter.c b/ref-filter.c\nindex e307fab..1f97910 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -954,6 +954,20 @@ static int commit_contains(struct ref_filter *filter, struct commit *commit)\n \n /*\n  * Return 1 if the refname matches one of the patterns, otherwise 0.\n+ * A pattern can be a literal prefix (e.g. a refname \"refs/heads/master\"\n+ * matches a pattern \"refs/heads/m\") or a wildcard (e.g. the same ref\n+ * matches \"refs/heads/m*\",too).\n+ */\n+static int match_pattern(const char **patterns, const char *refname)\n+{\n+\tfor (; *patterns; patterns++)\n+\t\tif (!wildmatch(*patterns, refname, 0, NULL))\n+\t\t\treturn 1;\n+\treturn 0;\n+}\n+\n+/*\n+ * Return 1 if the refname matches one of the patterns, otherwise 0.\n  * A pattern can be path prefix (e.g. a refname \"refs/heads/master\"\n  * matches a pattern \"refs/heads/\") or a wildcard (e.g. the same ref\n  * matches \"refs/heads/m*\",too).\n@@ -977,6 +991,15 @@ static int match_name_as_path(const char **pattern, const char *refname)\n \treturn 0;\n }\n \n+static int filter_pattern_match(struct ref_filter *filter, const char *refname)\n+{\n+\tif (!*filter->name_patterns)\n+\t\treturn 0;\n+\tif (filter->match_as_path)\n+\t\treturn match_name_as_path(filter->name_patterns, refname);\n+\treturn match_pattern(filter->name_patterns, refname);\n+}\n+\n /*\n  * Given a ref (sha1, refname) see if it points to one of the sha1s\n  * in a sha1_array.\n@@ -1026,17 +1049,12 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,\n \tstruct ref_array_item *ref;\n \tstruct commit *commit = NULL;\n \n-\tif (flag & REF_BAD_NAME) {\n-\t\t  warning(\"ignoring ref with broken name %s\", refname);\n-\t\t  return 0;\n-\t}\n-\n \tif (flag & REF_ISBROKEN) {\n \t\twarning(\"ignoring broken ref %s\", refname);\n \t\treturn 0;\n \t}\n \n-\tif (*filter->name_patterns && !match_name_as_path(filter->name_patterns, refname))\n+\tif (!filter_pattern_match(filter, refname))\n \t\treturn 0;\n \n \tif (!match_points_at(&filter->points_at, oid->hash, refname))\ndiff --git a/ref-filter.h b/ref-filter.h\nindex 6b6fb96..a4809c8 100644\n--- a/ref-filter.h\n+++ b/ref-filter.h\n@@ -54,7 +54,8 @@ struct ref_filter {\n \t} merge;\n \tstruct commit *merge_commit;\n \n-\tunsigned int with_commit_tag_algo: 1;\n+\tunsigned int with_commit_tag_algo: 1,\n+\t\tmatch_as_path: 1;\n \tunsigned int lines;\n };\n \n-- \n2.4.4\n"},{"id":"264836","messageId":"1435232596-27466-6-git-send-email-karthik.188@gmail.com","threadId":"39720","inReplyTo":"1435232596-27466-1-git-send-email-karthik.188@gmail.com","subject":"[RFC/PATCH 6/9] tag.c: use 'ref-filter' data structures","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-06-25T11:43:13Z","receivedAt":"2015-06-25T11:43:13Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"Make 'tag.c' use 'ref-filter' data structures and make changes to\nsupport the new data structures. This is a part of the process\nof porting 'tag.c' to use 'ref-filter' APIs.\n\nThis is a temporary step before porting 'tag.c' to use 'ref-filter'\ncompletely. As this is a temporary step, most of the code\nintroduced here will be removed when 'tag.c' is ported over to use\n'ref-filter' APIs\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>\nSigned-off-by: Karthik Nayak <karthik.188@gmail.com>\n---\n builtin/tag.c | 106 +++++++++++++++++++++++++++++++---------------------------\n 1 file changed, 57 insertions(+), 49 deletions(-)\n\ndiff --git a/builtin/tag.c b/builtin/tag.c\nindex 9f300e0..65b6707 100644\n--- a/builtin/tag.c\n+++ b/builtin/tag.c\n@@ -17,6 +17,7 @@\n #include \"gpg-interface.h\"\n #include \"sha1-array.h\"\n #include \"column.h\"\n+#include \"ref-filter.h\"\n \n static const char * const git_tag_usage[] = {\n \tN_(\"git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] <tagname> [<head>]\"),\n@@ -34,15 +35,6 @@ static const char * const git_tag_usage[] = {\n \n static int tag_sort;\n \n-struct tag_filter {\n-\tconst char **patterns;\n-\tint lines;\n-\tint sort;\n-\tstruct string_list tags;\n-\tstruct commit_list *with_commit;\n-};\n-\n-static struct sha1_array points_at;\n static unsigned int colopts;\n \n static int match_pattern(const char **patterns, const char *ref)\n@@ -61,19 +53,20 @@ static int match_pattern(const char **patterns, const char *ref)\n  * removed as we port tag.c to use the ref-filter APIs.\n  */\n static const unsigned char *match_points_at(const char *refname,\n-\t\t\t\t\t    const unsigned char *sha1)\n+\t\t\t\t\t    const unsigned char *sha1,\n+\t\t\t\t\t    struct sha1_array *points_at)\n {\n \tconst unsigned char *tagged_sha1 = NULL;\n \tstruct object *obj;\n \n-\tif (sha1_array_lookup(&points_at, sha1) >= 0)\n+\tif (sha1_array_lookup(points_at, sha1) >= 0)\n \t\treturn sha1;\n \tobj = parse_object(sha1);\n \tif (!obj)\n \t\tdie(_(\"malformed object at '%s'\"), refname);\n \tif (obj->type == OBJ_TAG)\n \t\ttagged_sha1 = ((struct tag *)obj)->tagged->sha1;\n-\tif (tagged_sha1 && sha1_array_lookup(&points_at, tagged_sha1) >= 0)\n+\tif (tagged_sha1 && sha1_array_lookup(points_at, tagged_sha1) >= 0)\n \t\treturn tagged_sha1;\n \treturn NULL;\n }\n@@ -223,12 +216,24 @@ free_return:\n \tfree(buf);\n }\n \n+static void ref_array_append(struct ref_array *array, const char *refname)\n+{\n+\tsize_t len = strlen(refname);\n+\tstruct ref_array_item *ref = xcalloc(1, sizeof(struct ref_array_item) + len + 1);\n+\tmemcpy(ref->refname, refname, len);\n+\tref->refname[len] = '\\0';\n+\tREALLOC_ARRAY(array->items, array->nr + 1);\n+\tarray->items[array->nr++] = ref;\n+}\n+\n static int show_reference(const char *refname, const struct object_id *oid,\n \t\t\t  int flag, void *cb_data)\n {\n-\tstruct tag_filter *filter = cb_data;\n+\tstruct ref_filter_cbdata *data = cb_data;\n+\tstruct ref_array *array = data->array;\n+\tstruct ref_filter *filter = data->filter;\n \n-\tif (match_pattern(filter->patterns, refname)) {\n+\tif (match_pattern(filter->name_patterns, refname)) {\n \t\tif (filter->with_commit) {\n \t\t\tstruct commit *commit;\n \n@@ -239,12 +244,12 @@ static int show_reference(const char *refname, const struct object_id *oid,\n \t\t\t\treturn 0;\n \t\t}\n \n-\t\tif (points_at.nr && !match_points_at(refname, oid->hash))\n+\t\tif (filter->points_at.nr && !match_points_at(refname, oid->hash, &filter->points_at))\n \t\t\treturn 0;\n \n \t\tif (!filter->lines) {\n-\t\t\tif (filter->sort)\n-\t\t\t\tstring_list_append(&filter->tags, refname);\n+\t\t\tif (tag_sort)\n+\t\t\t\tref_array_append(array, refname);\n \t\t\telse\n \t\t\t\tprintf(\"%s\\n\", refname);\n \t\t\treturn 0;\n@@ -259,36 +264,36 @@ static int show_reference(const char *refname, const struct object_id *oid,\n \n static int sort_by_version(const void *a_, const void *b_)\n {\n-\tconst struct string_list_item *a = a_;\n-\tconst struct string_list_item *b = b_;\n-\treturn versioncmp(a->string, b->string);\n+\tconst struct ref_array_item *a = *((struct ref_array_item **)a_);\n+\tconst struct ref_array_item *b = *((struct ref_array_item **)b_);\n+\treturn versioncmp(a->refname, b->refname);\n }\n \n-static int list_tags(const char **patterns, int lines,\n-\t\t     struct commit_list *with_commit, int sort)\n+static int list_tags(struct ref_filter *filter, int sort)\n {\n-\tstruct tag_filter filter;\n+\tstruct ref_array array;\n+\tstruct ref_filter_cbdata data;\n+\n+\tmemset(&array, 0, sizeof(array));\n+\tdata.array = &array;\n+\tdata.filter = filter;\n \n-\tfilter.patterns = patterns;\n-\tfilter.lines = lines;\n-\tfilter.sort = sort;\n-\tfilter.with_commit = with_commit;\n-\tmemset(&filter.tags, 0, sizeof(filter.tags));\n-\tfilter.tags.strdup_strings = 1;\n+\tif (filter->lines == -1)\n+\t\tfilter->lines = 0;\n \n-\tfor_each_tag_ref(show_reference, (void *)&filter);\n+\tfor_each_tag_ref(show_reference, &data);\n \tif (sort) {\n \t\tint i;\n \t\tif ((sort & SORT_MASK) == VERCMP_SORT)\n-\t\t\tqsort(filter.tags.items, filter.tags.nr,\n-\t\t\t      sizeof(struct string_list_item), sort_by_version);\n+\t\t\tqsort(array.items, array.nr,\n+\t\t\t      sizeof(struct ref_array_item *), sort_by_version);\n \t\tif (sort & REVERSE_SORT)\n-\t\t\tfor (i = filter.tags.nr - 1; i >= 0; i--)\n-\t\t\t\tprintf(\"%s\\n\", filter.tags.items[i].string);\n+\t\t\tfor (i = array.nr - 1; i >= 0; i--)\n+\t\t\t\tprintf(\"%s\\n\", array.items[i]->refname);\n \t\telse\n-\t\t\tfor (i = 0; i < filter.tags.nr; i++)\n-\t\t\t\tprintf(\"%s\\n\", filter.tags.items[i].string);\n-\t\tstring_list_clear(&filter.tags, 0);\n+\t\t\tfor (i = 0; i < array.nr; i++)\n+\t\t\t\tprintf(\"%s\\n\", array.items[i]->refname);\n+\t\tref_array_clear(&array);\n \t}\n \treturn 0;\n }\n@@ -569,16 +574,16 @@ int cmd_tag(int argc, const char **argv, const char *prefix)\n \tconst char *object_ref, *tag;\n \tstruct create_tag_options opt;\n \tchar *cleanup_arg = NULL;\n-\tint annotate = 0, force = 0, lines = -1;\n+\tint annotate = 0, force = 0;\n \tint cmdmode = 0;\n \tconst char *msgfile = NULL, *keyid = NULL;\n \tstruct msg_arg msg = { 0, STRBUF_INIT };\n-\tstruct commit_list *with_commit = NULL;\n \tstruct ref_transaction *transaction;\n \tstruct strbuf err = STRBUF_INIT;\n+\tstruct ref_filter filter;\n \tstruct option options[] = {\n \t\tOPT_CMDMODE('l', \"list\", &cmdmode, N_(\"list tag names\"), 'l'),\n-\t\t{ OPTION_INTEGER, 'n', NULL, &lines, N_(\"n\"),\n+\t\t{ OPTION_INTEGER, 'n', NULL, &filter.lines, N_(\"n\"),\n \t\t\t\tN_(\"print <n> lines of each tag message\"),\n \t\t\t\tPARSE_OPT_OPTARG, NULL, 1 },\n \t\tOPT_CMDMODE('d', \"delete\", &cmdmode, N_(\"delete tags\"), 'd'),\n@@ -599,14 +604,14 @@ int cmd_tag(int argc, const char **argv, const char *prefix)\n \n \t\tOPT_GROUP(N_(\"Tag listing options\")),\n \t\tOPT_COLUMN(0, \"column\", &colopts, N_(\"show tag list in columns\")),\n-\t\tOPT_CONTAINS(&with_commit, N_(\"print only tags that contain the commit\")),\n-\t\tOPT_WITH(&with_commit, N_(\"print only tags that contain the commit\")),\n+\t\tOPT_CONTAINS(&filter.with_commit, N_(\"print only tags that contain the commit\")),\n+\t\tOPT_WITH(&filter.with_commit, N_(\"print only tags that contain the commit\")),\n \t\t{\n \t\t\tOPTION_CALLBACK, 0, \"sort\", &tag_sort, N_(\"type\"), N_(\"sort tags\"),\n \t\t\tPARSE_OPT_NONEG, parse_opt_sort\n \t\t},\n \t\t{\n-\t\t\tOPTION_CALLBACK, 0, \"points-at\", &points_at, N_(\"object\"),\n+\t\t\tOPTION_CALLBACK, 0, \"points-at\", &filter.points_at, N_(\"object\"),\n \t\t\tN_(\"print only tags of the object\"), 0, parse_opt_object_name\n \t\t},\n \t\tOPT_END()\n@@ -615,6 +620,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix)\n \tgit_config(git_tag_config, NULL);\n \n \tmemset(&opt, 0, sizeof(opt));\n+\tmemset(&filter, 0, sizeof(filter));\n+\tfilter.lines = -1;\n \n \targc = parse_options(argc, argv, prefix, options, git_tag_usage, 0);\n \n@@ -631,7 +638,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)\n \t\tusage_with_options(git_tag_usage, options);\n \n \tfinalize_colopts(&colopts, -1);\n-\tif (cmdmode == 'l' && lines != -1) {\n+\tif (cmdmode == 'l' && filter.lines != -1) {\n \t\tif (explicitly_enable_column(colopts))\n \t\t\tdie(_(\"--column and -n are incompatible\"));\n \t\tcolopts = 0;\n@@ -644,18 +651,19 @@ int cmd_tag(int argc, const char **argv, const char *prefix)\n \t\t\tcopts.padding = 2;\n \t\t\trun_column_filter(colopts, &copts);\n \t\t}\n-\t\tif (lines != -1 && tag_sort)\n+\t\tif (filter.lines != -1 && tag_sort)\n \t\t\tdie(_(\"--sort and -n are incompatible\"));\n-\t\tret = list_tags(argv, lines == -1 ? 0 : lines, with_commit, tag_sort);\n+\t\tfilter.name_patterns = argv;\n+\t\tret = list_tags(&filter, tag_sort);\n \t\tif (column_active(colopts))\n \t\t\tstop_column_filter();\n \t\treturn ret;\n \t}\n-\tif (lines != -1)\n+\tif (filter.lines != -1)\n \t\tdie(_(\"-n option is only allowed with -l.\"));\n-\tif (with_commit)\n+\tif (filter.with_commit)\n \t\tdie(_(\"--contains option is only allowed with -l.\"));\n-\tif (points_at.nr)\n+\tif (filter.points_at.nr)\n \t\tdie(_(\"--points-at option is only allowed with -l.\"));\n \tif (cmdmode == 'd')\n \t\treturn for_each_tag_name(argv, delete_tag);\n-- \n2.4.4\n"},{"id":"264838","messageId":"1435232596-27466-7-git-send-email-karthik.188@gmail.com","threadId":"39720","inReplyTo":"1435232596-27466-1-git-send-email-karthik.188@gmail.com","subject":"[RFC/PATCH 7/9] tag.c: use 'ref-filter' APIs","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-06-25T11:43:14Z","receivedAt":"2015-06-25T11:43:14Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"Make 'tag.c' use 'ref-filter' APIs for iterating through refs\nsorting and printing of refs. This removes most of the code\nused in 'tag.c' replacing it with calls to the 'ref-filter'\nlibrary.\n\nMake 'tag.c' use the 'filter_refs()' function provided by\n'ref-filter' to filter out tags based on the options set.\n\nFor printing tags we use 'show_ref_array_item()' function\nprovided by 'ref-filter'.\n\nWe improve the sorting option provided by 'tag.c' by using the\nsorting options provided by 'ref-filter'. This causes the test\n'invalid sort parameter on command line' in t7004 to fail, as\n'ref-filter' throws an error for all sorting fields which are\nincorrect. The test is changed to reflect the same.\n\nModify documentation for the same.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>\nSigned-off-by: Karthik Nayak <karthik.188@gmail.com>\n---\n Documentation/git-tag.txt |  16 ++-\n builtin/tag.c             | 337 ++++++----------------------------------------\n t/t7004-tag.sh            |   8 +-\n 3 files changed, 49 insertions(+), 312 deletions(-)\n\ndiff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt\nindex 034d10d..1950d94 100644\n--- a/Documentation/git-tag.txt\n+++ b/Documentation/git-tag.txt\n@@ -13,7 +13,7 @@ SYNOPSIS\n \t<tagname> [<commit> | <object>]\n 'git tag' -d <tagname>...\n 'git tag' [-n[<num>]] -l [--contains <commit>] [--points-at <object>]\n-\t[--column[=<options>] | --no-column] [<pattern>...]\n+\t[--column[=<options>] | --no-column] [--sort=<key>] [<pattern>...]\n \t[<pattern>...]\n 'git tag' -v <tagname>...\n \n@@ -95,14 +95,16 @@ OPTIONS\n \tusing fnmatch(3)).  Multiple patterns may be given; if any of\n \tthem matches, the tag is shown.\n \n---sort=<type>::\n-\tSort in a specific order. Supported type is \"refname\"\n-\t(lexicographic order), \"version:refname\" or \"v:refname\" (tag\n+--sort=<key>::\n+\tSort based on the key given.  Prefix `-` to sort in\n+\tdescending order of the value. You may use the --sort=<key> option\n+\tmultiple times, in which case the last key becomes the primary\n+\tkey. Also supports \"version:refname\" or \"v:refname\" (tag\n \tnames are treated as versions). The \"version:refname\" sort\n \torder can also be affected by the\n-\t\"versionsort.prereleaseSuffix\" configuration variable. Prepend\n-\t\"-\" to reverse sort order. When this option is not given, the\n-\tsort order defaults to the value configured for the 'tag.sort'\n+\t\"versionsort.prereleaseSuffix\" configuration variable.\n+\tThe keys supported are the same as those in `git for-each-ref`.\n+\tSort order defaults to the value configured for the 'tag.sort'\n \tvariable if it exists, or lexicographic order otherwise. See\n \tlinkgit:git-config[1].\n \ndiff --git a/builtin/tag.c b/builtin/tag.c\nindex 65b6707..d80120e 100644\n--- a/builtin/tag.c\n+++ b/builtin/tag.c\n@@ -28,273 +28,34 @@ static const char * const git_tag_usage[] = {\n \tNULL\n };\n \n-#define STRCMP_SORT     0\t/* must be zero */\n-#define VERCMP_SORT     1\n-#define SORT_MASK       0x7fff\n-#define REVERSE_SORT    0x8000\n-\n-static int tag_sort;\n-\n static unsigned int colopts;\n \n-static int match_pattern(const char **patterns, const char *ref)\n-{\n-\t/* no pattern means match everything */\n-\tif (!*patterns)\n-\t\treturn 1;\n-\tfor (; *patterns; patterns++)\n-\t\tif (!wildmatch(*patterns, ref, 0, NULL))\n-\t\t\treturn 1;\n-\treturn 0;\n-}\n-\n-/*\n- * This is currently duplicated in ref-filter.c, and will eventually be\n- * removed as we port tag.c to use the ref-filter APIs.\n- */\n-static const unsigned char *match_points_at(const char *refname,\n-\t\t\t\t\t    const unsigned char *sha1,\n-\t\t\t\t\t    struct sha1_array *points_at)\n-{\n-\tconst unsigned char *tagged_sha1 = NULL;\n-\tstruct object *obj;\n-\n-\tif (sha1_array_lookup(points_at, sha1) >= 0)\n-\t\treturn sha1;\n-\tobj = parse_object(sha1);\n-\tif (!obj)\n-\t\tdie(_(\"malformed object at '%s'\"), refname);\n-\tif (obj->type == OBJ_TAG)\n-\t\ttagged_sha1 = ((struct tag *)obj)->tagged->sha1;\n-\tif (tagged_sha1 && sha1_array_lookup(points_at, tagged_sha1) >= 0)\n-\t\treturn tagged_sha1;\n-\treturn NULL;\n-}\n-\n-static int in_commit_list(const struct commit_list *want, struct commit *c)\n-{\n-\tfor (; want; want = want->next)\n-\t\tif (!hashcmp(want->item->object.sha1, c->object.sha1))\n-\t\t\treturn 1;\n-\treturn 0;\n-}\n-\n-enum contains_result {\n-\tCONTAINS_UNKNOWN = -1,\n-\tCONTAINS_NO = 0,\n-\tCONTAINS_YES = 1\n-};\n-\n-/*\n- * Test whether the candidate or one of its parents is contained in the list.\n- * Do not recurse to find out, though, but return -1 if inconclusive.\n- */\n-static enum contains_result contains_test(struct commit *candidate,\n-\t\t\t    const struct commit_list *want)\n-{\n-\t/* was it previously marked as containing a want commit? */\n-\tif (candidate->object.flags & TMP_MARK)\n-\t\treturn 1;\n-\t/* or marked as not possibly containing a want commit? */\n-\tif (candidate->object.flags & UNINTERESTING)\n-\t\treturn 0;\n-\t/* or are we it? */\n-\tif (in_commit_list(want, candidate)) {\n-\t\tcandidate->object.flags |= TMP_MARK;\n-\t\treturn 1;\n-\t}\n-\n-\tif (parse_commit(candidate) < 0)\n-\t\treturn 0;\n-\n-\treturn -1;\n-}\n-\n-/*\n- * Mimicking the real stack, this stack lives on the heap, avoiding stack\n- * overflows.\n- *\n- * At each recursion step, the stack items points to the commits whose\n- * ancestors are to be inspected.\n- */\n-struct stack {\n-\tint nr, alloc;\n-\tstruct stack_entry {\n-\t\tstruct commit *commit;\n-\t\tstruct commit_list *parents;\n-\t} *stack;\n-};\n-\n-static void push_to_stack(struct commit *candidate, struct stack *stack)\n-{\n-\tint index = stack->nr++;\n-\tALLOC_GROW(stack->stack, stack->nr, stack->alloc);\n-\tstack->stack[index].commit = candidate;\n-\tstack->stack[index].parents = candidate->parents;\n-}\n-\n-static enum contains_result contains(struct commit *candidate,\n-\t\tconst struct commit_list *want)\n-{\n-\tstruct stack stack = { 0, 0, NULL };\n-\tint result = contains_test(candidate, want);\n-\n-\tif (result != CONTAINS_UNKNOWN)\n-\t\treturn result;\n-\n-\tpush_to_stack(candidate, &stack);\n-\twhile (stack.nr) {\n-\t\tstruct stack_entry *entry = &stack.stack[stack.nr - 1];\n-\t\tstruct commit *commit = entry->commit;\n-\t\tstruct commit_list *parents = entry->parents;\n-\n-\t\tif (!parents) {\n-\t\t\tcommit->object.flags |= UNINTERESTING;\n-\t\t\tstack.nr--;\n-\t\t}\n-\t\t/*\n-\t\t * If we just popped the stack, parents->item has been marked,\n-\t\t * therefore contains_test will return a meaningful 0 or 1.\n-\t\t */\n-\t\telse switch (contains_test(parents->item, want)) {\n-\t\tcase CONTAINS_YES:\n-\t\t\tcommit->object.flags |= TMP_MARK;\n-\t\t\tstack.nr--;\n-\t\t\tbreak;\n-\t\tcase CONTAINS_NO:\n-\t\t\tentry->parents = parents->next;\n-\t\t\tbreak;\n-\t\tcase CONTAINS_UNKNOWN:\n-\t\t\tpush_to_stack(parents->item, &stack);\n-\t\t\tbreak;\n-\t\t}\n-\t}\n-\tfree(stack.stack);\n-\treturn contains_test(candidate, want);\n-}\n-\n-/*\n- * Currently dupplicated in ref-filter, will eventually be removed as\n- * we port tag.c to use ref-filter APIs.\n- */\n-static void show_tag_lines(const struct object_id *oid, int lines)\n-{\n-\tint i;\n-\tunsigned long size;\n-\tenum object_type type;\n-\tchar *buf, *sp, *eol;\n-\tsize_t len;\n-\n-\tbuf = read_sha1_file(oid->hash, &type, &size);\n-\tif (!buf)\n-\t\tdie_errno(\"unable to read object %s\", oid_to_hex(oid));\n-\tif (type != OBJ_COMMIT && type != OBJ_TAG)\n-\t\tgoto free_return;\n-\tif (!size)\n-\t\tdie(\"an empty %s object %s?\",\n-\t\t    typename(type), oid_to_hex(oid));\n-\n-\t/* skip header */\n-\tsp = strstr(buf, \"\\n\\n\");\n-\tif (!sp)\n-\t\tgoto free_return;\n-\n-\t/* only take up to \"lines\" lines, and strip the signature from a tag */\n-\tif (type == OBJ_TAG)\n-\t\tsize = parse_signature(buf, size);\n-\tfor (i = 0, sp += 2; i < lines && sp < buf + size; i++) {\n-\t\tif (i)\n-\t\t\tprintf(\"\\n    \");\n-\t\teol = memchr(sp, '\\n', size - (sp - buf));\n-\t\tlen = eol ? eol - sp : size - (sp - buf);\n-\t\tfwrite(sp, len, 1, stdout);\n-\t\tif (!eol)\n-\t\t\tbreak;\n-\t\tsp = eol + 1;\n-\t}\n-free_return:\n-\tfree(buf);\n-}\n-\n-static void ref_array_append(struct ref_array *array, const char *refname)\n-{\n-\tsize_t len = strlen(refname);\n-\tstruct ref_array_item *ref = xcalloc(1, sizeof(struct ref_array_item) + len + 1);\n-\tmemcpy(ref->refname, refname, len);\n-\tref->refname[len] = '\\0';\n-\tREALLOC_ARRAY(array->items, array->nr + 1);\n-\tarray->items[array->nr++] = ref;\n-}\n-\n-static int show_reference(const char *refname, const struct object_id *oid,\n-\t\t\t  int flag, void *cb_data)\n-{\n-\tstruct ref_filter_cbdata *data = cb_data;\n-\tstruct ref_array *array = data->array;\n-\tstruct ref_filter *filter = data->filter;\n-\n-\tif (match_pattern(filter->name_patterns, refname)) {\n-\t\tif (filter->with_commit) {\n-\t\t\tstruct commit *commit;\n-\n-\t\t\tcommit = lookup_commit_reference_gently(oid->hash, 1);\n-\t\t\tif (!commit)\n-\t\t\t\treturn 0;\n-\t\t\tif (!contains(commit, filter->with_commit))\n-\t\t\t\treturn 0;\n-\t\t}\n-\n-\t\tif (filter->points_at.nr && !match_points_at(refname, oid->hash, &filter->points_at))\n-\t\t\treturn 0;\n-\n-\t\tif (!filter->lines) {\n-\t\t\tif (tag_sort)\n-\t\t\t\tref_array_append(array, refname);\n-\t\t\telse\n-\t\t\t\tprintf(\"%s\\n\", refname);\n-\t\t\treturn 0;\n-\t\t}\n-\t\tprintf(\"%-15s \", refname);\n-\t\tshow_tag_lines(oid, filter->lines);\n-\t\tputchar('\\n');\n-\t}\n-\n-\treturn 0;\n-}\n-\n-static int sort_by_version(const void *a_, const void *b_)\n-{\n-\tconst struct ref_array_item *a = *((struct ref_array_item **)a_);\n-\tconst struct ref_array_item *b = *((struct ref_array_item **)b_);\n-\treturn versioncmp(a->refname, b->refname);\n-}\n-\n-static int list_tags(struct ref_filter *filter, int sort)\n+static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting)\n {\n \tstruct ref_array array;\n-\tstruct ref_filter_cbdata data;\n+\tchar *format;\n+\tint i;\n \n \tmemset(&array, 0, sizeof(array));\n-\tdata.array = &array;\n-\tdata.filter = filter;\n \n \tif (filter->lines == -1)\n \t\tfilter->lines = 0;\n \n-\tfor_each_tag_ref(show_reference, &data);\n-\tif (sort) {\n-\t\tint i;\n-\t\tif ((sort & SORT_MASK) == VERCMP_SORT)\n-\t\t\tqsort(array.items, array.nr,\n-\t\t\t      sizeof(struct ref_array_item *), sort_by_version);\n-\t\tif (sort & REVERSE_SORT)\n-\t\t\tfor (i = array.nr - 1; i >= 0; i--)\n-\t\t\t\tprintf(\"%s\\n\", array.items[i]->refname);\n-\t\telse\n-\t\t\tfor (i = 0; i < array.nr; i++)\n-\t\t\t\tprintf(\"%s\\n\", array.items[i]->refname);\n-\t\tref_array_clear(&array);\n-\t}\n+\tif (filter->lines)\n+\t\tformat = \"%(refname:lalign16)\";\n+\telse\n+\t\tformat = \"%(refname:short)\";\n+\n+\tverify_ref_format(format);\n+\tif (!sorting)\n+\t\tsorting = ref_default_sorting();\n+\tfilter_refs(&array, filter, FILTER_REFS_TAGS);\n+\tref_array_sort(sorting, &array);\n+\n+\tfor (i = 0; i < array.nr; i++)\n+\t\tshow_ref_array_item(array.items[i], format, QUOTE_NONE, filter->lines);\n+\tref_array_clear(&array);\n+\n \treturn 0;\n }\n \n@@ -361,35 +122,22 @@ static const char tag_template_nocleanup[] =\n \t\"Lines starting with '%c' will be kept; you may remove them\"\n \t\" yourself if you want to.\\n\");\n \n-/*\n- * Parse a sort string, and return 0 if parsed successfully. Will return\n- * non-zero when the sort string does not parse into a known type. If var is\n- * given, the error message becomes a warning and includes information about\n- * the configuration value.\n- */\n-static int parse_sort_string(const char *var, const char *arg, int *sort)\n+/* Parse arg given and add it the ref_sorting array */\n+static int parse_sorting_string(const char *arg, struct ref_sorting **sorting_tail)\n {\n-\tint type = 0, flags = 0;\n-\n-\tif (skip_prefix(arg, \"-\", &arg))\n-\t\tflags |= REVERSE_SORT;\n+\tstruct ref_sorting *s;\n+\tint len;\n \n-\tif (skip_prefix(arg, \"version:\", &arg) || skip_prefix(arg, \"v:\", &arg))\n-\t\ttype = VERCMP_SORT;\n-\telse\n-\t\ttype = STRCMP_SORT;\n+\ts = xcalloc(1, sizeof(*s));\n+\ts->next = *sorting_tail;\n+\t*sorting_tail = s;\n \n-\tif (strcmp(arg, \"refname\")) {\n-\t\tif (!var)\n-\t\t\treturn error(_(\"unsupported sort specification '%s'\"), arg);\n-\t\telse {\n-\t\t\twarning(_(\"unsupported sort specification '%s' in variable '%s'\"),\n-\t\t\t\tvar, arg);\n-\t\t\treturn -1;\n-\t\t}\n+\tif (*arg == '-') {\n+\t\ts->reverse = 1;\n+\t\targ++;\n \t}\n-\n-\t*sort = (type | flags);\n+\tlen = strlen(arg);\n+\ts->atom = parse_ref_filter_atom(arg, arg+len);\n \n \treturn 0;\n }\n@@ -397,11 +145,12 @@ static int parse_sort_string(const char *var, const char *arg, int *sort)\n static int git_tag_config(const char *var, const char *value, void *cb)\n {\n \tint status;\n+\tstruct ref_sorting **sorting_tail = (struct ref_sorting **)cb;\n \n \tif (!strcmp(var, \"tag.sort\")) {\n \t\tif (!value)\n \t\t\treturn config_error_nonbool(var);\n-\t\tparse_sort_string(var, value, &tag_sort);\n+\t\tparse_sorting_string(value, sorting_tail);\n \t\treturn 0;\n \t}\n \n@@ -559,13 +308,6 @@ static int strbuf_check_tag_ref(struct strbuf *sb, const char *name)\n \treturn check_refname_format(sb->buf, 0);\n }\n \n-static int parse_opt_sort(const struct option *opt, const char *arg, int unset)\n-{\n-\tint *sort = opt->value;\n-\n-\treturn parse_sort_string(NULL, arg, sort);\n-}\n-\n int cmd_tag(int argc, const char **argv, const char *prefix)\n {\n \tstruct strbuf buf = STRBUF_INIT;\n@@ -581,6 +323,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)\n \tstruct ref_transaction *transaction;\n \tstruct strbuf err = STRBUF_INIT;\n \tstruct ref_filter filter;\n+\tstatic struct ref_sorting *sorting = NULL, **sorting_tail = &sorting;\n \tstruct option options[] = {\n \t\tOPT_CMDMODE('l', \"list\", &cmdmode, N_(\"list tag names\"), 'l'),\n \t\t{ OPTION_INTEGER, 'n', NULL, &filter.lines, N_(\"n\"),\n@@ -606,10 +349,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix)\n \t\tOPT_COLUMN(0, \"column\", &colopts, N_(\"show tag list in columns\")),\n \t\tOPT_CONTAINS(&filter.with_commit, N_(\"print only tags that contain the commit\")),\n \t\tOPT_WITH(&filter.with_commit, N_(\"print only tags that contain the commit\")),\n-\t\t{\n-\t\t\tOPTION_CALLBACK, 0, \"sort\", &tag_sort, N_(\"type\"), N_(\"sort tags\"),\n-\t\t\tPARSE_OPT_NONEG, parse_opt_sort\n-\t\t},\n+\t\tOPT_CALLBACK(0 , \"sort\", sorting_tail, N_(\"key\"),\n+\t\t\t     N_(\"field name to sort on\"), &parse_opt_ref_sorting),\n \t\t{\n \t\t\tOPTION_CALLBACK, 0, \"points-at\", &filter.points_at, N_(\"object\"),\n \t\t\tN_(\"print only tags of the object\"), 0, parse_opt_object_name\n@@ -617,7 +358,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)\n \t\tOPT_END()\n \t};\n \n-\tgit_config(git_tag_config, NULL);\n+\tgit_config(git_tag_config, sorting_tail);\n \n \tmemset(&opt, 0, sizeof(opt));\n \tmemset(&filter, 0, sizeof(filter));\n@@ -643,6 +384,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix)\n \t\t\tdie(_(\"--column and -n are incompatible\"));\n \t\tcolopts = 0;\n \t}\n+\tif (!sorting)\n+\t\tsorting = ref_default_sorting();\n \tif (cmdmode == 'l') {\n \t\tint ret;\n \t\tif (column_active(colopts)) {\n@@ -651,10 +394,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix)\n \t\t\tcopts.padding = 2;\n \t\t\trun_column_filter(colopts, &copts);\n \t\t}\n-\t\tif (filter.lines != -1 && tag_sort)\n-\t\t\tdie(_(\"--sort and -n are incompatible\"));\n \t\tfilter.name_patterns = argv;\n-\t\tret = list_tags(&filter, tag_sort);\n+\t\tret = list_tags(&filter, sorting);\n \t\tif (column_active(colopts))\n \t\t\tstop_column_filter();\n \t\treturn ret;\ndiff --git a/t/t7004-tag.sh b/t/t7004-tag.sh\nindex d1ff5c9..51a233f 100755\n--- a/t/t7004-tag.sh\n+++ b/t/t7004-tag.sh\n@@ -1450,13 +1450,7 @@ test_expect_success 'invalid sort parameter on command line' '\n \n test_expect_success 'invalid sort parameter in configuratoin' '\n \tgit config tag.sort \"v:notvalid\" &&\n-\tgit tag -l \"foo*\" >actual &&\n-\tcat >expect <<-\\EOF &&\n-\tfoo1.10\n-\tfoo1.3\n-\tfoo1.6\n-\tEOF\n-\ttest_cmp expect actual\n+\ttest_must_fail git tag -l \"foo*\" >actual\n '\n \n test_expect_success 'version sort with prerelease reordering' '\n-- \n2.4.4\n"},{"id":"264837","messageId":"1435232596-27466-8-git-send-email-karthik.188@gmail.com","threadId":"39720","inReplyTo":"1435232596-27466-1-git-send-email-karthik.188@gmail.com","subject":"[RFC/PATCH 8/9] tag.c: implement '--format' option","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-06-25T11:43:15Z","receivedAt":"2015-06-25T11:43:15Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"Implement the '--format' option provided by 'ref-filter'.\nThis lets the user list tags as per desired format similar\nto the implementation in 'git for-each-ref'.\n\nAdd tests and documentation for the same.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>\nSigned-off-by: Karthik Nayak <karthik.188@gmail.com>\n---\n Documentation/git-tag.txt | 15 ++++++++++++++-\n builtin/tag.c             | 14 ++++++++++----\n t/t7004-tag.sh            | 16 ++++++++++++++++\n 3 files changed, 40 insertions(+), 5 deletions(-)\n\ndiff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt\nindex 1950d94..16e396c 100644\n--- a/Documentation/git-tag.txt\n+++ b/Documentation/git-tag.txt\n@@ -13,7 +13,7 @@ SYNOPSIS\n \t<tagname> [<commit> | <object>]\n 'git tag' -d <tagname>...\n 'git tag' [-n[<num>]] -l [--contains <commit>] [--points-at <object>]\n-\t[--column[=<options>] | --no-column] [--sort=<key>] [<pattern>...]\n+\t[--column[=<options>] | --no-column] [--sort=<key>] [--format=<format>]\n \t[<pattern>...]\n 'git tag' -v <tagname>...\n \n@@ -156,6 +156,19 @@ This option is only applicable when listing tags without annotation lines.\n \tThe object that the new tag will refer to, usually a commit.\n \tDefaults to HEAD.\n \n+<format>::\n+\tA string that interpolates `%(fieldname)` from the\n+\tobject pointed at by a ref being shown.  If `fieldname`\n+\tis prefixed with an asterisk (`*`) and the ref points\n+\tat a tag object, the value for the field in the object\n+\ttag refers is used.  When unspecified, defaults to\n+\t`%(objectname) SPC %(objecttype) TAB %(refname)`.\n+\tIt also interpolates `%%` to `%`, and `%xx` where `xx`\n+\tare hex digits interpolates to character with hex code\n+\t`xx`; for example `%00` interpolates to `\\0` (NUL),\n+\t`%09` to `\\t` (TAB) and `%0a` to `\\n` (LF).\n+\tThe fields are same as those in `git for-each-ref`.\n+\n \n CONFIGURATION\n -------------\ndiff --git a/builtin/tag.c b/builtin/tag.c\nindex d80120e..91356c9 100644\n--- a/builtin/tag.c\n+++ b/builtin/tag.c\n@@ -30,12 +30,14 @@ static const char * const git_tag_usage[] = {\n \n static unsigned int colopts;\n \n-static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting)\n+static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting, const char *format)\n {\n \tstruct ref_array array;\n-\tchar *format;\n \tint i;\n \n+\tif (!format)\n+\t\tcheck_format = 1;\n+\n \tmemset(&array, 0, sizeof(array));\n \n \tif (filter->lines == -1)\n@@ -43,7 +45,7 @@ static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting)\n \n \tif (filter->lines)\n \t\tformat = \"%(refname:lalign16)\";\n-\telse\n+\telse if (!format)\n \t\tformat = \"%(refname:short)\";\n \n \tverify_ref_format(format);\n@@ -324,6 +326,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)\n \tstruct strbuf err = STRBUF_INIT;\n \tstruct ref_filter filter;\n \tstatic struct ref_sorting *sorting = NULL, **sorting_tail = &sorting;\n+\tconst char *format = NULL;\n \tstruct option options[] = {\n \t\tOPT_CMDMODE('l', \"list\", &cmdmode, N_(\"list tag names\"), 'l'),\n \t\t{ OPTION_INTEGER, 'n', NULL, &filter.lines, N_(\"n\"),\n@@ -355,6 +358,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)\n \t\t\tOPTION_CALLBACK, 0, \"points-at\", &filter.points_at, N_(\"object\"),\n \t\t\tN_(\"print only tags of the object\"), 0, parse_opt_object_name\n \t\t},\n+\t\tOPT_STRING(  0 , \"format\", &format, N_(\"format\"), N_(\"format to use for the output\")),\n \t\tOPT_END()\n \t};\n \n@@ -394,8 +398,10 @@ int cmd_tag(int argc, const char **argv, const char *prefix)\n \t\t\tcopts.padding = 2;\n \t\t\trun_column_filter(colopts, &copts);\n \t\t}\n+\t\tif (format && (filter.lines != -1))\n+\t\t\tdie(_(\"--format and -n are incompatible\"));\n \t\tfilter.name_patterns = argv;\n-\t\tret = list_tags(&filter, sorting);\n+\t\tret = list_tags(&filter, sorting, format);\n \t\tif (column_active(colopts))\n \t\t\tstop_column_filter();\n \t\treturn ret;\ndiff --git a/t/t7004-tag.sh b/t/t7004-tag.sh\nindex 51a233f..e8cebb6 100755\n--- a/t/t7004-tag.sh\n+++ b/t/t7004-tag.sh\n@@ -1507,4 +1507,20 @@ EOF\"\n \ttest_cmp expect actual\n '\n \n+test_expect_success '--format cannot be used with -n' '\n+\ttest_must_fail git tag -l -n4 --format=\"%(refname)\"\n+'\n+\n+test_expect_success '--format should list tags as per format given' '\n+\tcat >expect <<-\\EOF &&\n+\tfoo1.10\n+\tfoo1.3\n+\tfoo1.6\n+\tfoo1.6-rc1\n+\tfoo1.6-rc2\n+\tEOF\n+\tgit tag -l --format=\"%(refname)\" \"foo*\" >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\n-- \n2.4.4\n"},{"id":"264839","messageId":"1435232596-27466-9-git-send-email-karthik.188@gmail.com","threadId":"39720","inReplyTo":"1435232596-27466-1-git-send-email-karthik.188@gmail.com","subject":"[RFC/PATCH 9/9] tag.c: implement '--merged' and '--no-merged' options","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-06-25T11:43:16Z","receivedAt":"2015-06-25T11:43:16Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"Using 'ref-filter' APIs implement the '--merged' and '--no-merged'\noptions into 'tag.c'. The '--merged' option lets the user to only\nlist tags merged into the named commit. The '--no-merged' option\nlets the user to only list tags not merged into the named commit.\nIf no object is provided it assumes HEAD as the object.\n\nAdd documentation and tests for the same.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>\nSigned-off-by: Karthik Nayak <karthik.188@gmail.com>\n---\n Documentation/git-tag.txt | 10 +++++++++-\n builtin/tag.c             |  9 +++++----\n t/t7004-tag.sh            | 27 +++++++++++++++++++++++++++\n 3 files changed, 41 insertions(+), 5 deletions(-)\n\ndiff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt\nindex 16e396c..74ed157 100644\n--- a/Documentation/git-tag.txt\n+++ b/Documentation/git-tag.txt\n@@ -14,7 +14,7 @@ SYNOPSIS\n 'git tag' -d <tagname>...\n 'git tag' [-n[<num>]] -l [--contains <commit>] [--points-at <object>]\n \t[--column[=<options>] | --no-column] [--sort=<key>] [--format=<format>]\n-\t[<pattern>...]\n+\t[(--merged | --no-merged) [<commit>]] [<pattern>...]\n 'git tag' -v <tagname>...\n \n DESCRIPTION\n@@ -169,6 +169,14 @@ This option is only applicable when listing tags without annotation lines.\n \t`%09` to `\\t` (TAB) and `%0a` to `\\n` (LF).\n \tThe fields are same as those in `git for-each-ref`.\n \n+--merged [<commit>]::\n+\tOnly list tags whose tips are reachable from the\n+\tspecified commit (HEAD if not specified).\n+\n+--no-merged [<commit>]::\n+\tOnly list tags whose tips are not reachable from the\n+\tspecified commit (HEAD if not specified).\n+\n \n CONFIGURATION\n -------------\ndiff --git a/builtin/tag.c b/builtin/tag.c\nindex 91356c9..9a1f7a5 100644\n--- a/builtin/tag.c\n+++ b/builtin/tag.c\n@@ -23,7 +23,7 @@ static const char * const git_tag_usage[] = {\n \tN_(\"git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] <tagname> [<head>]\"),\n \tN_(\"git tag -d <tagname>...\"),\n \tN_(\"git tag -l [-n[<num>]] [--contains <commit>] [--points-at <object>]\"\n-\t\t\"\\n\\t\\t[<pattern>...]\"),\n+\t\t\"\\n\\t\\t[--merged [<commit>]] [--no-merged [<commit>]] [<pattern>...]\"),\n \tN_(\"git tag -v <tagname>...\"),\n \tNULL\n };\n@@ -35,9 +35,6 @@ static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting, con\n \tstruct ref_array array;\n \tint i;\n \n-\tif (!format)\n-\t\tcheck_format = 1;\n-\n \tmemset(&array, 0, sizeof(array));\n \n \tif (filter->lines == -1)\n@@ -352,6 +349,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix)\n \t\tOPT_COLUMN(0, \"column\", &colopts, N_(\"show tag list in columns\")),\n \t\tOPT_CONTAINS(&filter.with_commit, N_(\"print only tags that contain the commit\")),\n \t\tOPT_WITH(&filter.with_commit, N_(\"print only tags that contain the commit\")),\n+\t\tOPT_MERGED(&filter, N_(\"print only tags that are merged\")),\n+\t\tOPT_NO_MERGED(&filter, N_(\"print only tags that are not merged\")),\n \t\tOPT_CALLBACK(0 , \"sort\", sorting_tail, N_(\"key\"),\n \t\t\t     N_(\"field name to sort on\"), &parse_opt_ref_sorting),\n \t\t{\n@@ -412,6 +411,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix)\n \t\tdie(_(\"--contains option is only allowed with -l.\"));\n \tif (filter.points_at.nr)\n \t\tdie(_(\"--points-at option is only allowed with -l.\"));\n+\tif (filter.merge_commit)\n+\t\tdie(_(\"--merged and --no-merged option are only allowed with -l\"));\n \tif (cmdmode == 'd')\n \t\treturn for_each_tag_name(argv, delete_tag);\n \tif (cmdmode == 'v')\ndiff --git a/t/t7004-tag.sh b/t/t7004-tag.sh\nindex e8cebb6..873aad3 100755\n--- a/t/t7004-tag.sh\n+++ b/t/t7004-tag.sh\n@@ -1523,4 +1523,31 @@ test_expect_success '--format should list tags as per format given' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'setup --merged test tags' '\n+\tgit tag mergetest-1 HEAD~2 &&\n+\tgit tag mergetest-2 HEAD~1 &&\n+\tgit tag mergetest-3 HEAD\n+'\n+\n+test_expect_success '--merged cannot be used in non-list mode' '\n+\ttest_must_fail git tag --merged=mergetest-2 foo\n+'\n+\n+test_expect_success '--merged shows merged tags' '\n+\tcat >expect <<-\\EOF &&\n+\tmergetest-1\n+\tmergetest-2\n+\tEOF\n+\tgit tag -l --merged=mergetest-2 mergetest-* >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success '--no-merged show unmerged tags' '\n+\tcat >expect <<-\\EOF &&\n+\tmergetest-3\n+\tEOF\n+\tgit tag -l --no-merged=mergetest-2 mergetest-* >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\n-- \n2.4.4\n"},{"id":"264844","messageId":"1435237395-6754-1-git-send-email-karthik.188@gmail.com","threadId":"39720","inReplyTo":"1435232596-27466-8-git-send-email-karthik.188@gmail.com","subject":"[RFC/PATCH 8/9] tag.c: implement '--format' option","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-06-25T13:03:15Z","receivedAt":"2015-06-25T13:03:15Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"Implement the '--format' option provided by 'ref-filter'.\nThis lets the user list tags as per desired format similar\nto the implementation in 'git for-each-ref'.\n\nAdd tests and documentation for the same.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>\nSigned-off-by: Karthik Nayak <karthik.188@gmail.com>\n---\n Documentation/git-tag.txt | 15 ++++++++++++++-\n builtin/tag.c             | 11 +++++++----\n t/t7004-tag.sh            | 16 ++++++++++++++++\n 3 files changed, 37 insertions(+), 5 deletions(-)\n\ndiff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt\nindex 1950d94..16e396c 100644\n--- a/Documentation/git-tag.txt\n+++ b/Documentation/git-tag.txt\n@@ -13,7 +13,7 @@ SYNOPSIS\n \t<tagname> [<commit> | <object>]\n 'git tag' -d <tagname>...\n 'git tag' [-n[<num>]] -l [--contains <commit>] [--points-at <object>]\n-\t[--column[=<options>] | --no-column] [--sort=<key>] [<pattern>...]\n+\t[--column[=<options>] | --no-column] [--sort=<key>] [--format=<format>]\n \t[<pattern>...]\n 'git tag' -v <tagname>...\n \n@@ -156,6 +156,19 @@ This option is only applicable when listing tags without annotation lines.\n \tThe object that the new tag will refer to, usually a commit.\n \tDefaults to HEAD.\n \n+<format>::\n+\tA string that interpolates `%(fieldname)` from the\n+\tobject pointed at by a ref being shown.  If `fieldname`\n+\tis prefixed with an asterisk (`*`) and the ref points\n+\tat a tag object, the value for the field in the object\n+\ttag refers is used.  When unspecified, defaults to\n+\t`%(objectname) SPC %(objecttype) TAB %(refname)`.\n+\tIt also interpolates `%%` to `%`, and `%xx` where `xx`\n+\tare hex digits interpolates to character with hex code\n+\t`xx`; for example `%00` interpolates to `\\0` (NUL),\n+\t`%09` to `\\t` (TAB) and `%0a` to `\\n` (LF).\n+\tThe fields are same as those in `git for-each-ref`.\n+\n \n CONFIGURATION\n -------------\ndiff --git a/builtin/tag.c b/builtin/tag.c\nindex d80120e..257526b 100644\n--- a/builtin/tag.c\n+++ b/builtin/tag.c\n@@ -30,10 +30,9 @@ static const char * const git_tag_usage[] = {\n \n static unsigned int colopts;\n \n-static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting)\n+static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting, const char *format)\n {\n \tstruct ref_array array;\n-\tchar *format;\n \tint i;\n \n \tmemset(&array, 0, sizeof(array));\n@@ -43,7 +42,7 @@ static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting)\n \n \tif (filter->lines)\n \t\tformat = \"%(refname:lalign16)\";\n-\telse\n+\telse if (!format)\n \t\tformat = \"%(refname:short)\";\n \n \tverify_ref_format(format);\n@@ -324,6 +323,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)\n \tstruct strbuf err = STRBUF_INIT;\n \tstruct ref_filter filter;\n \tstatic struct ref_sorting *sorting = NULL, **sorting_tail = &sorting;\n+\tconst char *format = NULL;\n \tstruct option options[] = {\n \t\tOPT_CMDMODE('l', \"list\", &cmdmode, N_(\"list tag names\"), 'l'),\n \t\t{ OPTION_INTEGER, 'n', NULL, &filter.lines, N_(\"n\"),\n@@ -355,6 +355,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)\n \t\t\tOPTION_CALLBACK, 0, \"points-at\", &filter.points_at, N_(\"object\"),\n \t\t\tN_(\"print only tags of the object\"), 0, parse_opt_object_name\n \t\t},\n+\t\tOPT_STRING(  0 , \"format\", &format, N_(\"format\"), N_(\"format to use for the output\")),\n \t\tOPT_END()\n \t};\n \n@@ -394,8 +395,10 @@ int cmd_tag(int argc, const char **argv, const char *prefix)\n \t\t\tcopts.padding = 2;\n \t\t\trun_column_filter(colopts, &copts);\n \t\t}\n+\t\tif (format && (filter.lines != -1))\n+\t\t\tdie(_(\"--format and -n are incompatible\"));\n \t\tfilter.name_patterns = argv;\n-\t\tret = list_tags(&filter, sorting);\n+\t\tret = list_tags(&filter, sorting, format);\n \t\tif (column_active(colopts))\n \t\t\tstop_column_filter();\n \t\treturn ret;\ndiff --git a/t/t7004-tag.sh b/t/t7004-tag.sh\nindex 51a233f..e8cebb6 100755\n--- a/t/t7004-tag.sh\n+++ b/t/t7004-tag.sh\n@@ -1507,4 +1507,20 @@ EOF\"\n \ttest_cmp expect actual\n '\n \n+test_expect_success '--format cannot be used with -n' '\n+\ttest_must_fail git tag -l -n4 --format=\"%(refname)\"\n+'\n+\n+test_expect_success '--format should list tags as per format given' '\n+\tcat >expect <<-\\EOF &&\n+\tfoo1.10\n+\tfoo1.3\n+\tfoo1.6\n+\tfoo1.6-rc1\n+\tfoo1.6-rc2\n+\tEOF\n+\tgit tag -l --format=\"%(refname)\" \"foo*\" >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\n-- \n2.4.4\n"},{"id":"264999","messageId":"558DC0EB.3050203@gmail.com","threadId":"39720","inReplyTo":"1435232596-27466-5-git-send-email-karthik.188@gmail.com","subject":"Re: [RFC/PATCH 5/9] ref-filter: add option to match literal pattern","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-06-26T21:15:23Z","receivedAt":"2015-06-26T21:15:23Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"Just a few things I need to fix, personal note.\n\nOn 06/25/2015 05:13 PM, Karthik Nayak wrote:\n> Since 'ref-filter' only has an option to match path names.\n> Add an option for regular pattern matching.\n>\n> Mentored-by: Christian Couder <christian.couder@gmail.com>\n> Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>\n> Signed-off-by: Karthik Nayak <karthik.188@gmail.com>\n> ---\n>   builtin/for-each-ref.c |  1 +\n>   ref-filter.c           | 30 ++++++++++++++++++++++++------\n>   ref-filter.h           |  3 ++-\n>   3 files changed, 27 insertions(+), 7 deletions(-)\n>\n> diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c\n> index c318e33..01d5363 100644\n> --- a/builtin/for-each-ref.c\n> +++ b/builtin/for-each-ref.c\n> @@ -68,6 +68,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)\n>   \tgit_config(git_default_config, NULL);\n>\n>   \tfilter.name_patterns = argv;\n> +\tfilter.match_as_path = 1;\n>   \tfilter_refs(&array, &filter, FILTER_REFS_ALL | FILTER_REFS_INCLUDE_BROKEN);\n>   \tref_array_sort(sorting, &array);\n>\n> diff --git a/ref-filter.c b/ref-filter.c\n> index e307fab..1f97910 100644\n> --- a/ref-filter.c\n> +++ b/ref-filter.c\n> @@ -954,6 +954,20 @@ static int commit_contains(struct ref_filter *filter, struct commit *commit)\n>\n>   /*\n>    * Return 1 if the refname matches one of the patterns, otherwise 0.\n> + * A pattern can be a literal prefix (e.g. a refname \"refs/heads/master\"\n> + * matches a pattern \"refs/heads/m\") or a wildcard (e.g. the same ref\n> + * matches \"refs/heads/m*\",too).\n> + */\n> +static int match_pattern(const char **patterns, const char *refname)\n> +{\n> +\tfor (; *patterns; patterns++)\n> +\t\tif (!wildmatch(*patterns, refname, 0, NULL))\n> +\t\t\treturn 1;\n> +\treturn 0;\n> +}\n> +\n> +/*\n> + * Return 1 if the refname matches one of the patterns, otherwise 0.\n>    * A pattern can be path prefix (e.g. a refname \"refs/heads/master\"\n>    * matches a pattern \"refs/heads/\") or a wildcard (e.g. the same ref\n>    * matches \"refs/heads/m*\",too).\n> @@ -977,6 +991,15 @@ static int match_name_as_path(const char **pattern, const char *refname)\n>   \treturn 0;\n>   }\n>\n> +static int filter_pattern_match(struct ref_filter *filter, const char *refname)\n> +{\n> +\tif (!*filter->name_patterns)\n> +\t\treturn 0;\n\nShould return 1.\n\n> +\tif (filter->match_as_path)\n> +\t\treturn match_name_as_path(filter->name_patterns, refname);\n> +\treturn match_pattern(filter->name_patterns, refname);\n> +}\n> +\n>   /*\n>    * Given a ref (sha1, refname) see if it points to one of the sha1s\n>    * in a sha1_array.\n> @@ -1026,17 +1049,12 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,\n>   \tstruct ref_array_item *ref;\n>   \tstruct commit *commit = NULL;\n>\n> -\tif (flag & REF_BAD_NAME) {\n> -\t\t  warning(\"ignoring ref with broken name %s\", refname);\n> -\t\t  return 0;\n> -\t}\n> -\n\nUndo this merge conflict.\n\n>   \tif (flag & REF_ISBROKEN) {\n>   \t\twarning(\"ignoring broken ref %s\", refname);\n>   \t\treturn 0;\n>   \t}\n>\n> -\tif (*filter->name_patterns && !match_name_as_path(filter->name_patterns, refname))\n> +\tif (!filter_pattern_match(filter, refname))\n>   \t\treturn 0;\n>\n>   \tif (!match_points_at(&filter->points_at, oid->hash, refname))\n> diff --git a/ref-filter.h b/ref-filter.h\n> index 6b6fb96..a4809c8 100644\n> --- a/ref-filter.h\n> +++ b/ref-filter.h\n> @@ -54,7 +54,8 @@ struct ref_filter {\n>   \t} merge;\n>   \tstruct commit *merge_commit;\n>\n> -\tunsigned int with_commit_tag_algo: 1;\n> +\tunsigned int with_commit_tag_algo: 1,\n> +\t\tmatch_as_path: 1;\n>   \tunsigned int lines;\n>   };\n>\n>\n\nI'll add these changes to my local branch.\n\n-- \nRegards,\nKarthik\n"},{"id":"265034","messageId":"CAP8UFD1gT_2RKYc1vvBO9goGwPzFxhu9uMan5+cLO7eWxwwB_w@mail.gmail.com","threadId":"39720","inReplyTo":"1435232596-27466-1-git-send-email-karthik.188@gmail.com","subject":"Re: [RFC/PATCH 1/9] ref-filter: add %(refname:lalignX) option","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2015-06-27T20:02:14Z","receivedAt":"2015-06-27T20:02:14Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"On Thu, Jun 25, 2015 at 1:43 PM, Karthik Nayak <karthik.188@gmail.com> wrote:\n> Add support for %(refname:lalignX) where X is a number.\n> This will print a shortened refname aligned to the left\n> followed by spaces for a total length of X characters.\n> If X is less than the shortened refname size, the entire\n> shortened refname is printed.\n>\n> Mentored-by: Christian Couder <christian.couder@gmail.com>\n> Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>\n> Signed-off-by: Karthik Nayak <karthik.188@gmail.com>\n> ---\n>  ref-filter.c | 17 ++++++++++++++++-\n>  1 file changed, 16 insertions(+), 1 deletion(-)\n>\n> diff --git a/ref-filter.c b/ref-filter.c\n> index 00d06bf..299b048 100644\n> --- a/ref-filter.c\n> +++ b/ref-filter.c\n> @@ -695,7 +695,22 @@ static void populate_value(struct ref_array_item *ref)\n>                         int num_ours, num_theirs;\n>\n>                         formatp++;\n> -                       if (!strcmp(formatp, \"short\"))\n> +                       if (starts_with(formatp, \"lalign\")) {\n> +                               const char *valp;\n> +                               int val;\n> +\n> +                               skip_prefix(formatp, \"lalign\", &valp);\n> +                               val = atoi(valp);\n\nAfter thinking about such code, I wonder if it would be better to\nsupport %(refname:lalign=X) instead of %(refname:lalignX).\n\nThe reason why it might be interesting to require an = sign between\n\"align\" and the number X is that if we later want to introduce another\noption with a name that starts with \"lalign\", for example\n%(refname:lalignall=X) that would truncate the refname if it is bigger\nthan X), we might be more backward compatible with old git versions\nthat implement %(refname:lalign=X) but not %(refname:lalignall=X).\n\nWe will be more backward compatible because the above call to\nstarts_with() would probably be something like:\n\n                       if (starts_with(formatp, \"lalign=\")) {\n\nwhich means that old git versions would ignore something like \"lalignall=X\".\n\n> +                               refname = shorten_unambiguous_ref(refname,\n> +                                                                 warn_ambiguous_refs);\n> +                               if (val > strlen(refname)) {\n> +                                       struct strbuf buf = STRBUF_INIT;\n> +                                       strbuf_addstr(&buf, refname);\n> +                                       strbuf_addchars(&buf, ' ', val - strlen(refname));\n> +                                       free((char *)refname);\n> +                                       refname = strbuf_detach(&buf, NULL);\n> +                               }\n\nThanks,\nChristian.\n"},{"id":"265036","messageId":"CACsJy8DFrNMGBTL2xpQ6aG6huNhL-ipofPySL8_P+-EQtZyAMw@mail.gmail.com","threadId":"39720","inReplyTo":"1435232596-27466-1-git-send-email-karthik.188@gmail.com","subject":"Re: [RFC/PATCH 1/9] ref-filter: add %(refname:lalignX) option","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2015-06-27T23:43:04Z","receivedAt":"2015-06-27T23:43:04Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Thu, Jun 25, 2015 at 6:43 PM, Karthik Nayak <karthik.188@gmail.com> wrote:\n> Add support for %(refname:lalignX) where X is a number.\n> This will print a shortened refname aligned to the left\n> followed by spaces for a total length of X characters.\n> If X is less than the shortened refname size, the entire\n> shortened refname is printed.\n>\n> Mentored-by: Christian Couder <christian.couder@gmail.com>\n> Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>\n> Signed-off-by: Karthik Nayak <karthik.188@gmail.com>\n> ---\n>  ref-filter.c | 17 ++++++++++++++++-\n>  1 file changed, 16 insertions(+), 1 deletion(-)\n>\n> diff --git a/ref-filter.c b/ref-filter.c\n> index 00d06bf..299b048 100644\n> --- a/ref-filter.c\n> +++ b/ref-filter.c\n> @@ -695,7 +695,22 @@ static void populate_value(struct ref_array_item *ref)\n>                         int num_ours, num_theirs;\n>\n>                         formatp++;\n> -                       if (!strcmp(formatp, \"short\"))\n> +                       if (starts_with(formatp, \"lalign\")) {\n> +                               const char *valp;\n> +                               int val;\n> +\n> +                               skip_prefix(formatp, \"lalign\", &valp);\n> +                               val = atoi(valp);\n> +                               refname = shorten_unambiguous_ref(refname,\n> +                                                                 warn_ambiguous_refs);\n> +                               if (val > strlen(refname)) {\n> +                                       struct strbuf buf = STRBUF_INIT;\n> +                                       strbuf_addstr(&buf, refname);\n> +                                       strbuf_addchars(&buf, ' ', val - strlen(refname));\n\nWe don't forbid non-ascii characters in refname so you probably want\nto use utf8_width() here instead of strlen()\n\n> +                                       free((char *)refname);\n> +                                       refname = strbuf_detach(&buf, NULL);\n> +                               }\n> +                       } else if (!strcmp(formatp, \"short\"))\n>                                 refname = shorten_unambiguous_ref(refname,\n>                                                       warn_ambiguous_refs);\n>                         else if (!strcmp(formatp, \"track\") &&\n> --\n> 2.4.4\n>\n> --\n> To unsubscribe from this list: send the line \"unsubscribe git\" in\n> the body of a message to majordomo@vger.kernel.org\n> More majordomo info at  http://vger.kernel.org/majordomo-info.html\n\n\n\n-- \nDuy\n"},{"id":"265038","messageId":"CAP8UFD2nnJYybMVPeQ5QMvsHmcqJf3tmAuSpfrCdqTaucKUuSw@mail.gmail.com","threadId":"39720","inReplyTo":"CAP8UFD1gT_2RKYc1vvBO9goGwPzFxhu9uMan5+cLO7eWxwwB_w@mail.gmail.com","subject":"Re: [RFC/PATCH 1/9] ref-filter: add %(refname:lalignX) option","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2015-06-28T04:53:09Z","receivedAt":"2015-06-28T04:53:09Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"On Sat, Jun 27, 2015 at 10:02 PM, Christian Couder\n<christian.couder@gmail.com> wrote:\n> On Thu, Jun 25, 2015 at 1:43 PM, Karthik Nayak <karthik.188@gmail.com> wrote:\n>\n>> +                       if (starts_with(formatp, \"lalign\")) {\n>> +                               const char *valp;\n>> +                               int val;\n>> +\n>> +                               skip_prefix(formatp, \"lalign\", &valp);\n>> +                               val = atoi(valp);\n>\n> After thinking about such code, I wonder if it would be better to\n> support %(refname:lalign=X) instead of %(refname:lalignX).\n>\n> The reason why it might be interesting to require an = sign between\n> \"align\" and the number X is that if we later want to introduce another\n> option with a name that starts with \"lalign\", for example\n> %(refname:lalignall=X) that would truncate the refname if it is bigger\n> than X), we might be more backward compatible with old git versions\n> that implement %(refname:lalign=X) but not %(refname:lalignall=X).\n>\n> We will be more backward compatible because the above call to\n> starts_with() would probably be something like:\n>\n>                        if (starts_with(formatp, \"lalign=\")) {\n>\n> which means that old git versions would ignore something like \"lalignall=X\".\n\nAnother reason is that it would be simpler if we ever want to have\narbitrary string parameters, like %(refname:substitute=%/%\\%).\n"},{"id":"265042","messageId":"CAOLa=ZRdwoVrEh5igD-T5CPSOzOF8+k4pF6PE99wCqQo_q6+6g@mail.gmail.com","threadId":"39720","inReplyTo":"CAP8UFD1gT_2RKYc1vvBO9goGwPzFxhu9uMan5+cLO7eWxwwB_w@mail.gmail.com","subject":"Re: [RFC/PATCH 1/9] ref-filter: add %(refname:lalignX) option","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-06-28T06:59:13Z","receivedAt":"2015-06-28T06:59:13Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"Hey Christian,\nOn Sun, Jun 28, 2015 at 1:32 AM, Christian Couder\n<christian.couder@gmail.com> wrote:\n>\n> After thinking about such code, I wonder if it would be better to\n> support %(refname:lalign=X) instead of %(refname:lalignX).\n>\n> The reason why it might be interesting to require an = sign between\n> \"align\" and the number X is that if we later want to introduce another\n> option with a name that starts with \"lalign\", for example\n> %(refname:lalignall=X) that would truncate the refname if it is bigger\n> than X), we might be more backward compatible with old git versions\n> that implement %(refname:lalign=X) but not %(refname:lalignall=X).\n>\n> We will be more backward compatible because the above call to\n> starts_with() would probably be something like:\n>\n>                        if (starts_with(formatp, \"lalign=\")) {\n>\n> which means that old git versions would ignore something like \"lalignall=X\".\n>\n\nGood point! I agree with what you said, including an \"=\" sign would mean more\ncompatibility in the future as we could have lalign* options. Will\nchange this, thanks.\n\n-- \nRegards,\nKarthik Nayak\n"},{"id":"265044","messageId":"xmqqsi9ce0xj.fsf@gitster.dls.corp.google.com","threadId":"39720","inReplyTo":"1435232596-27466-1-git-send-email-karthik.188@gmail.com","subject":"Re: [RFC/PATCH 1/9] ref-filter: add %(refname:lalignX) option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-06-28T07:39:52Z","receivedAt":"2015-06-28T07:39:52Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Karthik Nayak <karthik.188@gmail.com> writes:\n\n> Add support for %(refname:lalignX) where X is a number.\n> This will print a shortened refname aligned to the left\n> followed by spaces for a total length of X characters.\n> If X is less than the shortened refname size, the entire\n> shortened refname is printed.\n\nWhy would we even want this kind of thing in the first place?  Is\nthis to make it possible to re-implement some option that exists\nalready in 'git branch' or 'git tag' as a thin wrapper on top of\nthis underlying feature?\n\nAs a low-level plumbing, I'd rather not to see such an elaborate\nformatting option added to for-each-ref; after all, the design of\nthe command to allow its output properly script-quoted is so that we\ncan offload such non-essential (meaning: does not need anything only\nGit knows; computing the display width of a string and filling the\noutput space is an example.  As opposed to something like --merged\nthat needs help from Git, which has the ultimate knowledge on the\ntopology) processing to Porcelain that uses the command as plumbing.\n"},{"id":"265046","messageId":"CAOLa=ZTkq9NWSu-Bd1iwxYD1yj9+URuQSopc_qjgxSbBv2t2uA@mail.gmail.com","threadId":"39720","inReplyTo":"xmqqsi9ce0xj.fsf@gitster.dls.corp.google.com","subject":"Re: [RFC/PATCH 1/9] ref-filter: add %(refname:lalignX) option","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-06-28T09:13:14Z","receivedAt":"2015-06-28T09:13:14Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"On Sun, Jun 28, 2015 at 1:09 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Karthik Nayak <karthik.188@gmail.com> writes:\n>\n>> Add support for %(refname:lalignX) where X is a number.\n>> This will print a shortened refname aligned to the left\n>> followed by spaces for a total length of X characters.\n>> If X is less than the shortened refname size, the entire\n>> shortened refname is printed.\n>\n> Why would we even want this kind of thing in the first place?  Is\n> this to make it possible to re-implement some option that exists\n> already in 'git branch' or 'git tag' as a thin wrapper on top of\n> this underlying feature?\n> As a low-level plumbing, I'd rather not to see such an elaborate\n> formatting option added to for-each-ref; after all, the design of\n> the command to allow its output properly script-quoted is so that we\n> can offload such non-essential (meaning: does not need anything only\n> Git knows; computing the display width of a string and filling the\n> output space is an example.  As opposed to something like --merged\n> that needs help from Git, which has the ultimate knowledge on the\n> topology) processing to Porcelain that uses the command as plumbing.\n>\n\nWell this is to support the printing of tag in `git tag -l`, if you\nsee the current\nimplementation we print refs using \"printf(\"%-15s \", refname);\" whenever the\n\"-n[<n>]\" option is given, hence this patch to support printing of refs using a\nrequired spacing.\n\nI couldn't find a way to do with the current options available in\nfor-each-ref/ref-filter.\nIs there a better way to go about this?\n\n-- \nRegards,\nKarthik Nayak\n"},{"id":"265104","messageId":"xmqqwpyncedr.fsf@gitster.dls.corp.google.com","threadId":"39720","inReplyTo":"CAOLa=ZTkq9NWSu-Bd1iwxYD1yj9+URuQSopc_qjgxSbBv2t2uA@mail.gmail.com","subject":"Re: [RFC/PATCH 1/9] ref-filter: add %(refname:lalignX) option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-06-29T04:44:32Z","receivedAt":"2015-06-29T04:44:32Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Karthik Nayak <karthik.188@gmail.com> writes:\n\n> On Sun, Jun 28, 2015 at 1:09 PM, Junio C Hamano <gitster@pobox.com> wrote:\n>\n>> Why would we even want this kind of thing in the first place?  Is\n>> this to make it possible to re-implement some option that exists\n>> already in 'git branch' or 'git tag' as a thin wrapper on top of\n>> this underlying feature?\n>> ...\n>\n> Well this is to support the printing of tag in `git tag -l`,...\n\nOK, then.\nThanks.\n"},{"id":"265159","messageId":"xmqqy4j29y0o.fsf@gitster.dls.corp.google.com","threadId":"39720","inReplyTo":"1435232596-27466-5-git-send-email-karthik.188@gmail.com","subject":"Re: [RFC/PATCH 5/9] ref-filter: add option to match literal pattern","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-06-29T18:20:55Z","receivedAt":"2015-06-29T18:20:55Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Karthik Nayak <karthik.188@gmail.com> writes:\n\n> Since 'ref-filter' only has an option to match path names.\n\nThat is not a whole sentence ;-)\n\n> Add an option for regular pattern matching.\n\n> Mentored-by: Christian Couder <christian.couder@gmail.com>\n> Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>\n> Signed-off-by: Karthik Nayak <karthik.188@gmail.com>\n\n> -\tif (flag & REF_BAD_NAME) {\n> -\t\t  warning(\"ignoring ref with broken name %s\", refname);\n> -\t\t  return 0;\n> -\t}\n> -\n\nHmm, where did this check go in the new code?  Or is it now OK not\nto warn or ignore, and if so why?\n\n>  \tif (flag & REF_ISBROKEN) {\n>  \t\twarning(\"ignoring broken ref %s\", refname);\n>  \t\treturn 0;\n>  \t}\n>  \n> -\tif (*filter->name_patterns && !match_name_as_path(filter->name_patterns, refname))\n> +\tif (!filter_pattern_match(filter, refname))\n>  \t\treturn 0;\n>  \n>  \tif (!match_points_at(&filter->points_at, oid->hash, refname))\n\n> diff --git a/ref-filter.h b/ref-filter.h\n> index 6b6fb96..a4809c8 100644\n> --- a/ref-filter.h\n> +++ b/ref-filter.h\n> @@ -54,7 +54,8 @@ struct ref_filter {\n>  \t} merge;\n>  \tstruct commit *merge_commit;\n>  \n> -\tunsigned int with_commit_tag_algo: 1;\n> +\tunsigned int with_commit_tag_algo: 1,\n> +\t\tmatch_as_path: 1;\n\nLose SP on both sides of the colon, or have SP on both sides\n(same for the last patch in the previous series).\n"},{"id":"265231","messageId":"CAOLa=ZSfpjumz6Cu7O3DF8vmVGofpibiJmpPo4irjn32f9WHxg@mail.gmail.com","threadId":"39720","inReplyTo":"xmqqy4j29y0o.fsf@gitster.dls.corp.google.com","subject":"Re: [RFC/PATCH 5/9] ref-filter: add option to match literal pattern","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-06-30T13:36:37Z","receivedAt":"2015-06-30T13:36:37Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"On Mon, Jun 29, 2015 at 11:50 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Karthik Nayak <karthik.188@gmail.com> writes:\n>\n>> Since 'ref-filter' only has an option to match path names.\n>\n> That is not a whole sentence ;-)\n>\n\nArgh! Noted.\n\n>> Add an option for regular pattern matching.\n>\n>> Mentored-by: Christian Couder <christian.couder@gmail.com>\n>> Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>\n>> Signed-off-by: Karthik Nayak <karthik.188@gmail.com>\n>\n>> -     if (flag & REF_BAD_NAME) {\n>> -               warning(\"ignoring ref with broken name %s\", refname);\n>> -               return 0;\n>> -     }\n>> -\n>\n> Hmm, where did this check go in the new code?  Or is it now OK not\n> to warn or ignore, and if so why?\n>\n\nMerge conflict, I've replied with a fixing patch, shouldn't be there\nin the next version :)\n\n>>       if (flag & REF_ISBROKEN) {\n>>               warning(\"ignoring broken ref %s\", refname);\n>>               return 0;\n>>       }\n>>\n>> -     if (*filter->name_patterns && !match_name_as_path(filter->name_patterns, refname))\n>> +     if (!filter_pattern_match(filter, refname))\n>>               return 0;\n>>\n>>       if (!match_points_at(&filter->points_at, oid->hash, refname))\n>\n>> diff --git a/ref-filter.h b/ref-filter.h\n>> index 6b6fb96..a4809c8 100644\n>> --- a/ref-filter.h\n>> +++ b/ref-filter.h\n>> @@ -54,7 +54,8 @@ struct ref_filter {\n>>       } merge;\n>>       struct commit *merge_commit;\n>>\n>> -     unsigned int with_commit_tag_algo: 1;\n>> +     unsigned int with_commit_tag_algo: 1,\n>> +             match_as_path: 1;\n>\n> Lose SP on both sides of the colon, or have SP on both sides\n> (same for the last patch in the previous series).\n\nWill Do!\n\nThanks for the quick review.\n\n-- \nRegards,\nKarthik Nayak\n"},{"id":"266055","messageId":"CACsJy8DYcTAB6OkpAf-5kQ0V09Jkw8KDTGbRvLRO4TVXAwK8Bw@mail.gmail.com","threadId":"39720","inReplyTo":"1435232596-27466-4-git-send-email-karthik.188@gmail.com","subject":"Re: [RFC/PATCH 4/9] ref-filter: add support to sort by version","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2015-07-12T09:09:20Z","receivedAt":"2015-07-12T09:09:20Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Thu, Jun 25, 2015 at 6:43 PM, Karthik Nayak <karthik.188@gmail.com> wrote:\n> Add support to sort by version using the \"v:refname\" and\n> \"version:refname\" option. This is achieved by using the\n> 'version_cmp()' function as the comparing function for qsort.\n\nIf these v:refname and version:refname are from git-tag, you may want\nto see [1]. I would say \"version:\" or \"v:\" is in the same class as \"-\"\n(for reverse sort) and they should be parsed in\nparse_opt_ref_sorting() instead. They should not be treated as atom\nnames. By stripping \"version:\" before pref_ref_filter_atom() is called\nin this function, you make \"version:\" work with all supported atoms.\n\n[1] http://article.gmane.org/gmane.comp.version-control.git/242446\n-- \nDuy\n"},{"id":"266061","messageId":"CAOLa=ZSi1i2x9iZrAK_mULp6NRUPDkJ=f26qM1Mfu=cmTiKUXg@mail.gmail.com","threadId":"39720","inReplyTo":"CACsJy8DYcTAB6OkpAf-5kQ0V09Jkw8KDTGbRvLRO4TVXAwK8Bw@mail.gmail.com","subject":"Re: [RFC/PATCH 4/9] ref-filter: add support to sort by version","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-07-12T13:37:46Z","receivedAt":"2015-07-12T13:37:46Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"On Sun, Jul 12, 2015 at 2:39 PM, Duy Nguyen <pclouds@gmail.com> wrote:\n> On Thu, Jun 25, 2015 at 6:43 PM, Karthik Nayak <karthik.188@gmail.com> wrote:\n>> Add support to sort by version using the \"v:refname\" and\n>> \"version:refname\" option. This is achieved by using the\n>> 'version_cmp()' function as the comparing function for qsort.\n>\n> If these v:refname and version:refname are from git-tag, you may want\n> to see [1]. I would say \"version:\" or \"v:\" is in the same class as \"-\"\n> (for reverse sort) and they should be parsed in\n> parse_opt_ref_sorting() instead. They should not be treated as atom\n> names. By stripping \"version:\" before pref_ref_filter_atom() is called\n> in this function, you make \"version:\" work with all supported atoms.\n>\n> [1] http://article.gmane.org/gmane.comp.version-control.git/242446\n> --\n> Duy\n\nThanks for this, what you're saying makes sense, will follow.\n\n-- \nRegards,\nKarthik Nayak\n"}]}