ref-filter: add support to sort by version

Add support to sort by version using the "v:refname" and
"version:refname" option. This is achieved by using the 'versioncmp()'
function as the comparing function for qsort.

This option is included to support sorting by versions in `git tag -l`
which will eventually be ported to use ref-filter APIs.

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>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Karthik Nayak
2015-09-10 21:18:25 +05:30
committed by Junio C Hamano
parent 1bb38e5a6a
commit 90c004085c
4 changed files with 51 additions and 6 deletions

View File

@ -157,6 +157,9 @@ For sorting purposes, fields with numeric values sort in numeric
order (`objectsize`, `authordate`, `committerdate`, `taggerdate`). order (`objectsize`, `authordate`, `committerdate`, `taggerdate`).
All other fields are used to sort in their byte-value order. All other fields are used to sort in their byte-value order.
There is also an option to sort by versions, this can be done by using
the fieldname `version:refname` or its alias `v:refname`.
In any case, a field name that refers to a field inapplicable to In any case, a field name that refers to a field inapplicable to
the object referred by the ref does not cause an error. It the object referred by the ref does not cause an error. It
returns an empty string instead. returns an empty string instead.

View File

@ -11,6 +11,8 @@
#include "ref-filter.h" #include "ref-filter.h"
#include "revision.h" #include "revision.h"
#include "utf8.h" #include "utf8.h"
#include "git-compat-util.h"
#include "version.h"
typedef enum { FIELD_STR, FIELD_ULONG, FIELD_TIME } cmp_type; typedef enum { FIELD_STR, FIELD_ULONG, FIELD_TIME } cmp_type;
@ -1439,19 +1441,19 @@ static int cmp_ref_sorting(struct ref_sorting *s, struct ref_array_item *a, stru
get_ref_atom_value(a, s->atom, &va); get_ref_atom_value(a, s->atom, &va);
get_ref_atom_value(b, s->atom, &vb); get_ref_atom_value(b, s->atom, &vb);
switch (cmp_type) { if (s->version)
case FIELD_STR: cmp = versioncmp(va->s, vb->s);
else if (cmp_type == FIELD_STR)
cmp = strcmp(va->s, vb->s); cmp = strcmp(va->s, vb->s);
break; else {
default:
if (va->ul < vb->ul) if (va->ul < vb->ul)
cmp = -1; cmp = -1;
else if (va->ul == vb->ul) else if (va->ul == vb->ul)
cmp = 0; cmp = 0;
else else
cmp = 1; cmp = 1;
break;
} }
return (s->reverse) ? -cmp : cmp; return (s->reverse) ? -cmp : cmp;
} }
@ -1584,6 +1586,9 @@ int parse_opt_ref_sorting(const struct option *opt, const char *arg, int unset)
s->reverse = 1; s->reverse = 1;
arg++; arg++;
} }
if (skip_prefix(arg, "version:", &arg) ||
skip_prefix(arg, "v:", &arg))
s->version = 1;
len = strlen(arg); len = strlen(arg);
s->atom = parse_ref_filter_atom(arg, arg+len); s->atom = parse_ref_filter_atom(arg, arg+len);
return 0; return 0;

View File

@ -28,7 +28,8 @@ struct atom_value;
struct ref_sorting { struct ref_sorting {
struct ref_sorting *next; struct ref_sorting *next;
int atom; /* index into used_atom array (internal) */ int atom; /* index into used_atom array (internal) */
unsigned reverse : 1; unsigned reverse : 1,
version : 1;
}; };
struct ref_array_item { struct ref_array_item {

View File

@ -219,4 +219,40 @@ test_expect_success '`%(contents:lines=-1)` should fail' '
test_must_fail git for-each-ref --format="%(refname:short) |%(contents:lines=-1)" test_must_fail git for-each-ref --format="%(refname:short) |%(contents:lines=-1)"
' '
test_expect_success 'setup for version sort' '
test_commit foo1.3 &&
test_commit foo1.6 &&
test_commit foo1.10
'
test_expect_success 'version sort' '
git for-each-ref --sort=version:refname --format="%(refname:short)" refs/tags/ | grep "foo" >actual &&
cat >expect <<-\EOF &&
foo1.3
foo1.6
foo1.10
EOF
test_cmp expect actual
'
test_expect_success 'version sort (shortened)' '
git for-each-ref --sort=v:refname --format="%(refname:short)" refs/tags/ | grep "foo" >actual &&
cat >expect <<-\EOF &&
foo1.3
foo1.6
foo1.10
EOF
test_cmp expect actual
'
test_expect_success 'reverse version sort' '
git for-each-ref --sort=-version:refname --format="%(refname:short)" refs/tags/ | grep "foo" >actual &&
cat >expect <<-\EOF &&
foo1.10
foo1.6
foo1.3
EOF
test_cmp expect actual
'
test_done test_done