From 9ef176b55c373ba087b2d84e77b5713578891927 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Thu, 27 Feb 2014 19:56:52 +0700 Subject: tag: support --sort= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --sort=version:refname (or --sort=v:refname for short) sorts tags as if they are versions. --sort=-refname reverses the order (with or without ":version"). versioncmp() is copied from string/strverscmp.c in glibc commit ee9247c38a8def24a59eb5cfb7196a98bef8cfdc, reformatted to Git coding style. The implementation is under LGPL-2.1 and according to [1] I can relicense it to GPLv2. [1] http://www.gnu.org/licenses/gpl-faq.html#AllCompatibility Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- builtin/tag.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 66 insertions(+), 5 deletions(-) (limited to 'builtin/tag.c') diff --git a/builtin/tag.c b/builtin/tag.c index 74d3780b7..0439c489f 100644 --- a/builtin/tag.c +++ b/builtin/tag.c @@ -27,9 +27,16 @@ static const char * const git_tag_usage[] = { NULL }; +#define STRCMP_SORT 0 /* must be zero */ +#define VERCMP_SORT 1 +#define SORT_MASK 0x7fff +#define REVERSE_SORT 0x8000 + struct tag_filter { const char **patterns; int lines; + int sort; + struct string_list tags; struct commit_list *with_commit; }; @@ -166,7 +173,10 @@ static int show_reference(const char *refname, const unsigned char *sha1, return 0; if (!filter->lines) { - printf("%s\n", refname); + if (filter->sort) + string_list_append(&filter->tags, refname); + else + printf("%s\n", refname); return 0; } printf("%-15s ", refname); @@ -177,17 +187,39 @@ static int show_reference(const char *refname, const unsigned char *sha1, return 0; } +static int sort_by_version(const void *a_, const void *b_) +{ + const struct string_list_item *a = a_; + const struct string_list_item *b = b_; + return versioncmp(a->string, b->string); +} + static int list_tags(const char **patterns, int lines, - struct commit_list *with_commit) + struct commit_list *with_commit, int sort) { struct tag_filter filter; filter.patterns = patterns; filter.lines = lines; + filter.sort = sort; filter.with_commit = with_commit; + memset(&filter.tags, 0, sizeof(filter.tags)); + filter.tags.strdup_strings = 1; for_each_tag_ref(show_reference, (void *) &filter); - + if (sort) { + int i; + if ((sort & SORT_MASK) == VERCMP_SORT) + qsort(filter.tags.items, filter.tags.nr, + sizeof(struct string_list_item), sort_by_version); + if (sort & REVERSE_SORT) + for (i = filter.tags.nr - 1; i >= 0; i--) + printf("%s\n", filter.tags.items[i].string); + else + for (i = 0; i < filter.tags.nr; i++) + printf("%s\n", filter.tags.items[i].string); + string_list_clear(&filter.tags, 0); + } return 0; } @@ -427,6 +459,29 @@ static int parse_opt_points_at(const struct option *opt __attribute__((unused)), return 0; } +static int parse_opt_sort(const struct option *opt, const char *arg, int unset) +{ + int *sort = opt->value; + int flags = 0; + + if (*arg == '-') { + flags |= REVERSE_SORT; + arg++; + } + if (starts_with(arg, "version:")) { + *sort = VERCMP_SORT; + arg += 8; + } else if (starts_with(arg, "v:")) { + *sort = VERCMP_SORT; + arg += 2; + } else + *sort = STRCMP_SORT; + if (strcmp(arg, "refname")) + die(_("unsupported sort specification %s"), arg); + *sort |= flags; + return 0; +} + int cmd_tag(int argc, const char **argv, const char *prefix) { struct strbuf buf = STRBUF_INIT; @@ -437,7 +492,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix) struct create_tag_options opt; char *cleanup_arg = NULL; int annotate = 0, force = 0, lines = -1; - int cmdmode = 0; + int cmdmode = 0, sort = 0; const char *msgfile = NULL, *keyid = NULL; struct msg_arg msg = { 0, STRBUF_INIT }; struct commit_list *with_commit = NULL; @@ -462,6 +517,10 @@ int cmd_tag(int argc, const char **argv, const char *prefix) N_("use another key to sign the tag")), OPT__FORCE(&force, N_("replace the tag if exists")), OPT_COLUMN(0, "column", &colopts, N_("show tag list in columns")), + { + OPTION_CALLBACK, 0, "sort", &sort, N_("type"), N_("sort tags"), + PARSE_OPT_NONEG, parse_opt_sort + }, OPT_GROUP(N_("Tag listing options")), { @@ -509,7 +568,9 @@ int cmd_tag(int argc, const char **argv, const char *prefix) copts.padding = 2; run_column_filter(colopts, &copts); } - ret = list_tags(argv, lines == -1 ? 0 : lines, with_commit); + if (lines != -1 && sort) + die(_("--sort and -n are incompatible")); + ret = list_tags(argv, lines == -1 ? 0 : lines, with_commit, sort); if (column_active(colopts)) stop_column_filter(); return ret; -- cgit v1.2.1