summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNguyễn Thái Ngọc Duy <pclouds@gmail.com>2015-02-26 17:44:01 +0700
committerJunio C Hamano <gitster@pobox.com>2015-02-27 13:38:22 -0800
commitd811c8e17c652e62a97e75abf80dfea5d81ef309 (patch)
tree047e6678d308dd8032e6a09501764974bc31f93e
parentfdf96a20acf96a6ac538df8113b2aafd6ed71d50 (diff)
downloadgit-d811c8e17c652e62a97e75abf80dfea5d81ef309.tar.gz
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>
-rw-r--r--Documentation/config.txt7
-rwxr-xr-xt/t7004-tag.sh28
-rw-r--r--versioncmp.c50
3 files changed, 85 insertions, 0 deletions
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 9335ff2ae2..69a73458c3 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -2523,6 +2523,13 @@ user.signingkey::
This option is passed unchanged to gpg's --local-user parameter,
so you may specify a key using any method that gpg supports.
+versionsort.prereleaseSuffix::
+ When version sort is used in linkgit:git-tag[1], prerelease
+ tags (e.g. "1.0-rc1") may appear after the main release
+ "1.0". By specifying the suffix "-rc" in this variable,
+ "1.0-rc1" will appear before "1.0". One variable assignment
+ per suffix.
+
web.browser::
Specify a web browser that may be used by some commands.
Currently only linkgit:git-instaweb[1] and linkgit:git-help[1]
diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh
index 796e9f79ea..5674fe9f72 100755
--- a/t/t7004-tag.sh
+++ b/t/t7004-tag.sh
@@ -1459,6 +1459,34 @@ test_expect_success 'invalid sort parameter in configuratoin' '
test_cmp expect actual
'
+test_expect_success 'version sort with prerelease reordering' '
+ git config --unset tag.sort &&
+ git config versionsort.prereleaseSuffix -rc &&
+ git tag foo1.6-rc1 &&
+ git tag foo1.6-rc2 &&
+ git tag -l --sort=version:refname "foo*" >actual &&
+ cat >expect <<-\EOF &&
+ foo1.3
+ foo1.6-rc1
+ foo1.6-rc2
+ foo1.6
+ foo1.10
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success 'reverse version sort with prerelease reordering' '
+ git tag -l --sort=-version:refname "foo*" >actual &&
+ cat >expect <<-\EOF &&
+ foo1.10
+ foo1.6
+ foo1.6-rc2
+ foo1.6-rc1
+ foo1.3
+ EOF
+ test_cmp expect actual
+'
+
run_with_limited_stack () {
(ulimit -s 128 && "$@")
}
diff --git a/versioncmp.c b/versioncmp.c
index 7511e08271..80bfd109fa 100644
--- a/versioncmp.c
+++ b/versioncmp.c
@@ -1,4 +1,5 @@
#include "cache.h"
+#include "string-list.h"
/*
* versioncmp(): copied from string/strverscmp.c in glibc commit
@@ -20,6 +21,48 @@
#define CMP 2
#define LEN 3
+static const struct string_list *prereleases;
+static int initialized;
+
+/*
+ * p1 and p2 point to the first different character in two strings. If
+ * either p1 or p2 starts with a prerelease suffix, it will be forced
+ * to be on top.
+ *
+ * If both p1 and p2 start with (different) suffix, the order is
+ * determined by config file.
+ *
+ * Note that we don't have to deal with the situation when both p1 and
+ * p2 start with the same suffix because the common part is already
+ * consumed by the caller.
+ *
+ * Return non-zero if *diff contains the return value for versioncmp()
+ */
+static int swap_prereleases(const void *p1_,
+ const void *p2_,
+ int *diff)
+{
+ const char *p1 = p1_;
+ const char *p2 = p2_;
+ int i, i1 = -1, i2 = -1;
+
+ for (i = 0; i < prereleases->nr; i++) {
+ const char *suffix = prereleases->items[i].string;
+ if (i1 == -1 && starts_with(p1, suffix))
+ i1 = i;
+ if (i2 == -1 && starts_with(p2, suffix))
+ i2 = i;
+ }
+ if (i1 == -1 && i2 == -1)
+ return 0;
+ if (i1 >= 0 && i2 >= 0)
+ *diff = i1 - i2;
+ else if (i1 >= 0)
+ *diff = -1;
+ else /* if (i2 >= 0) */
+ *diff = 1;
+ return 1;
+}
/*
* Compare S1 and S2 as strings holding indices/version numbers,
@@ -74,6 +117,13 @@ int versioncmp(const char *s1, const char *s2)
state += (c1 == '0') + (isdigit (c1) != 0);
}
+ if (!initialized) {
+ initialized = 1;
+ prereleases = git_config_get_value_multi("versionsort.prereleasesuffix");
+ }
+ if (prereleases && swap_prereleases(p1 - 1, p2 - 1, &diff))
+ return diff;
+
state = result_type[state * 3 + (((c2 == '0') + (isdigit (c2) != 0)))];
switch (state) {