versionsort: support reorder prerelease suffixes
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Nguyễn Thái Ngọc Duy committed
Feb 26, 2015 at 17:44 UTC
d811c8e17c652e62a97e75abf80dfea5d81ef309
3 files changed
+85
Documentation/config.txt
+7
@@ -2523,6 +2523,13 @@ user.signingkey::
2523
This option is passed unchanged to gpg's --local-user parameter,
2524
so you may specify a key using any method that gpg supports.
2525
2526
+versionsort.prereleaseSuffix::
2527
+ When version sort is used in linkgit:git-tag[1], prerelease
2528
+ tags (e.g. "1.0-rc1") may appear after the main release
2529
+ "1.0". By specifying the suffix "-rc" in this variable,
2530
+ "1.0-rc1" will appear before "1.0". One variable assignment
2531
+ per suffix.
2532
+
2533
web.browser::
2534
Specify a web browser that may be used by some commands.
2535
Currently only linkgit:git-instaweb[1] and linkgit:git-help[1]
t/t7004-tag.sh
+28
@@ -1459,6 +1459,34 @@ test_expect_success 'invalid sort parameter in configuratoin' '
1459
test_cmp expect actual
1460
'
1461
1462
+test_expect_success 'version sort with prerelease reordering' '
1463
+ git config --unset tag.sort &&
1464
+ git config versionsort.prereleaseSuffix -rc &&
1465
+ git tag foo1.6-rc1 &&
1466
+ git tag foo1.6-rc2 &&
1467
+ git tag -l --sort=version:refname "foo*" >actual &&
1468
+ cat >expect <<-\EOF &&
1469
+ foo1.3
1470
+ foo1.6-rc1
1471
+ foo1.6-rc2
1472
+ foo1.6
1473
+ foo1.10
1474
+ EOF
1475
+ test_cmp expect actual
1476
+'
1477
+
1478
+test_expect_success 'reverse version sort with prerelease reordering' '
1479
+ git tag -l --sort=-version:refname "foo*" >actual &&
1480
+ cat >expect <<-\EOF &&
1481
+ foo1.10
1482
+ foo1.6
1483
+ foo1.6-rc2
1484
+ foo1.6-rc1
1485
+ foo1.3
1486
+ EOF
1487
+ test_cmp expect actual
1488
+'
1489
+
1490
run_with_limited_stack () {
1491
(ulimit -s 128 && "$@")
1492
}
versioncmp.c
+50
@@ -1,4 +1,5 @@
1
#include "cache.h"
2
+#include "string-list.h"
3
4
/*
5
* versioncmp(): copied from string/strverscmp.c in glibc commit
@@ -20,6 +21,48 @@
21
#define CMP 2
22
#define LEN 3
23
24
+static const struct string_list *prereleases;
25
+static int initialized;
26
+
27
+/*
28
+ * p1 and p2 point to the first different character in two strings. If
29
+ * either p1 or p2 starts with a prerelease suffix, it will be forced
30
+ * to be on top.
31
+ *
32
+ * If both p1 and p2 start with (different) suffix, the order is
33
+ * determined by config file.
34
+ *
35
+ * Note that we don't have to deal with the situation when both p1 and
36
+ * p2 start with the same suffix because the common part is already
37
+ * consumed by the caller.
38
+ *
39
+ * Return non-zero if *diff contains the return value for versioncmp()
40
+ */
41
+static int swap_prereleases(const void *p1_,
42
+ const void *p2_,
43
+ int *diff)
44
+{
45
+ const char *p1 = p1_;
46
+ const char *p2 = p2_;
47
+ int i, i1 = -1, i2 = -1;
48
+
49
+ for (i = 0; i < prereleases->nr; i++) {
50
+ const char *suffix = prereleases->items[i].string;
51
+ if (i1 == -1 && starts_with(p1, suffix))
52
+ i1 = i;
53
+ if (i2 == -1 && starts_with(p2, suffix))
54
+ i2 = i;
55
+ }
56
+ if (i1 == -1 && i2 == -1)
57
+ return 0;
58
+ if (i1 >= 0 && i2 >= 0)
59
+ *diff = i1 - i2;
60
+ else if (i1 >= 0)
61
+ *diff = -1;
62
+ else /* if (i2 >= 0) */
63
+ *diff = 1;
64
+ return 1;
65
+}
66
67
/*
68
* Compare S1 and S2 as strings holding indices/version numbers,
@@ -74,6 +117,13 @@ int versioncmp(const char *s1, const char *s2)
117
state += (c1 == '0') + (isdigit (c1) != 0);
118
}
119
120
+ if (!initialized) {
121
+ initialized = 1;
122
+ prereleases = git_config_get_value_multi("versionsort.prereleasesuffix");
123
+ }
124
+ if (prereleases && swap_prereleases(p1 - 1, p2 - 1, &diff))
125
+ return diff;
126
+
127
state = result_type[state * 3 + (((c2 == '0') + (isdigit (c2) != 0)))];
128
129
switch (state) {