{"thread":{"id":"48197","subject":"[PATCH] ls-remote: create option to sort by versions","startedAt":"2018-04-02T00:53:08Z","lastAt":"2018-05-12T09:55:28Z","messageCount":62,"participants":["Harald Nordgren","Ævar Arnfjörð Bjarmason","Jeff King","Junio C Hamano","Eric Sunshine","Derrick Stolee","Stefan Beller","Todd Zullinger","René Scharfe"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"343562","messageId":"20180402005248.52418-1-haraldnordgren@gmail.com","threadId":"48197","inReplyTo":null,"subject":"[PATCH] ls-remote: create option to sort by versions","fromName":"Harald Nordgren","fromEmail":"haraldnordgren@gmail.com","sentAt":"2018-04-02T00:52:48Z","receivedAt":"2018-04-02T00:53:08Z","isPatch":true,"sender":{"key":"haraldnordgren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9569897?v=4"},"body":"Create the options '-V ' and '--version-sort' to sort\n'git ls-remote' output by version semantics. This is useful e.g. for\nthe Go repository after the release of version 1.10, where otherwise\nv1.10 is sorted before v1.2. See:\n\n\t$ git ls-remote -t https://go.googlesource.com/go\n\t...\n\t205f850ceacfc39d1e9d76a9569416284594ce8c\trefs/tags/go1.1\n\td260448f6b6ac10efe4ae7f6dfe944e72bc2a676\trefs/tags/go1.1.1\n\t1d6d8fca241bb611af51e265c1b5a2e9ae904702\trefs/tags/go1.1.2\n\tbf86aec25972f3a100c3aa58a6abcbcc35bdea49\trefs/tags/go1.10\n\tac7c0ee26dda18076d5f6c151d8f920b43340ae3\trefs/tags/go1.10.1\n\t9ce6b5c2ed5d3d5251b9a6a0c548d5fb2c8567e8\trefs/tags/go1.10beta1\n\t594668a5a96267a46282ce3007a584ec07adf705\trefs/tags/go1.10beta2\n\t5348aed83e39bd1d450d92d7f627e994c2db6ebf\trefs/tags/go1.10rc1\n\t20e228f2fdb44350c858de941dff4aea9f3127b8\trefs/tags/go1.10rc2\n\t1c5438aae896edcd1e9f9618f4776517f08053b3\trefs/tags/go1.1rc2\n\t46a6097aa7943a490e9bd2e04274845d0e5e200f\trefs/tags/go1.1rc3\n\t402d3590b54e4a0df9fb51ed14b2999e85ce0b76\trefs/tags/go1.2\n\t9c9802fad57c1bcb72ea98c5c55ea2652efc5772\trefs/tags/go1.2.1\n\t...\n\nSigned-off-by: Harald Nordgren <haraldnordgren@gmail.com>\n---\n builtin/ls-remote.c | 27 +++++++++++++++++++++++++--\n 1 file changed, 25 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/ls-remote.c b/builtin/ls-remote.c\nindex 540d56429..740c6f117 100644\n--- a/builtin/ls-remote.c\n+++ b/builtin/ls-remote.c\n@@ -1,6 +1,7 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n #include \"transport.h\"\n+#include \"ref-filter.h\"\n #include \"remote.h\"\n \n static const char * const ls_remote_usage[] = {\n@@ -33,11 +34,20 @@ static int tail_match(const char **pattern, const char *path)\n \treturn 0;\n }\n \n+static int cmp_ref_versions(const void *_a, const void *_b)\n+{\n+\tconst struct ref *a = *(const struct ref **)_a;\n+\tconst struct ref *b = *(const struct ref **)_b;\n+\n+\treturn versioncmp(a->name, b->name);\n+}\n+\n int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n {\n \tconst char *dest = NULL;\n \tunsigned flags = 0;\n \tint get_url = 0;\n+\tint version_sort = 0;\n \tint quiet = 0;\n \tint status = 0;\n \tint show_symref_target = 0;\n@@ -47,6 +57,8 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \tstruct remote *remote;\n \tstruct transport *transport;\n \tconst struct ref *ref;\n+\tconst struct ref **refs = NULL;\n+\tint nr = 0;\n \n \tstruct option options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"do not print remote URL\")),\n@@ -60,6 +72,8 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \t\tOPT_BIT(0, \"refs\", &flags, N_(\"do not show peeled tags\"), REF_NORMAL),\n \t\tOPT_BOOL(0, \"get-url\", &get_url,\n \t\t\t N_(\"take url.<base>.insteadOf into account\")),\n+\t\tOPT_BOOL('V', \"version-sort\", &version_sort,\n+\t\t\t N_(\"sort tags by version numbers\")),\n \t\tOPT_SET_INT_F(0, \"exit-code\", &status,\n \t\t\t      N_(\"exit with exit code 2 if no matching refs are found\"),\n \t\t\t      2, PARSE_OPT_NOCOMPLETE),\n@@ -101,13 +115,22 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \tif (transport_disconnect(transport))\n \t\treturn 1;\n \n-\tif (!dest && !quiet)\n-\t\tfprintf(stderr, \"From %s\\n\", *remote->url);\n \tfor ( ; ref; ref = ref->next) {\n \t\tif (!check_ref_type(ref, flags))\n \t\t\tcontinue;\n \t\tif (!tail_match(pattern, ref->name))\n \t\t\tcontinue;\n+\t\tREALLOC_ARRAY(refs, nr + 1);\n+\t\trefs[nr++] = ref;\n+\t}\n+\n+\tif (version_sort)\n+\t\tQSORT(refs, nr, cmp_ref_versions);\n+\n+\tif (!dest && !quiet)\n+\t\tfprintf(stderr, \"From %s\\n\", *remote->url);\n+\tfor (int i = 0; i < nr; i++) {\n+\t\tconst struct ref *ref = refs[i];\n \t\tif (show_symref_target && ref->symref)\n \t\t\tprintf(\"ref: %s\\t%s\\n\", ref->symref, ref->name);\n \t\tprintf(\"%s\\t%s\\n\", oid_to_hex(&ref->old_oid), ref->name);\n-- \n2.14.3 (Apple Git-98)\n\n"},{"id":"343570","messageId":"87605aw1ue.fsf@evledraar.gmail.com","threadId":"48197","inReplyTo":"20180402005248.52418-1-haraldnordgren@gmail.com","subject":"Re: [PATCH] ls-remote: create option to sort by versions","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-04-02T06:37:29Z","receivedAt":"2018-04-02T06:37:37Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Mon, Apr 02 2018, Harald Nordgren wrote:\n\n> Create the options '-V ' and '--version-sort' to sort\n> 'git ls-remote' output by version semantics. This is useful e.g. for\n> the Go repository after the release of version 1.10, where otherwise\n> v1.10 is sorted before v1.2. See:\n>\n> \t$ git ls-remote -t https://go.googlesource.com/go\n> \t...\n> \t205f850ceacfc39d1e9d76a9569416284594ce8c\trefs/tags/go1.1\n> \td260448f6b6ac10efe4ae7f6dfe944e72bc2a676\trefs/tags/go1.1.1\n> \t1d6d8fca241bb611af51e265c1b5a2e9ae904702\trefs/tags/go1.1.2\n> \tbf86aec25972f3a100c3aa58a6abcbcc35bdea49\trefs/tags/go1.10\n> \tac7c0ee26dda18076d5f6c151d8f920b43340ae3\trefs/tags/go1.10.1\n> \t9ce6b5c2ed5d3d5251b9a6a0c548d5fb2c8567e8\trefs/tags/go1.10beta1\n> \t594668a5a96267a46282ce3007a584ec07adf705\trefs/tags/go1.10beta2\n> \t5348aed83e39bd1d450d92d7f627e994c2db6ebf\trefs/tags/go1.10rc1\n> \t20e228f2fdb44350c858de941dff4aea9f3127b8\trefs/tags/go1.10rc2\n> \t1c5438aae896edcd1e9f9618f4776517f08053b3\trefs/tags/go1.1rc2\n> \t46a6097aa7943a490e9bd2e04274845d0e5e200f\trefs/tags/go1.1rc3\n> \t402d3590b54e4a0df9fb51ed14b2999e85ce0b76\trefs/tags/go1.2\n> \t9c9802fad57c1bcb72ea98c5c55ea2652efc5772\trefs/tags/go1.2.1\n> \t...\n\nThis is a sensible thing to want, but why not follow the UI we have for\nthis with git-tag? I.e. --sort=<key> & -i (or --ignore-case)? Of course\nls-remote doesn't just show tags, so maybe we'd want --tag-sort=<key>\nand --ignore-tag-case or something, but the rest should be equivalent,\nno?\n\n> [...]\n> @@ -101,13 +115,22 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n>  \tif (transport_disconnect(transport))\n>  \t\treturn 1;\n>\n> -\tif (!dest && !quiet)\n> -\t\tfprintf(stderr, \"From %s\\n\", *remote->url);\n>  \tfor ( ; ref; ref = ref->next) {\n>  \t\tif (!check_ref_type(ref, flags))\n>  \t\t\tcontinue;\n>  \t\tif (!tail_match(pattern, ref->name))\n>  \t\t\tcontinue;\n> +\t\tREALLOC_ARRAY(refs, nr + 1);\n> +\t\trefs[nr++] = ref;\n> +\t}\n> +\n> +\tif (version_sort)\n> +\t\tQSORT(refs, nr, cmp_ref_versions);\n> +\n> +\tif (!dest && !quiet)\n> +\t\tfprintf(stderr, \"From %s\\n\", *remote->url);\n\nIs there some subtlety here I'm missing which means that when sorting\nwe'd now need to print this \"From\" line later (i.e. after sorting?\n"},{"id":"343585","messageId":"CAHwyqnV1BwsaHVsh0xSx3MroNoJRT7UYrqF_WFKhkZMf-X9Evg@mail.gmail.com","threadId":"48197","inReplyTo":"87605aw1ue.fsf@evledraar.gmail.com","subject":"Re: [PATCH] ls-remote: create option to sort by versions","fromName":"Harald Nordgren","fromEmail":"haraldnordgren@gmail.com","sentAt":"2018-04-02T16:26:49Z","receivedAt":"2018-04-02T16:27:35Z","isPatch":true,"sender":{"key":"haraldnordgren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9569897?v=4"},"body":"Thanks for your comment Ævar!\n\nIn regards the the print statement, it was only moved down according\nto the diff because I added more logic above. Basically there is 1)\nthe unrolling of the linked list to an array and 2) the printing\nlogic. I could move it and make the diff smaller, but that probably\nmakes the code a tiny bit more complicated.\n\nIt would be nice to have a uniform option like\n'--sort=version:refname'. But spending a few hours to look over the\ncode, it seems that ls-remote.c would require a lot of rewrites if we\nwanted to start using `ref_array` and `ref_array_item` for storing the\nrefs.\n\nWhich seems necessary in order to hook in to the sorting flow used in\nother subcommands. That, or reimplement `cmp_ref_sorting`. But maybe\nI'm missing something?\n\nOn Mon, Apr 2, 2018 at 8:37 AM, Ævar Arnfjörð Bjarmason\n<avarab@gmail.com> wrote:\n>\n> On Mon, Apr 02 2018, Harald Nordgren wrote:\n>\n>> Create the options '-V ' and '--version-sort' to sort\n>> 'git ls-remote' output by version semantics. This is useful e.g. for\n>> the Go repository after the release of version 1.10, where otherwise\n>> v1.10 is sorted before v1.2. See:\n>>\n>>       $ git ls-remote -t https://go.googlesource.com/go\n>>       ...\n>>       205f850ceacfc39d1e9d76a9569416284594ce8c        refs/tags/go1.1\n>>       d260448f6b6ac10efe4ae7f6dfe944e72bc2a676        refs/tags/go1.1.1\n>>       1d6d8fca241bb611af51e265c1b5a2e9ae904702        refs/tags/go1.1.2\n>>       bf86aec25972f3a100c3aa58a6abcbcc35bdea49        refs/tags/go1.10\n>>       ac7c0ee26dda18076d5f6c151d8f920b43340ae3        refs/tags/go1.10.1\n>>       9ce6b5c2ed5d3d5251b9a6a0c548d5fb2c8567e8        refs/tags/go1.10beta1\n>>       594668a5a96267a46282ce3007a584ec07adf705        refs/tags/go1.10beta2\n>>       5348aed83e39bd1d450d92d7f627e994c2db6ebf        refs/tags/go1.10rc1\n>>       20e228f2fdb44350c858de941dff4aea9f3127b8        refs/tags/go1.10rc2\n>>       1c5438aae896edcd1e9f9618f4776517f08053b3        refs/tags/go1.1rc2\n>>       46a6097aa7943a490e9bd2e04274845d0e5e200f        refs/tags/go1.1rc3\n>>       402d3590b54e4a0df9fb51ed14b2999e85ce0b76        refs/tags/go1.2\n>>       9c9802fad57c1bcb72ea98c5c55ea2652efc5772        refs/tags/go1.2.1\n>>       ...\n>\n> This is a sensible thing to want, but why not follow the UI we have for\n> this with git-tag? I.e. --sort=<key> & -i (or --ignore-case)? Of course\n> ls-remote doesn't just show tags, so maybe we'd want --tag-sort=<key>\n> and --ignore-tag-case or something, but the rest should be equivalent,\n> no?\n>\n>> [...]\n>> @@ -101,13 +115,22 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n>>       if (transport_disconnect(transport))\n>>               return 1;\n>>\n>> -     if (!dest && !quiet)\n>> -             fprintf(stderr, \"From %s\\n\", *remote->url);\n>>       for ( ; ref; ref = ref->next) {\n>>               if (!check_ref_type(ref, flags))\n>>                       continue;\n>>               if (!tail_match(pattern, ref->name))\n>>                       continue;\n>> +             REALLOC_ARRAY(refs, nr + 1);\n>> +             refs[nr++] = ref;\n>> +     }\n>> +\n>> +     if (version_sort)\n>> +             QSORT(refs, nr, cmp_ref_versions);\n>> +\n>> +     if (!dest && !quiet)\n>> +             fprintf(stderr, \"From %s\\n\", *remote->url);\n>\n> Is there some subtlety here I'm missing which means that when sorting\n> we'd now need to print this \"From\" line later (i.e. after sorting?\n"},{"id":"343587","messageId":"87zi2lv7io.fsf@evledraar.gmail.com","threadId":"48197","inReplyTo":"CAHwyqnV1BwsaHVsh0xSx3MroNoJRT7UYrqF_WFKhkZMf-X9Evg@mail.gmail.com","subject":"Re: [PATCH] ls-remote: create option to sort by versions","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-04-02T17:32:31Z","receivedAt":"2018-04-02T17:32:40Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Mon, Apr 02 2018, Harald Nordgren wrote:\n\n> In regards the the print statement, it was only moved down according\n> to the diff because I added more logic above. Basically there is 1)\n> the unrolling of the linked list to an array and 2) the printing\n> logic. I could move it and make the diff smaller, but that probably\n> makes the code a tiny bit more complicated.\n\nI was just wondering since it wasn't explained in the commit message,\nmakes sense to copy this explanation into v2, or lead with a purely code\nre-arrangement patch.\n\n> It would be nice to have a uniform option like\n> '--sort=version:refname'. But spending a few hours to look over the\n> code, it seems that ls-remote.c would require a lot of rewrites if we\n> wanted to start using `ref_array` and `ref_array_item` for storing the\n> refs.\n>\n> Which seems necessary in order to hook in to the sorting flow used in\n> other subcommands. That, or reimplement `cmp_ref_sorting`. But maybe\n> I'm missing something?\n\nI'm thinking just in terms of UI. If it's the case that porting this to\nwhatever guts git-tag uses for sorting would be hard, then we could\nstill use the same command-line option convention (and perhaps just die\nif anything except --sort=version:refname is supplied). Changing the\nunderlying implementation is easier than cleaning up UI-differences that\n(seemingly) only arose due to underlying implementation details at the\ntime.\n\n> On Mon, Apr 2, 2018 at 8:37 AM, Ævar Arnfjörð Bjarmason\n> <avarab@gmail.com> wrote:\n>>\n>> On Mon, Apr 02 2018, Harald Nordgren wrote:\n>>\n>>> Create the options '-V ' and '--version-sort' to sort\n>>> 'git ls-remote' output by version semantics. This is useful e.g. for\n>>> the Go repository after the release of version 1.10, where otherwise\n>>> v1.10 is sorted before v1.2. See:\n>>>\n>>>       $ git ls-remote -t https://go.googlesource.com/go\n>>>       ...\n>>>       205f850ceacfc39d1e9d76a9569416284594ce8c        refs/tags/go1.1\n>>>       d260448f6b6ac10efe4ae7f6dfe944e72bc2a676        refs/tags/go1.1.1\n>>>       1d6d8fca241bb611af51e265c1b5a2e9ae904702        refs/tags/go1.1.2\n>>>       bf86aec25972f3a100c3aa58a6abcbcc35bdea49        refs/tags/go1.10\n>>>       ac7c0ee26dda18076d5f6c151d8f920b43340ae3        refs/tags/go1.10.1\n>>>       9ce6b5c2ed5d3d5251b9a6a0c548d5fb2c8567e8        refs/tags/go1.10beta1\n>>>       594668a5a96267a46282ce3007a584ec07adf705        refs/tags/go1.10beta2\n>>>       5348aed83e39bd1d450d92d7f627e994c2db6ebf        refs/tags/go1.10rc1\n>>>       20e228f2fdb44350c858de941dff4aea9f3127b8        refs/tags/go1.10rc2\n>>>       1c5438aae896edcd1e9f9618f4776517f08053b3        refs/tags/go1.1rc2\n>>>       46a6097aa7943a490e9bd2e04274845d0e5e200f        refs/tags/go1.1rc3\n>>>       402d3590b54e4a0df9fb51ed14b2999e85ce0b76        refs/tags/go1.2\n>>>       9c9802fad57c1bcb72ea98c5c55ea2652efc5772        refs/tags/go1.2.1\n>>>       ...\n>>\n>> This is a sensible thing to want, but why not follow the UI we have for\n>> this with git-tag? I.e. --sort=<key> & -i (or --ignore-case)? Of course\n>> ls-remote doesn't just show tags, so maybe we'd want --tag-sort=<key>\n>> and --ignore-tag-case or something, but the rest should be equivalent,\n>> no?\n>>\n>>> [...]\n>>> @@ -101,13 +115,22 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n>>>       if (transport_disconnect(transport))\n>>>               return 1;\n>>>\n>>> -     if (!dest && !quiet)\n>>> -             fprintf(stderr, \"From %s\\n\", *remote->url);\n>>>       for ( ; ref; ref = ref->next) {\n>>>               if (!check_ref_type(ref, flags))\n>>>                       continue;\n>>>               if (!tail_match(pattern, ref->name))\n>>>                       continue;\n>>> +             REALLOC_ARRAY(refs, nr + 1);\n>>> +             refs[nr++] = ref;\n>>> +     }\n>>> +\n>>> +     if (version_sort)\n>>> +             QSORT(refs, nr, cmp_ref_versions);\n>>> +\n>>> +     if (!dest && !quiet)\n>>> +             fprintf(stderr, \"From %s\\n\", *remote->url);\n>>\n>> Is there some subtlety here I'm missing which means that when sorting\n>> we'd now need to print this \"From\" line later (i.e. after sorting?\n"},{"id":"343589","messageId":"CAHwyqnU_5RVJBRLm4SBPo-xQKFQQTat33RdJBN2OOBSt1ZBNPQ@mail.gmail.com","threadId":"48197","inReplyTo":"87zi2lv7io.fsf@evledraar.gmail.com","subject":"Re: [PATCH] ls-remote: create option to sort by versions","fromName":"Harald Nordgren","fromEmail":"haraldnordgren@gmail.com","sentAt":"2018-04-02T17:42:29Z","receivedAt":"2018-04-02T17:43:15Z","isPatch":true,"sender":{"key":"haraldnordgren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9569897?v=4"},"body":"Both points make sense and it sounds like a very pragmatic approach.\nI'll look into it!\n\nOn Mon, Apr 2, 2018 at 7:32 PM, Ævar Arnfjörð Bjarmason\n<avarab@gmail.com> wrote:\n>\n> On Mon, Apr 02 2018, Harald Nordgren wrote:\n>\n>> In regards the the print statement, it was only moved down according\n>> to the diff because I added more logic above. Basically there is 1)\n>> the unrolling of the linked list to an array and 2) the printing\n>> logic. I could move it and make the diff smaller, but that probably\n>> makes the code a tiny bit more complicated.\n>\n> I was just wondering since it wasn't explained in the commit message,\n> makes sense to copy this explanation into v2, or lead with a purely code\n> re-arrangement patch.\n>\n>> It would be nice to have a uniform option like\n>> '--sort=version:refname'. But spending a few hours to look over the\n>> code, it seems that ls-remote.c would require a lot of rewrites if we\n>> wanted to start using `ref_array` and `ref_array_item` for storing the\n>> refs.\n>>\n>> Which seems necessary in order to hook in to the sorting flow used in\n>> other subcommands. That, or reimplement `cmp_ref_sorting`. But maybe\n>> I'm missing something?\n>\n> I'm thinking just in terms of UI. If it's the case that porting this to\n> whatever guts git-tag uses for sorting would be hard, then we could\n> still use the same command-line option convention (and perhaps just die\n> if anything except --sort=version:refname is supplied). Changing the\n> underlying implementation is easier than cleaning up UI-differences that\n> (seemingly) only arose due to underlying implementation details at the\n> time.\n>\n>> On Mon, Apr 2, 2018 at 8:37 AM, Ævar Arnfjörð Bjarmason\n>> <avarab@gmail.com> wrote:\n>>>\n>>> On Mon, Apr 02 2018, Harald Nordgren wrote:\n>>>\n>>>> Create the options '-V ' and '--version-sort' to sort\n>>>> 'git ls-remote' output by version semantics. This is useful e.g. for\n>>>> the Go repository after the release of version 1.10, where otherwise\n>>>> v1.10 is sorted before v1.2. See:\n>>>>\n>>>>       $ git ls-remote -t https://go.googlesource.com/go\n>>>>       ...\n>>>>       205f850ceacfc39d1e9d76a9569416284594ce8c        refs/tags/go1.1\n>>>>       d260448f6b6ac10efe4ae7f6dfe944e72bc2a676        refs/tags/go1.1.1\n>>>>       1d6d8fca241bb611af51e265c1b5a2e9ae904702        refs/tags/go1.1.2\n>>>>       bf86aec25972f3a100c3aa58a6abcbcc35bdea49        refs/tags/go1.10\n>>>>       ac7c0ee26dda18076d5f6c151d8f920b43340ae3        refs/tags/go1.10.1\n>>>>       9ce6b5c2ed5d3d5251b9a6a0c548d5fb2c8567e8        refs/tags/go1.10beta1\n>>>>       594668a5a96267a46282ce3007a584ec07adf705        refs/tags/go1.10beta2\n>>>>       5348aed83e39bd1d450d92d7f627e994c2db6ebf        refs/tags/go1.10rc1\n>>>>       20e228f2fdb44350c858de941dff4aea9f3127b8        refs/tags/go1.10rc2\n>>>>       1c5438aae896edcd1e9f9618f4776517f08053b3        refs/tags/go1.1rc2\n>>>>       46a6097aa7943a490e9bd2e04274845d0e5e200f        refs/tags/go1.1rc3\n>>>>       402d3590b54e4a0df9fb51ed14b2999e85ce0b76        refs/tags/go1.2\n>>>>       9c9802fad57c1bcb72ea98c5c55ea2652efc5772        refs/tags/go1.2.1\n>>>>       ...\n>>>\n>>> This is a sensible thing to want, but why not follow the UI we have for\n>>> this with git-tag? I.e. --sort=<key> & -i (or --ignore-case)? Of course\n>>> ls-remote doesn't just show tags, so maybe we'd want --tag-sort=<key>\n>>> and --ignore-tag-case or something, but the rest should be equivalent,\n>>> no?\n>>>\n>>>> [...]\n>>>> @@ -101,13 +115,22 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n>>>>       if (transport_disconnect(transport))\n>>>>               return 1;\n>>>>\n>>>> -     if (!dest && !quiet)\n>>>> -             fprintf(stderr, \"From %s\\n\", *remote->url);\n>>>>       for ( ; ref; ref = ref->next) {\n>>>>               if (!check_ref_type(ref, flags))\n>>>>                       continue;\n>>>>               if (!tail_match(pattern, ref->name))\n>>>>                       continue;\n>>>> +             REALLOC_ARRAY(refs, nr + 1);\n>>>> +             refs[nr++] = ref;\n>>>> +     }\n>>>> +\n>>>> +     if (version_sort)\n>>>> +             QSORT(refs, nr, cmp_ref_versions);\n>>>> +\n>>>> +     if (!dest && !quiet)\n>>>> +             fprintf(stderr, \"From %s\\n\", *remote->url);\n>>>\n>>> Is there some subtlety here I'm missing which means that when sorting\n>>> we'd now need to print this \"From\" line later (i.e. after sorting?\n"},{"id":"343590","messageId":"20180402174614.GA28566@sigill.intra.peff.net","threadId":"48197","inReplyTo":"CAHwyqnV1BwsaHVsh0xSx3MroNoJRT7UYrqF_WFKhkZMf-X9Evg@mail.gmail.com","subject":"Re: [PATCH] ls-remote: create option to sort by versions","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-04-02T17:46:15Z","receivedAt":"2018-04-02T17:46:21Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Apr 02, 2018 at 06:26:49PM +0200, Harald Nordgren wrote:\n\n> It would be nice to have a uniform option like\n> '--sort=version:refname'. But spending a few hours to look over the\n> code, it seems that ls-remote.c would require a lot of rewrites if we\n> wanted to start using `ref_array` and `ref_array_item` for storing the\n> refs.\n> \n> Which seems necessary in order to hook in to the sorting flow used in\n> other subcommands. That, or reimplement `cmp_ref_sorting`. But maybe\n> I'm missing something?\n\nI haven't looked at how painful it might be to use ref-filter.c, but it\nwould buy us even more if we could. That would open up other options\nlike --format, I think (OTOH there may be some funny corner cases; that\ncode assumes we're talking about local refs, so if you were to ask for\n\"%(committerdate)\" or something, we might have to more cleanly handle\nthe case where we don't actually have the object).\n\n-Peff\n"},{"id":"343597","messageId":"xmqqbmf1zcfb.fsf@gitster-ct.c.googlers.com","threadId":"48197","inReplyTo":"87605aw1ue.fsf@evledraar.gmail.com","subject":"Re: [PATCH] ls-remote: create option to sort by versions","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-04-02T18:32:56Z","receivedAt":"2018-04-02T18:33:08Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> This is a sensible thing to want, but why not follow the UI we have for\n> this with git-tag? I.e. --sort=<key> & -i (or --ignore-case)? Of course\n> ls-remote doesn't just show tags, so maybe we'd want --tag-sort=<key>\n> and --ignore-tag-case or something, but the rest should be equivalent,\n> no?\n\nYeah, and if we can reuse more of ref-filter.c machinery (which was\nfactored out of for-each-ref and tag you suggested borrows from),\nthat would be even better.  In the context of ls-remote, however, we\ncannot inspect the object (we typically do not have them yet), so it\nmay not be practical, but I agree with your suggestion---we should\nmatch the behaviour at the UI level at least when we can.\n\n"},{"id":"343602","messageId":"CAHwyqnV8tB63gQFVJhyNtr304Uv1TwWvYiX+3wuU0fDFhOphgg@mail.gmail.com","threadId":"48197","inReplyTo":"xmqqbmf1zcfb.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH] ls-remote: create option to sort by versions","fromName":"Harald Nordgren","fromEmail":"haraldnordgren@gmail.com","sentAt":"2018-04-02T20:03:53Z","receivedAt":"2018-04-02T20:04:39Z","isPatch":true,"sender":{"key":"haraldnordgren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9569897?v=4"},"body":"Thanks for all the discussion!\n\nI think I figured out a way to reuse more ref-filter.c machinery. I\nwill submit another patchset shortly.\n\nOn Mon, Apr 2, 2018 at 8:32 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n>\n>> This is a sensible thing to want, but why not follow the UI we have for\n>> this with git-tag? I.e. --sort=<key> & -i (or --ignore-case)? Of course\n>> ls-remote doesn't just show tags, so maybe we'd want --tag-sort=<key>\n>> and --ignore-tag-case or something, but the rest should be equivalent,\n>> no?\n>\n> Yeah, and if we can reuse more of ref-filter.c machinery (which was\n> factored out of for-each-ref and tag you suggested borrows from),\n> that would be even better.  In the context of ls-remote, however, we\n> cannot inspect the object (we typically do not have them yet), so it\n> may not be practical, but I agree with your suggestion---we should\n> match the behaviour at the UI level at least when we can.\n>\n"},{"id":"343626","messageId":"20180402210523.83293-1-haraldnordgren@gmail.com","threadId":"48197","inReplyTo":"20180402005248.52418-1-haraldnordgren@gmail.com","subject":"[PATCH v4] ls-remote: create '--sort' option","fromName":"Harald Nordgren","fromEmail":"haraldnordgren@gmail.com","sentAt":"2018-04-02T21:05:23Z","receivedAt":"2018-04-02T21:05:51Z","isPatch":true,"sender":{"key":"haraldnordgren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9569897?v=4"},"body":"Create a '--sort' option for ls-remote, based on the one from\nfor-each-ref. This e.g. allows ref names to be sorted by version\nsemantics, so that v1.2 is sorted before v1.10.\n\nSigned-off-by: Harald Nordgren <haraldnordgren@gmail.com>\n---\n Documentation/git-ls-remote.txt | 12 +++++++++++-\n builtin/ls-remote.c             | 27 +++++++++++++++++++++++++--\n t/t5512-ls-remote.sh            | 41 ++++++++++++++++++++++++++++++++++++++++-\n 3 files changed, 76 insertions(+), 4 deletions(-)\n\ndiff --git a/Documentation/git-ls-remote.txt b/Documentation/git-ls-remote.txt\nindex 5f2628c8f..17fae7218 100644\n--- a/Documentation/git-ls-remote.txt\n+++ b/Documentation/git-ls-remote.txt\n@@ -10,7 +10,7 @@ SYNOPSIS\n --------\n [verse]\n 'git ls-remote' [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n-\t      [-q | --quiet] [--exit-code] [--get-url]\n+\t      [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n \t      [--symref] [<repository> [<refs>...]]\n \n DESCRIPTION\n@@ -60,6 +60,16 @@ OPTIONS\n \tupload-pack only shows the symref HEAD, so it will be the only\n \tone shown by ls-remote.\n \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 \"versionsort.suffix\"\n+\tconfiguration variable.\n+\tThe keys supported are the same as those in `git for-each-ref`.\n+\n <repository>::\n \tThe \"remote\" repository to query.  This parameter can be\n \teither a URL or the name of a remote (see the GIT URLS and\ndiff --git a/builtin/ls-remote.c b/builtin/ls-remote.c\nindex 540d56429..5521c72f4 100644\n--- a/builtin/ls-remote.c\n+++ b/builtin/ls-remote.c\n@@ -1,6 +1,7 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n #include \"transport.h\"\n+#include \"ref-filter.h\"\n #include \"remote.h\"\n \n static const char * const ls_remote_usage[] = {\n@@ -47,6 +48,8 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \tstruct remote *remote;\n \tstruct transport *transport;\n \tconst struct ref *ref;\n+\tstruct ref_array array;\n+\tstatic struct ref_sorting *sorting = NULL, **sorting_tail = &sorting;\n \n \tstruct option options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"do not print remote URL\")),\n@@ -60,6 +63,8 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \t\tOPT_BIT(0, \"refs\", &flags, N_(\"do not show peeled tags\"), REF_NORMAL),\n \t\tOPT_BOOL(0, \"get-url\", &get_url,\n \t\t\t N_(\"take url.<base>.insteadOf into account\")),\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\tOPT_SET_INT_F(0, \"exit-code\", &status,\n \t\t\t      N_(\"exit with exit code 2 if no matching refs are found\"),\n \t\t\t      2, PARSE_OPT_NOCOMPLETE),\n@@ -68,6 +73,8 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \t\tOPT_END()\n \t};\n \n+\tmemset(&array, 0, sizeof(array));\n+\n \targc = parse_options(argc, argv, prefix, options, ls_remote_usage,\n \t\t\t     PARSE_OPT_STOP_AT_NON_OPTION);\n \tdest = argv[0];\n@@ -108,9 +115,25 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \t\t\tcontinue;\n \t\tif (!tail_match(pattern, ref->name))\n \t\t\tcontinue;\n+\n+\t\tstruct ref_array_item *item;\n+\t\tFLEX_ALLOC_MEM(item, refname, ref->name, strlen(ref->name));\n+\t\titem->symref = ref->symref;\n+\t\titem->objectname = ref->old_oid;\n+\n+\t\tREALLOC_ARRAY(array.items, array.nr + 1);\n+\t\tarray.items[array.nr++] = item;\n+\t}\n+\n+\tif (sorting) {\n+\t\tref_array_sort(sorting, &array);\n+\t}\n+\n+\tfor (int i = 0; i < array.nr; i++) {\n+\t\tconst struct ref_array_item *ref = array.items[i];\n \t\tif (show_symref_target && ref->symref)\n-\t\t\tprintf(\"ref: %s\\t%s\\n\", ref->symref, ref->name);\n-\t\tprintf(\"%s\\t%s\\n\", oid_to_hex(&ref->old_oid), ref->name);\n+\t\t\tprintf(\"ref: %s\\t%s\\n\", ref->symref, ref->refname);\n+\t\tprintf(\"%s\\t%s\\n\", oid_to_hex(&ref->objectname), ref->refname);\n \t\tstatus = 0; /* we found something */\n \t}\n \treturn status;\ndiff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh\nindex 02106c922..66370cd88 100755\n--- a/t/t5512-ls-remote.sh\n+++ b/t/t5512-ls-remote.sh\n@@ -10,6 +10,9 @@ test_expect_success setup '\n \ttest_tick &&\n \tgit commit -m initial &&\n \tgit tag mark &&\n+\tgit tag mark1.1 &&\n+\tgit tag mark1.2 &&\n+\tgit tag mark1.10 &&\n \tgit show-ref --tags -d | sed -e \"s/ /\t/\" >expected.tag &&\n \t(\n \t\techo \"$(git rev-parse HEAD)\tHEAD\"\n@@ -39,6 +42,39 @@ test_expect_success 'ls-remote self' '\n \ttest_cmp expected.all actual\n '\n \n+test_expect_success 'ls-remote --sort=\"version:refname\" --tags self' '\n+\tcat >expect <<-\\EOF &&\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.1\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.2\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.10\n+\tEOF\n+\tgit ls-remote --sort=\"version:refname\" --tags self >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'ls-remote --sort=\"-version:refname\" --tags self' '\n+\tcat >expect <<-\\EOF &&\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.10\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.2\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.1\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark\n+\tEOF\n+\tgit ls-remote --sort=\"-version:refname\" --tags self >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'ls-remote --sort=\"-refname\" --tags self' '\n+\tcat >expect <<-\\EOF &&\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.2\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.10\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.1\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark\n+\tEOF\n+\tgit ls-remote --sort=\"-refname\" --tags self >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_expect_success 'dies when no remote specified and no default remotes found' '\n \ttest_must_fail git ls-remote\n '\n@@ -131,7 +167,7 @@ test_expect_success 'Report no-match with --exit-code' '\n \n test_expect_success 'Report match with --exit-code' '\n \tgit ls-remote --exit-code other.git \"refs/tags/*\" >actual &&\n-\tgit ls-remote . tags/mark >expect &&\n+\tgit ls-remote . tags/mark* >expect &&\n \ttest_cmp expect actual\n '\n \n@@ -178,6 +214,9 @@ test_expect_success 'ls-remote --symref' '\n \t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/remotes/origin/HEAD\n \t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/remotes/origin/master\n \t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.1\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.10\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.2\n \tEOF\n \tgit ls-remote --symref >actual &&\n \ttest_cmp expect actual\n-- \n2.14.3 (Apple Git-98)\n\n"},{"id":"343633","messageId":"20180402221124.88049-1-haraldnordgren@gmail.com","threadId":"48197","inReplyTo":"CAHwyqnV8tB63gQFVJhyNtr304Uv1TwWvYiX+3wuU0fDFhOphgg@mail.gmail.com","subject":"[PATCH v5] ls-remote: create '--sort' option","fromName":"Harald Nordgren","fromEmail":"haraldnordgren@gmail.com","sentAt":"2018-04-02T22:11:24Z","receivedAt":"2018-04-02T22:11:50Z","isPatch":true,"sender":{"key":"haraldnordgren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9569897?v=4"},"body":"Create a '--sort' option for ls-remote, based on the one from\nfor-each-ref. This e.g. allows ref names to be sorted by version\nsemantics, so that v1.2 is sorted before v1.10.\n\nSigned-off-by: Harald Nordgren <haraldnordgren@gmail.com>\n---\n Documentation/git-ls-remote.txt | 12 +++++++++++-\n builtin/ls-remote.c             | 26 ++++++++++++++++++++++++--\n t/t5512-ls-remote.sh            | 41 ++++++++++++++++++++++++++++++++++++++++-\n 3 files changed, 75 insertions(+), 4 deletions(-)\n\ndiff --git a/Documentation/git-ls-remote.txt b/Documentation/git-ls-remote.txt\nindex 5f2628c8f..17fae7218 100644\n--- a/Documentation/git-ls-remote.txt\n+++ b/Documentation/git-ls-remote.txt\n@@ -10,7 +10,7 @@ SYNOPSIS\n --------\n [verse]\n 'git ls-remote' [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n-\t      [-q | --quiet] [--exit-code] [--get-url]\n+\t      [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n \t      [--symref] [<repository> [<refs>...]]\n \n DESCRIPTION\n@@ -60,6 +60,16 @@ OPTIONS\n \tupload-pack only shows the symref HEAD, so it will be the only\n \tone shown by ls-remote.\n \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 \"versionsort.suffix\"\n+\tconfiguration variable.\n+\tThe keys supported are the same as those in `git for-each-ref`.\n+\n <repository>::\n \tThe \"remote\" repository to query.  This parameter can be\n \teither a URL or the name of a remote (see the GIT URLS and\ndiff --git a/builtin/ls-remote.c b/builtin/ls-remote.c\nindex 540d56429..7e2d820c4 100644\n--- a/builtin/ls-remote.c\n+++ b/builtin/ls-remote.c\n@@ -1,6 +1,7 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n #include \"transport.h\"\n+#include \"ref-filter.h\"\n #include \"remote.h\"\n \n static const char * const ls_remote_usage[] = {\n@@ -47,6 +48,8 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \tstruct remote *remote;\n \tstruct transport *transport;\n \tconst struct ref *ref;\n+\tstruct ref_array array;\n+\tstatic struct ref_sorting *sorting = NULL, **sorting_tail = &sorting;\n \n \tstruct option options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"do not print remote URL\")),\n@@ -60,6 +63,8 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \t\tOPT_BIT(0, \"refs\", &flags, N_(\"do not show peeled tags\"), REF_NORMAL),\n \t\tOPT_BOOL(0, \"get-url\", &get_url,\n \t\t\t N_(\"take url.<base>.insteadOf into account\")),\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\tOPT_SET_INT_F(0, \"exit-code\", &status,\n \t\t\t      N_(\"exit with exit code 2 if no matching refs are found\"),\n \t\t\t      2, PARSE_OPT_NOCOMPLETE),\n@@ -68,6 +73,8 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \t\tOPT_END()\n \t};\n \n+\tmemset(&array, 0, sizeof(array));\n+\n \targc = parse_options(argc, argv, prefix, options, ls_remote_usage,\n \t\t\t     PARSE_OPT_STOP_AT_NON_OPTION);\n \tdest = argv[0];\n@@ -104,13 +111,28 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \tif (!dest && !quiet)\n \t\tfprintf(stderr, \"From %s\\n\", *remote->url);\n \tfor ( ; ref; ref = ref->next) {\n+\t\tstruct ref_array_item *item;\n \t\tif (!check_ref_type(ref, flags))\n \t\t\tcontinue;\n \t\tif (!tail_match(pattern, ref->name))\n \t\t\tcontinue;\n+\n+\t\tFLEX_ALLOC_MEM(item, refname, ref->name, strlen(ref->name));\n+\t\titem->symref = ref->symref;\n+\t\titem->objectname = ref->old_oid;\n+\n+\t\tREALLOC_ARRAY(array.items, array.nr + 1);\n+\t\tarray.items[array.nr++] = item;\n+\t}\n+\n+\tif (sorting)\n+\t\tref_array_sort(sorting, &array);\n+\n+\tfor (int i = 0; i < array.nr; i++) {\n+\t\tconst struct ref_array_item *ref = array.items[i];\n \t\tif (show_symref_target && ref->symref)\n-\t\t\tprintf(\"ref: %s\\t%s\\n\", ref->symref, ref->name);\n-\t\tprintf(\"%s\\t%s\\n\", oid_to_hex(&ref->old_oid), ref->name);\n+\t\t\tprintf(\"ref: %s\\t%s\\n\", ref->symref, ref->refname);\n+\t\tprintf(\"%s\\t%s\\n\", oid_to_hex(&ref->objectname), ref->refname);\n \t\tstatus = 0; /* we found something */\n \t}\n \treturn status;\ndiff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh\nindex 02106c922..66370cd88 100755\n--- a/t/t5512-ls-remote.sh\n+++ b/t/t5512-ls-remote.sh\n@@ -10,6 +10,9 @@ test_expect_success setup '\n \ttest_tick &&\n \tgit commit -m initial &&\n \tgit tag mark &&\n+\tgit tag mark1.1 &&\n+\tgit tag mark1.2 &&\n+\tgit tag mark1.10 &&\n \tgit show-ref --tags -d | sed -e \"s/ /\t/\" >expected.tag &&\n \t(\n \t\techo \"$(git rev-parse HEAD)\tHEAD\"\n@@ -39,6 +42,39 @@ test_expect_success 'ls-remote self' '\n \ttest_cmp expected.all actual\n '\n \n+test_expect_success 'ls-remote --sort=\"version:refname\" --tags self' '\n+\tcat >expect <<-\\EOF &&\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.1\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.2\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.10\n+\tEOF\n+\tgit ls-remote --sort=\"version:refname\" --tags self >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'ls-remote --sort=\"-version:refname\" --tags self' '\n+\tcat >expect <<-\\EOF &&\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.10\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.2\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.1\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark\n+\tEOF\n+\tgit ls-remote --sort=\"-version:refname\" --tags self >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'ls-remote --sort=\"-refname\" --tags self' '\n+\tcat >expect <<-\\EOF &&\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.2\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.10\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.1\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark\n+\tEOF\n+\tgit ls-remote --sort=\"-refname\" --tags self >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_expect_success 'dies when no remote specified and no default remotes found' '\n \ttest_must_fail git ls-remote\n '\n@@ -131,7 +167,7 @@ test_expect_success 'Report no-match with --exit-code' '\n \n test_expect_success 'Report match with --exit-code' '\n \tgit ls-remote --exit-code other.git \"refs/tags/*\" >actual &&\n-\tgit ls-remote . tags/mark >expect &&\n+\tgit ls-remote . tags/mark* >expect &&\n \ttest_cmp expect actual\n '\n \n@@ -178,6 +214,9 @@ test_expect_success 'ls-remote --symref' '\n \t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/remotes/origin/HEAD\n \t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/remotes/origin/master\n \t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.1\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.10\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.2\n \tEOF\n \tgit ls-remote --symref >actual &&\n \ttest_cmp expect actual\n-- \n2.14.3 (Apple Git-98)\n\n"},{"id":"343642","messageId":"CAPig+cRTcY+XNedi=PdfRWpWR-LTAVvR4kkKkrs1e58LLYd3-Q@mail.gmail.com","threadId":"48197","inReplyTo":"20180402221124.88049-1-haraldnordgren@gmail.com","subject":"Re: [PATCH v5] ls-remote: create '--sort' option","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2018-04-02T22:53:32Z","receivedAt":"2018-04-02T22:53:38Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Mon, Apr 2, 2018 at 6:11 PM, Harald Nordgren\n<haraldnordgren@gmail.com> wrote:\n> Create a '--sort' option for ls-remote, based on the one from\n> for-each-ref. This e.g. allows ref names to be sorted by version\n> semantics, so that v1.2 is sorted before v1.10.\n>\n> Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com>\n> ---\n\nPlease take pity on reviewers and use this space below the \"---\" line\nfollowing your sign-off to explain what changed since the previous\nattempt and to provide a link to the previous round(s), like this[1].\nThanks.\n\n[1]: https://www.youtube.com/watch?v=r_8ydghbGSg\n\n>  Documentation/git-ls-remote.txt | 12 +++++++++++-\n>  builtin/ls-remote.c             | 26 ++++++++++++++++++++++++--\n>  t/t5512-ls-remote.sh            | 41 ++++++++++++++++++++++++++++++++++++++++-\n>  3 files changed, 75 insertions(+), 4 deletions(-)\n"},{"id":"343643","messageId":"CAPig+cQ4=aft738gxngHDGB+ZZPFFCmve=D6ExRg_F3jr8634g@mail.gmail.com","threadId":"48197","inReplyTo":"CAPig+cRTcY+XNedi=PdfRWpWR-LTAVvR4kkKkrs1e58LLYd3-Q@mail.gmail.com","subject":"Re: [PATCH v5] ls-remote: create '--sort' option","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2018-04-02T22:54:59Z","receivedAt":"2018-04-02T22:55:12Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Mon, Apr 2, 2018 at 6:53 PM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n> On Mon, Apr 2, 2018 at 6:11 PM, Harald Nordgren\n> <haraldnordgren@gmail.com> wrote:\n>> Create a '--sort' option for ls-remote, based on the one from\n>> for-each-ref. This e.g. allows ref names to be sorted by version\n>> semantics, so that v1.2 is sorted before v1.10.\n>>\n>> Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com>\n>> ---\n>\n> Please take pity on reviewers and use this space below the \"---\" line\n> following your sign-off to explain what changed since the previous\n> attempt and to provide a link to the previous round(s), like this[1].\n> Thanks.\n>\n> [1]: https://www.youtube.com/watch?v=r_8ydghbGSg\n\nOr, like this if we want to be really accurate[1].\n\n[1]: https://public-inbox.org/git/20180402210523.83293-1-haraldnordgren@gmail.com/\n"},{"id":"343652","messageId":"20180403004818.91941-1-haraldnordgren@gmail.com","threadId":"48197","inReplyTo":"CAHwyqnV8tB63gQFVJhyNtr304Uv1TwWvYiX+3wuU0fDFhOphgg@mail.gmail.com","subject":"[PATCH v6] ls-remote: create '--sort' option","fromName":"Harald Nordgren","fromEmail":"haraldnordgren@gmail.com","sentAt":"2018-04-03T00:48:18Z","receivedAt":"2018-04-03T00:48:42Z","isPatch":true,"sender":{"key":"haraldnordgren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9569897?v=4"},"body":"Create a '--sort' option for ls-remote, based on the one from\nfor-each-ref. This e.g. allows ref names to be sorted by version\nsemantics, so that v1.2 is sorted before v1.10.\n\nSigned-off-by: Harald Nordgren <haraldnordgren@gmail.com>\n---\n\nNotes:\n    Moving 'int i' declaration outside of 'for' loop init\n\n Documentation/git-ls-remote.txt | 12 +++++++++++-\n builtin/ls-remote.c             | 27 +++++++++++++++++++++++++--\n t/t5512-ls-remote.sh            | 41 ++++++++++++++++++++++++++++++++++++++++-\n 3 files changed, 76 insertions(+), 4 deletions(-)\n\ndiff --git a/Documentation/git-ls-remote.txt b/Documentation/git-ls-remote.txt\nindex 5f2628c8f..17fae7218 100644\n--- a/Documentation/git-ls-remote.txt\n+++ b/Documentation/git-ls-remote.txt\n@@ -10,7 +10,7 @@ SYNOPSIS\n --------\n [verse]\n 'git ls-remote' [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n-\t      [-q | --quiet] [--exit-code] [--get-url]\n+\t      [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n \t      [--symref] [<repository> [<refs>...]]\n \n DESCRIPTION\n@@ -60,6 +60,16 @@ OPTIONS\n \tupload-pack only shows the symref HEAD, so it will be the only\n \tone shown by ls-remote.\n \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 \"versionsort.suffix\"\n+\tconfiguration variable.\n+\tThe keys supported are the same as those in `git for-each-ref`.\n+\n <repository>::\n \tThe \"remote\" repository to query.  This parameter can be\n \teither a URL or the name of a remote (see the GIT URLS and\ndiff --git a/builtin/ls-remote.c b/builtin/ls-remote.c\nindex 540d56429..113a2fd7d 100644\n--- a/builtin/ls-remote.c\n+++ b/builtin/ls-remote.c\n@@ -1,6 +1,7 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n #include \"transport.h\"\n+#include \"ref-filter.h\"\n #include \"remote.h\"\n \n static const char * const ls_remote_usage[] = {\n@@ -43,10 +44,13 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \tint show_symref_target = 0;\n \tconst char *uploadpack = NULL;\n \tconst char **pattern = NULL;\n+\tint i;\n \n \tstruct remote *remote;\n \tstruct transport *transport;\n \tconst struct ref *ref;\n+\tstruct ref_array array;\n+\tstatic struct ref_sorting *sorting = NULL, **sorting_tail = &sorting;\n \n \tstruct option options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"do not print remote URL\")),\n@@ -60,6 +64,8 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \t\tOPT_BIT(0, \"refs\", &flags, N_(\"do not show peeled tags\"), REF_NORMAL),\n \t\tOPT_BOOL(0, \"get-url\", &get_url,\n \t\t\t N_(\"take url.<base>.insteadOf into account\")),\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\tOPT_SET_INT_F(0, \"exit-code\", &status,\n \t\t\t      N_(\"exit with exit code 2 if no matching refs are found\"),\n \t\t\t      2, PARSE_OPT_NOCOMPLETE),\n@@ -68,6 +74,8 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \t\tOPT_END()\n \t};\n \n+\tmemset(&array, 0, sizeof(array));\n+\n \targc = parse_options(argc, argv, prefix, options, ls_remote_usage,\n \t\t\t     PARSE_OPT_STOP_AT_NON_OPTION);\n \tdest = argv[0];\n@@ -104,13 +112,28 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \tif (!dest && !quiet)\n \t\tfprintf(stderr, \"From %s\\n\", *remote->url);\n \tfor ( ; ref; ref = ref->next) {\n+\t\tstruct ref_array_item *item;\n \t\tif (!check_ref_type(ref, flags))\n \t\t\tcontinue;\n \t\tif (!tail_match(pattern, ref->name))\n \t\t\tcontinue;\n+\n+\t\tFLEX_ALLOC_MEM(item, refname, ref->name, strlen(ref->name));\n+\t\titem->symref = ref->symref;\n+\t\titem->objectname = ref->old_oid;\n+\n+\t\tREALLOC_ARRAY(array.items, array.nr + 1);\n+\t\tarray.items[array.nr++] = item;\n+\t}\n+\n+\tif (sorting)\n+\t\tref_array_sort(sorting, &array);\n+\n+\tfor (i = 0; i < array.nr; i++) {\n+\t\tconst struct ref_array_item *ref = array.items[i];\n \t\tif (show_symref_target && ref->symref)\n-\t\t\tprintf(\"ref: %s\\t%s\\n\", ref->symref, ref->name);\n-\t\tprintf(\"%s\\t%s\\n\", oid_to_hex(&ref->old_oid), ref->name);\n+\t\t\tprintf(\"ref: %s\\t%s\\n\", ref->symref, ref->refname);\n+\t\tprintf(\"%s\\t%s\\n\", oid_to_hex(&ref->objectname), ref->refname);\n \t\tstatus = 0; /* we found something */\n \t}\n \treturn status;\ndiff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh\nindex 02106c922..66370cd88 100755\n--- a/t/t5512-ls-remote.sh\n+++ b/t/t5512-ls-remote.sh\n@@ -10,6 +10,9 @@ test_expect_success setup '\n \ttest_tick &&\n \tgit commit -m initial &&\n \tgit tag mark &&\n+\tgit tag mark1.1 &&\n+\tgit tag mark1.2 &&\n+\tgit tag mark1.10 &&\n \tgit show-ref --tags -d | sed -e \"s/ /\t/\" >expected.tag &&\n \t(\n \t\techo \"$(git rev-parse HEAD)\tHEAD\"\n@@ -39,6 +42,39 @@ test_expect_success 'ls-remote self' '\n \ttest_cmp expected.all actual\n '\n \n+test_expect_success 'ls-remote --sort=\"version:refname\" --tags self' '\n+\tcat >expect <<-\\EOF &&\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.1\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.2\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.10\n+\tEOF\n+\tgit ls-remote --sort=\"version:refname\" --tags self >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'ls-remote --sort=\"-version:refname\" --tags self' '\n+\tcat >expect <<-\\EOF &&\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.10\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.2\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.1\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark\n+\tEOF\n+\tgit ls-remote --sort=\"-version:refname\" --tags self >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'ls-remote --sort=\"-refname\" --tags self' '\n+\tcat >expect <<-\\EOF &&\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.2\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.10\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.1\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark\n+\tEOF\n+\tgit ls-remote --sort=\"-refname\" --tags self >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_expect_success 'dies when no remote specified and no default remotes found' '\n \ttest_must_fail git ls-remote\n '\n@@ -131,7 +167,7 @@ test_expect_success 'Report no-match with --exit-code' '\n \n test_expect_success 'Report match with --exit-code' '\n \tgit ls-remote --exit-code other.git \"refs/tags/*\" >actual &&\n-\tgit ls-remote . tags/mark >expect &&\n+\tgit ls-remote . tags/mark* >expect &&\n \ttest_cmp expect actual\n '\n \n@@ -178,6 +214,9 @@ test_expect_success 'ls-remote --symref' '\n \t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/remotes/origin/HEAD\n \t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/remotes/origin/master\n \t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.1\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.10\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.2\n \tEOF\n \tgit ls-remote --symref >actual &&\n \ttest_cmp expect actual\n-- \n2.14.3 (Apple Git-98)\n\n"},{"id":"343794","messageId":"20180404171153.4126-1-haraldnordgren@gmail.com","threadId":"48197","inReplyTo":"20180402005248.52418-1-haraldnordgren@gmail.com","subject":"[PATCH v7] ls-remote: create '--sort' option","fromName":"Harald Nordgren","fromEmail":"haraldnordgren@gmail.com","sentAt":"2018-04-04T17:11:53Z","receivedAt":"2018-04-04T17:12:17Z","isPatch":true,"sender":{"key":"haraldnordgren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9569897?v=4"},"body":"Create a '--sort' option for ls-remote, based on the one from\nfor-each-ref. This e.g. allows ref names to be sorted by version\nsemantics, so that v1.2 is sorted before v1.10.\n\nSigned-off-by: Harald Nordgren <haraldnordgren@gmail.com>\n---\n\nNotes:\n    Started using 'ALLOC_GROW'\n\n Documentation/git-ls-remote.txt | 12 +++++++++++-\n builtin/ls-remote.c             | 27 +++++++++++++++++++++++++--\n t/t5512-ls-remote.sh            | 41 ++++++++++++++++++++++++++++++++++++++++-\n 3 files changed, 76 insertions(+), 4 deletions(-)\n\ndiff --git a/Documentation/git-ls-remote.txt b/Documentation/git-ls-remote.txt\nindex 5f2628c8f..17fae7218 100644\n--- a/Documentation/git-ls-remote.txt\n+++ b/Documentation/git-ls-remote.txt\n@@ -10,7 +10,7 @@ SYNOPSIS\n --------\n [verse]\n 'git ls-remote' [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n-\t      [-q | --quiet] [--exit-code] [--get-url]\n+\t      [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n \t      [--symref] [<repository> [<refs>...]]\n \n DESCRIPTION\n@@ -60,6 +60,16 @@ OPTIONS\n \tupload-pack only shows the symref HEAD, so it will be the only\n \tone shown by ls-remote.\n \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 \"versionsort.suffix\"\n+\tconfiguration variable.\n+\tThe keys supported are the same as those in `git for-each-ref`.\n+\n <repository>::\n \tThe \"remote\" repository to query.  This parameter can be\n \teither a URL or the name of a remote (see the GIT URLS and\ndiff --git a/builtin/ls-remote.c b/builtin/ls-remote.c\nindex 540d56429..5bb8ee68a 100644\n--- a/builtin/ls-remote.c\n+++ b/builtin/ls-remote.c\n@@ -1,6 +1,7 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n #include \"transport.h\"\n+#include \"ref-filter.h\"\n #include \"remote.h\"\n \n static const char * const ls_remote_usage[] = {\n@@ -43,10 +44,13 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \tint show_symref_target = 0;\n \tconst char *uploadpack = NULL;\n \tconst char **pattern = NULL;\n+\tint i;\n \n \tstruct remote *remote;\n \tstruct transport *transport;\n \tconst struct ref *ref;\n+\tstruct ref_array array;\n+\tstatic struct ref_sorting *sorting = NULL, **sorting_tail = &sorting;\n \n \tstruct option options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"do not print remote URL\")),\n@@ -60,6 +64,8 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \t\tOPT_BIT(0, \"refs\", &flags, N_(\"do not show peeled tags\"), REF_NORMAL),\n \t\tOPT_BOOL(0, \"get-url\", &get_url,\n \t\t\t N_(\"take url.<base>.insteadOf into account\")),\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\tOPT_SET_INT_F(0, \"exit-code\", &status,\n \t\t\t      N_(\"exit with exit code 2 if no matching refs are found\"),\n \t\t\t      2, PARSE_OPT_NOCOMPLETE),\n@@ -68,6 +74,8 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \t\tOPT_END()\n \t};\n \n+\tmemset(&array, 0, sizeof(array));\n+\n \targc = parse_options(argc, argv, prefix, options, ls_remote_usage,\n \t\t\t     PARSE_OPT_STOP_AT_NON_OPTION);\n \tdest = argv[0];\n@@ -104,13 +112,28 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \tif (!dest && !quiet)\n \t\tfprintf(stderr, \"From %s\\n\", *remote->url);\n \tfor ( ; ref; ref = ref->next) {\n+\t\tstruct ref_array_item *item;\n \t\tif (!check_ref_type(ref, flags))\n \t\t\tcontinue;\n \t\tif (!tail_match(pattern, ref->name))\n \t\t\tcontinue;\n+\n+\t\tFLEX_ALLOC_MEM(item, refname, ref->name, strlen(ref->name));\n+\t\titem->symref = ref->symref;\n+\t\titem->objectname = ref->old_oid;\n+\n+\t\tALLOC_GROW(array.items, array.nr + 1, array.alloc);\n+\t\tarray.items[array.nr++] = item;\n+\t}\n+\n+\tif (sorting)\n+\t\tref_array_sort(sorting, &array);\n+\n+\tfor (i = 0; i < array.nr; i++) {\n+\t\tconst struct ref_array_item *ref = array.items[i];\n \t\tif (show_symref_target && ref->symref)\n-\t\t\tprintf(\"ref: %s\\t%s\\n\", ref->symref, ref->name);\n-\t\tprintf(\"%s\\t%s\\n\", oid_to_hex(&ref->old_oid), ref->name);\n+\t\t\tprintf(\"ref: %s\\t%s\\n\", ref->symref, ref->refname);\n+\t\tprintf(\"%s\\t%s\\n\", oid_to_hex(&ref->objectname), ref->refname);\n \t\tstatus = 0; /* we found something */\n \t}\n \treturn status;\ndiff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh\nindex 02106c922..66370cd88 100755\n--- a/t/t5512-ls-remote.sh\n+++ b/t/t5512-ls-remote.sh\n@@ -10,6 +10,9 @@ test_expect_success setup '\n \ttest_tick &&\n \tgit commit -m initial &&\n \tgit tag mark &&\n+\tgit tag mark1.1 &&\n+\tgit tag mark1.2 &&\n+\tgit tag mark1.10 &&\n \tgit show-ref --tags -d | sed -e \"s/ /\t/\" >expected.tag &&\n \t(\n \t\techo \"$(git rev-parse HEAD)\tHEAD\"\n@@ -39,6 +42,39 @@ test_expect_success 'ls-remote self' '\n \ttest_cmp expected.all actual\n '\n \n+test_expect_success 'ls-remote --sort=\"version:refname\" --tags self' '\n+\tcat >expect <<-\\EOF &&\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.1\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.2\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.10\n+\tEOF\n+\tgit ls-remote --sort=\"version:refname\" --tags self >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'ls-remote --sort=\"-version:refname\" --tags self' '\n+\tcat >expect <<-\\EOF &&\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.10\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.2\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.1\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark\n+\tEOF\n+\tgit ls-remote --sort=\"-version:refname\" --tags self >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'ls-remote --sort=\"-refname\" --tags self' '\n+\tcat >expect <<-\\EOF &&\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.2\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.10\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.1\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark\n+\tEOF\n+\tgit ls-remote --sort=\"-refname\" --tags self >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_expect_success 'dies when no remote specified and no default remotes found' '\n \ttest_must_fail git ls-remote\n '\n@@ -131,7 +167,7 @@ test_expect_success 'Report no-match with --exit-code' '\n \n test_expect_success 'Report match with --exit-code' '\n \tgit ls-remote --exit-code other.git \"refs/tags/*\" >actual &&\n-\tgit ls-remote . tags/mark >expect &&\n+\tgit ls-remote . tags/mark* >expect &&\n \ttest_cmp expect actual\n '\n \n@@ -178,6 +214,9 @@ test_expect_success 'ls-remote --symref' '\n \t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/remotes/origin/HEAD\n \t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/remotes/origin/master\n \t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.1\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.10\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.2\n \tEOF\n \tgit ls-remote --symref >actual &&\n \ttest_cmp expect actual\n-- \n2.14.3 (Apple Git-98)\n\n"},{"id":"343795","messageId":"CAHwyqnXtc-WgynCmE+EEVYtg6RRVweK8vwfBQS5VL4ygaFumKQ@mail.gmail.com","threadId":"48197","inReplyTo":"20180404171153.4126-1-haraldnordgren@gmail.com","subject":"Re: [PATCH v7] ls-remote: create '--sort' option","fromName":"Harald Nordgren","fromEmail":"haraldnordgren@gmail.com","sentAt":"2018-04-04T17:18:42Z","receivedAt":"2018-04-04T17:19:28Z","isPatch":true,"sender":{"key":"haraldnordgren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9569897?v=4"},"body":"I updated the code to use 'ALLOC_GROW'. I makes sense, I now I realize\nwhy array.alloc is there ;)\n\nJeff, you are right that 'git ls-remote --sort=committerdate' will not\nwork. Do you think we need to do something about this, or it's fine\nthat it fails the way you showed?\n\nOn Wed, Apr 4, 2018 at 7:11 PM, Harald Nordgren\n<haraldnordgren@gmail.com> wrote:\n> Create a '--sort' option for ls-remote, based on the one from\n> for-each-ref. This e.g. allows ref names to be sorted by version\n> semantics, so that v1.2 is sorted before v1.10.\n>\n> Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com>\n> ---\n>\n> Notes:\n>     Started using 'ALLOC_GROW'\n>\n>  Documentation/git-ls-remote.txt | 12 +++++++++++-\n>  builtin/ls-remote.c             | 27 +++++++++++++++++++++++++--\n>  t/t5512-ls-remote.sh            | 41 ++++++++++++++++++++++++++++++++++++++++-\n>  3 files changed, 76 insertions(+), 4 deletions(-)\n>\n> diff --git a/Documentation/git-ls-remote.txt b/Documentation/git-ls-remote.txt\n> index 5f2628c8f..17fae7218 100644\n> --- a/Documentation/git-ls-remote.txt\n> +++ b/Documentation/git-ls-remote.txt\n> @@ -10,7 +10,7 @@ SYNOPSIS\n>  --------\n>  [verse]\n>  'git ls-remote' [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n> -             [-q | --quiet] [--exit-code] [--get-url]\n> +             [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n>               [--symref] [<repository> [<refs>...]]\n>\n>  DESCRIPTION\n> @@ -60,6 +60,16 @@ OPTIONS\n>         upload-pack only shows the symref HEAD, so it will be the only\n>         one shown by ls-remote.\n>\n> +--sort=<key>::\n> +       Sort based on the key given.  Prefix `-` to sort in\n> +       descending order of the value. You may use the --sort=<key> option\n> +       multiple times, in which case the last key becomes the primary\n> +       key. Also supports \"version:refname\" or \"v:refname\" (tag\n> +       names are treated as versions). The \"version:refname\" sort\n> +       order can also be affected by the \"versionsort.suffix\"\n> +       configuration variable.\n> +       The keys supported are the same as those in `git for-each-ref`.\n> +\n>  <repository>::\n>         The \"remote\" repository to query.  This parameter can be\n>         either a URL or the name of a remote (see the GIT URLS and\n> diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c\n> index 540d56429..5bb8ee68a 100644\n> --- a/builtin/ls-remote.c\n> +++ b/builtin/ls-remote.c\n> @@ -1,6 +1,7 @@\n>  #include \"builtin.h\"\n>  #include \"cache.h\"\n>  #include \"transport.h\"\n> +#include \"ref-filter.h\"\n>  #include \"remote.h\"\n>\n>  static const char * const ls_remote_usage[] = {\n> @@ -43,10 +44,13 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n>         int show_symref_target = 0;\n>         const char *uploadpack = NULL;\n>         const char **pattern = NULL;\n> +       int i;\n>\n>         struct remote *remote;\n>         struct transport *transport;\n>         const struct ref *ref;\n> +       struct ref_array array;\n> +       static struct ref_sorting *sorting = NULL, **sorting_tail = &sorting;\n>\n>         struct option options[] = {\n>                 OPT__QUIET(&quiet, N_(\"do not print remote URL\")),\n> @@ -60,6 +64,8 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n>                 OPT_BIT(0, \"refs\", &flags, N_(\"do not show peeled tags\"), REF_NORMAL),\n>                 OPT_BOOL(0, \"get-url\", &get_url,\n>                          N_(\"take url.<base>.insteadOf into account\")),\n> +               OPT_CALLBACK(0 , \"sort\", sorting_tail, N_(\"key\"),\n> +                            N_(\"field name to sort on\"), &parse_opt_ref_sorting),\n>                 OPT_SET_INT_F(0, \"exit-code\", &status,\n>                               N_(\"exit with exit code 2 if no matching refs are found\"),\n>                               2, PARSE_OPT_NOCOMPLETE),\n> @@ -68,6 +74,8 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n>                 OPT_END()\n>         };\n>\n> +       memset(&array, 0, sizeof(array));\n> +\n>         argc = parse_options(argc, argv, prefix, options, ls_remote_usage,\n>                              PARSE_OPT_STOP_AT_NON_OPTION);\n>         dest = argv[0];\n> @@ -104,13 +112,28 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n>         if (!dest && !quiet)\n>                 fprintf(stderr, \"From %s\\n\", *remote->url);\n>         for ( ; ref; ref = ref->next) {\n> +               struct ref_array_item *item;\n>                 if (!check_ref_type(ref, flags))\n>                         continue;\n>                 if (!tail_match(pattern, ref->name))\n>                         continue;\n> +\n> +               FLEX_ALLOC_MEM(item, refname, ref->name, strlen(ref->name));\n> +               item->symref = ref->symref;\n> +               item->objectname = ref->old_oid;\n> +\n> +               ALLOC_GROW(array.items, array.nr + 1, array.alloc);\n> +               array.items[array.nr++] = item;\n> +       }\n> +\n> +       if (sorting)\n> +               ref_array_sort(sorting, &array);\n> +\n> +       for (i = 0; i < array.nr; i++) {\n> +               const struct ref_array_item *ref = array.items[i];\n>                 if (show_symref_target && ref->symref)\n> -                       printf(\"ref: %s\\t%s\\n\", ref->symref, ref->name);\n> -               printf(\"%s\\t%s\\n\", oid_to_hex(&ref->old_oid), ref->name);\n> +                       printf(\"ref: %s\\t%s\\n\", ref->symref, ref->refname);\n> +               printf(\"%s\\t%s\\n\", oid_to_hex(&ref->objectname), ref->refname);\n>                 status = 0; /* we found something */\n>         }\n>         return status;\n> diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh\n> index 02106c922..66370cd88 100755\n> --- a/t/t5512-ls-remote.sh\n> +++ b/t/t5512-ls-remote.sh\n> @@ -10,6 +10,9 @@ test_expect_success setup '\n>         test_tick &&\n>         git commit -m initial &&\n>         git tag mark &&\n> +       git tag mark1.1 &&\n> +       git tag mark1.2 &&\n> +       git tag mark1.10 &&\n>         git show-ref --tags -d | sed -e \"s/ /   /\" >expected.tag &&\n>         (\n>                 echo \"$(git rev-parse HEAD)     HEAD\"\n> @@ -39,6 +42,39 @@ test_expect_success 'ls-remote self' '\n>         test_cmp expected.all actual\n>  '\n>\n> +test_expect_success 'ls-remote --sort=\"version:refname\" --tags self' '\n> +       cat >expect <<-\\EOF &&\n> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark\n> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark1.1\n> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark1.2\n> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark1.10\n> +       EOF\n> +       git ls-remote --sort=\"version:refname\" --tags self >actual &&\n> +       test_cmp expect actual\n> +'\n> +\n> +test_expect_success 'ls-remote --sort=\"-version:refname\" --tags self' '\n> +       cat >expect <<-\\EOF &&\n> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark1.10\n> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark1.2\n> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark1.1\n> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark\n> +       EOF\n> +       git ls-remote --sort=\"-version:refname\" --tags self >actual &&\n> +       test_cmp expect actual\n> +'\n> +\n> +test_expect_success 'ls-remote --sort=\"-refname\" --tags self' '\n> +       cat >expect <<-\\EOF &&\n> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark1.2\n> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark1.10\n> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark1.1\n> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark\n> +       EOF\n> +       git ls-remote --sort=\"-refname\" --tags self >actual &&\n> +       test_cmp expect actual\n> +'\n> +\n>  test_expect_success 'dies when no remote specified and no default remotes found' '\n>         test_must_fail git ls-remote\n>  '\n> @@ -131,7 +167,7 @@ test_expect_success 'Report no-match with --exit-code' '\n>\n>  test_expect_success 'Report match with --exit-code' '\n>         git ls-remote --exit-code other.git \"refs/tags/*\" >actual &&\n> -       git ls-remote . tags/mark >expect &&\n> +       git ls-remote . tags/mark* >expect &&\n>         test_cmp expect actual\n>  '\n>\n> @@ -178,6 +214,9 @@ test_expect_success 'ls-remote --symref' '\n>         1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/remotes/origin/HEAD\n>         1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/remotes/origin/master\n>         1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark\n> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark1.1\n> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark1.10\n> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark1.2\n>         EOF\n>         git ls-remote --symref >actual &&\n>         test_cmp expect actual\n> --\n> 2.14.3 (Apple Git-98)\n>\n"},{"id":"343797","messageId":"CAHwyqnX614p+xbmUBLJwY2yK1gOddRuzEM806z1Fu1VPU8rzJw@mail.gmail.com","threadId":"48197","inReplyTo":"CAHwyqnXtc-WgynCmE+EEVYtg6RRVweK8vwfBQS5VL4ygaFumKQ@mail.gmail.com","subject":"Re: [PATCH v7] ls-remote: create '--sort' option","fromName":"Harald Nordgren","fromEmail":"haraldnordgren@gmail.com","sentAt":"2018-04-04T17:47:09Z","receivedAt":"2018-04-04T17:47:56Z","isPatch":true,"sender":{"key":"haraldnordgren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9569897?v=4"},"body":"Links to previous revisions:\n\n[1] https://public-inbox.org/git/20180402174614.GA28566@sigill.intra.peff.net/T/#m108fe8c83f3558afaea8e317e680f7eaa136e9a9\n[2] https://public-inbox.org/git/20180402211920.GA32099@sigill.intra.peff.net/T/#ma9ec4e0ce664160086e535c012e20d76822c60e5\n...\n[4] https://public-inbox.org/git/20180402174614.GA28566@sigill.intra.peff.net/T/#maa02c40c87b192e56c370c312098d469c9fce757\n[5] https://public-inbox.org/git/20180402174614.GA28566@sigill.intra.peff.net/T/#m52cdbbbba3f359e1257e7bdfe19cd9a26f55fa20\n[6] https://public-inbox.org/git/20180402174614.GA28566@sigill.intra.peff.net/T/#m6d3ce17f0f6dabeddaf03336c92512b7c413422b\n\nOn Wed, Apr 4, 2018 at 7:18 PM, Harald Nordgren\n<haraldnordgren@gmail.com> wrote:\n> I updated the code to use 'ALLOC_GROW'. I makes sense, I now I realize\n> why array.alloc is there ;)\n>\n> Jeff, you are right that 'git ls-remote --sort=committerdate' will not\n> work. Do you think we need to do something about this, or it's fine\n> that it fails the way you showed?\n>\n> On Wed, Apr 4, 2018 at 7:11 PM, Harald Nordgren\n> <haraldnordgren@gmail.com> wrote:\n>> Create a '--sort' option for ls-remote, based on the one from\n>> for-each-ref. This e.g. allows ref names to be sorted by version\n>> semantics, so that v1.2 is sorted before v1.10.\n>>\n>> Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com>\n>> ---\n>>\n>> Notes:\n>>     Started using 'ALLOC_GROW'\n>>\n>>  Documentation/git-ls-remote.txt | 12 +++++++++++-\n>>  builtin/ls-remote.c             | 27 +++++++++++++++++++++++++--\n>>  t/t5512-ls-remote.sh            | 41 ++++++++++++++++++++++++++++++++++++++++-\n>>  3 files changed, 76 insertions(+), 4 deletions(-)\n>>\n>> diff --git a/Documentation/git-ls-remote.txt b/Documentation/git-ls-remote.txt\n>> index 5f2628c8f..17fae7218 100644\n>> --- a/Documentation/git-ls-remote.txt\n>> +++ b/Documentation/git-ls-remote.txt\n>> @@ -10,7 +10,7 @@ SYNOPSIS\n>>  --------\n>>  [verse]\n>>  'git ls-remote' [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n>> -             [-q | --quiet] [--exit-code] [--get-url]\n>> +             [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n>>               [--symref] [<repository> [<refs>...]]\n>>\n>>  DESCRIPTION\n>> @@ -60,6 +60,16 @@ OPTIONS\n>>         upload-pack only shows the symref HEAD, so it will be the only\n>>         one shown by ls-remote.\n>>\n>> +--sort=<key>::\n>> +       Sort based on the key given.  Prefix `-` to sort in\n>> +       descending order of the value. You may use the --sort=<key> option\n>> +       multiple times, in which case the last key becomes the primary\n>> +       key. Also supports \"version:refname\" or \"v:refname\" (tag\n>> +       names are treated as versions). The \"version:refname\" sort\n>> +       order can also be affected by the \"versionsort.suffix\"\n>> +       configuration variable.\n>> +       The keys supported are the same as those in `git for-each-ref`.\n>> +\n>>  <repository>::\n>>         The \"remote\" repository to query.  This parameter can be\n>>         either a URL or the name of a remote (see the GIT URLS and\n>> diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c\n>> index 540d56429..5bb8ee68a 100644\n>> --- a/builtin/ls-remote.c\n>> +++ b/builtin/ls-remote.c\n>> @@ -1,6 +1,7 @@\n>>  #include \"builtin.h\"\n>>  #include \"cache.h\"\n>>  #include \"transport.h\"\n>> +#include \"ref-filter.h\"\n>>  #include \"remote.h\"\n>>\n>>  static const char * const ls_remote_usage[] = {\n>> @@ -43,10 +44,13 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n>>         int show_symref_target = 0;\n>>         const char *uploadpack = NULL;\n>>         const char **pattern = NULL;\n>> +       int i;\n>>\n>>         struct remote *remote;\n>>         struct transport *transport;\n>>         const struct ref *ref;\n>> +       struct ref_array array;\n>> +       static struct ref_sorting *sorting = NULL, **sorting_tail = &sorting;\n>>\n>>         struct option options[] = {\n>>                 OPT__QUIET(&quiet, N_(\"do not print remote URL\")),\n>> @@ -60,6 +64,8 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n>>                 OPT_BIT(0, \"refs\", &flags, N_(\"do not show peeled tags\"), REF_NORMAL),\n>>                 OPT_BOOL(0, \"get-url\", &get_url,\n>>                          N_(\"take url.<base>.insteadOf into account\")),\n>> +               OPT_CALLBACK(0 , \"sort\", sorting_tail, N_(\"key\"),\n>> +                            N_(\"field name to sort on\"), &parse_opt_ref_sorting),\n>>                 OPT_SET_INT_F(0, \"exit-code\", &status,\n>>                               N_(\"exit with exit code 2 if no matching refs are found\"),\n>>                               2, PARSE_OPT_NOCOMPLETE),\n>> @@ -68,6 +74,8 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n>>                 OPT_END()\n>>         };\n>>\n>> +       memset(&array, 0, sizeof(array));\n>> +\n>>         argc = parse_options(argc, argv, prefix, options, ls_remote_usage,\n>>                              PARSE_OPT_STOP_AT_NON_OPTION);\n>>         dest = argv[0];\n>> @@ -104,13 +112,28 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n>>         if (!dest && !quiet)\n>>                 fprintf(stderr, \"From %s\\n\", *remote->url);\n>>         for ( ; ref; ref = ref->next) {\n>> +               struct ref_array_item *item;\n>>                 if (!check_ref_type(ref, flags))\n>>                         continue;\n>>                 if (!tail_match(pattern, ref->name))\n>>                         continue;\n>> +\n>> +               FLEX_ALLOC_MEM(item, refname, ref->name, strlen(ref->name));\n>> +               item->symref = ref->symref;\n>> +               item->objectname = ref->old_oid;\n>> +\n>> +               ALLOC_GROW(array.items, array.nr + 1, array.alloc);\n>> +               array.items[array.nr++] = item;\n>> +       }\n>> +\n>> +       if (sorting)\n>> +               ref_array_sort(sorting, &array);\n>> +\n>> +       for (i = 0; i < array.nr; i++) {\n>> +               const struct ref_array_item *ref = array.items[i];\n>>                 if (show_symref_target && ref->symref)\n>> -                       printf(\"ref: %s\\t%s\\n\", ref->symref, ref->name);\n>> -               printf(\"%s\\t%s\\n\", oid_to_hex(&ref->old_oid), ref->name);\n>> +                       printf(\"ref: %s\\t%s\\n\", ref->symref, ref->refname);\n>> +               printf(\"%s\\t%s\\n\", oid_to_hex(&ref->objectname), ref->refname);\n>>                 status = 0; /* we found something */\n>>         }\n>>         return status;\n>> diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh\n>> index 02106c922..66370cd88 100755\n>> --- a/t/t5512-ls-remote.sh\n>> +++ b/t/t5512-ls-remote.sh\n>> @@ -10,6 +10,9 @@ test_expect_success setup '\n>>         test_tick &&\n>>         git commit -m initial &&\n>>         git tag mark &&\n>> +       git tag mark1.1 &&\n>> +       git tag mark1.2 &&\n>> +       git tag mark1.10 &&\n>>         git show-ref --tags -d | sed -e \"s/ /   /\" >expected.tag &&\n>>         (\n>>                 echo \"$(git rev-parse HEAD)     HEAD\"\n>> @@ -39,6 +42,39 @@ test_expect_success 'ls-remote self' '\n>>         test_cmp expected.all actual\n>>  '\n>>\n>> +test_expect_success 'ls-remote --sort=\"version:refname\" --tags self' '\n>> +       cat >expect <<-\\EOF &&\n>> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark\n>> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark1.1\n>> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark1.2\n>> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark1.10\n>> +       EOF\n>> +       git ls-remote --sort=\"version:refname\" --tags self >actual &&\n>> +       test_cmp expect actual\n>> +'\n>> +\n>> +test_expect_success 'ls-remote --sort=\"-version:refname\" --tags self' '\n>> +       cat >expect <<-\\EOF &&\n>> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark1.10\n>> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark1.2\n>> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark1.1\n>> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark\n>> +       EOF\n>> +       git ls-remote --sort=\"-version:refname\" --tags self >actual &&\n>> +       test_cmp expect actual\n>> +'\n>> +\n>> +test_expect_success 'ls-remote --sort=\"-refname\" --tags self' '\n>> +       cat >expect <<-\\EOF &&\n>> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark1.2\n>> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark1.10\n>> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark1.1\n>> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark\n>> +       EOF\n>> +       git ls-remote --sort=\"-refname\" --tags self >actual &&\n>> +       test_cmp expect actual\n>> +'\n>> +\n>>  test_expect_success 'dies when no remote specified and no default remotes found' '\n>>         test_must_fail git ls-remote\n>>  '\n>> @@ -131,7 +167,7 @@ test_expect_success 'Report no-match with --exit-code' '\n>>\n>>  test_expect_success 'Report match with --exit-code' '\n>>         git ls-remote --exit-code other.git \"refs/tags/*\" >actual &&\n>> -       git ls-remote . tags/mark >expect &&\n>> +       git ls-remote . tags/mark* >expect &&\n>>         test_cmp expect actual\n>>  '\n>>\n>> @@ -178,6 +214,9 @@ test_expect_success 'ls-remote --symref' '\n>>         1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/remotes/origin/HEAD\n>>         1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/remotes/origin/master\n>>         1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark\n>> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark1.1\n>> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark1.10\n>> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark1.2\n>>         EOF\n>>         git ls-remote --symref >actual &&\n>>         test_cmp expect actual\n>> --\n>> 2.14.3 (Apple Git-98)\n>>\n"},{"id":"343803","messageId":"20180404185518.GD9055@sigill.intra.peff.net","threadId":"48197","inReplyTo":"20180404171153.4126-1-haraldnordgren@gmail.com","subject":"Re: [PATCH v7] ls-remote: create '--sort' option","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-04-04T18:55:19Z","receivedAt":"2018-04-04T18:55:38Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Apr 04, 2018 at 07:11:53PM +0200, Harald Nordgren wrote:\n\n> @@ -60,6 +60,16 @@ OPTIONS\n>  \tupload-pack only shows the symref HEAD, so it will be the only\n>  \tone shown by ls-remote.\n>  \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 \"versionsort.suffix\"\n> +\tconfiguration variable.\n> +\tThe keys supported are the same as those in `git for-each-ref`.\n\nWe probably ought to warn the user in that final sentence that keys\nwhich actually look at the objects may not work, since we don't\nnecessarily have the objects.\n\nThere's one other subtlety, which is that things like %(HEAD) assume\nwe're talking about local refs, not the remote HEAD. So that wouldn't\nwork (of course it seems unlikely that anybody woudl _sort_ on that).\n\n> @@ -104,13 +112,28 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n>  \tif (!dest && !quiet)\n>  \t\tfprintf(stderr, \"From %s\\n\", *remote->url);\n>  \tfor ( ; ref; ref = ref->next) {\n> +\t\tstruct ref_array_item *item;\n>  \t\tif (!check_ref_type(ref, flags))\n>  \t\t\tcontinue;\n>  \t\tif (!tail_match(pattern, ref->name))\n>  \t\t\tcontinue;\n> +\n> +\t\tFLEX_ALLOC_MEM(item, refname, ref->name, strlen(ref->name));\n\nI think this can use the slightly-simpler FLEX_ALLOC_STR().\n\n> +\t\titem->symref = ref->symref;\n\nNormally a ref_array_item's symref is an allocated string owned by the\nitem. I don't think it actually matters now, but in the spirit of\nleast-surprise for the future, should this be xstrdup_or_null(ref->symref)?\n\n> +\t\titem->objectname = ref->old_oid;\n\nThis is actually a struct assignment. Which does work, but our usual\nmechanism would be to use \"oidcpy(&item->objectname, &ref->old_oid)\".\n\nAll of this might be a little nicer if ref-filter provided a function to\nallocate a new item. We're pushing the boundaries of ref-filter was\nmeant to be used here, as it was assumed you'd always start with a call\nto filter_refs().\n\n> +\t\tALLOC_GROW(array.items, array.nr + 1, array.alloc);\n> +\t\tarray.items[array.nr++] = item;\n\nThe existing ref-filter code fails to use ALLOC_GROW() correctly. I\ndon't think it actually matters, since we don't intermingle this with\nallocations done there. But perhaps we should be fixing that one while\nwe're looking at it. Or again, maybe it would be nicer still if there\nwere a ref-filter function to do this, and the whole call here could\njust be:\n\n  ref_array_push(&array, ref->name, &ref->old_oid);\n\nOne more drastic alternative is to actually use the existing\nfilter_refs(), and just teach it to populate the array from a list of\nrefs. As you can see from its implementation, it does a few other setup\nsteps. I don't think they matter now, but if you eventually wanted to be\nable to do \"git ls-remote --contains HEAD\", you'd need that setup.\n\n-Peff\n"},{"id":"343804","messageId":"20180404185606.GE9055@sigill.intra.peff.net","threadId":"48197","inReplyTo":"CAHwyqnXtc-WgynCmE+EEVYtg6RRVweK8vwfBQS5VL4ygaFumKQ@mail.gmail.com","subject":"Re: [PATCH v7] ls-remote: create '--sort' option","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-04-04T18:56:06Z","receivedAt":"2018-04-04T18:56:17Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Apr 04, 2018 at 07:18:42PM +0200, Harald Nordgren wrote:\n\n> Jeff, you are right that 'git ls-remote --sort=committerdate' will not\n> work. Do you think we need to do something about this, or it's fine\n> that it fails the way you showed?\n\nIt's a reasonable-sized footgun, but one that I think most people would\nbe unlikely to trigger. I think it's probably OK as long as we warn the\nuser in the documentation (see my other response).\n\n-Peff\n"},{"id":"343823","messageId":"20180404230110.9950-1-haraldnordgren@gmail.com","threadId":"48197","inReplyTo":"20180402005248.52418-1-haraldnordgren@gmail.com","subject":"[PATCH v8] ls-remote: create '--sort' option","fromName":"Harald Nordgren","fromEmail":"haraldnordgren@gmail.com","sentAt":"2018-04-04T23:01:10Z","receivedAt":"2018-04-04T23:01:34Z","isPatch":true,"sender":{"key":"haraldnordgren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9569897?v=4"},"body":"Create a '--sort' option for ls-remote, based on the one from\nfor-each-ref. This e.g. allows ref names to be sorted by version\nsemantics, so that v1.2 is sorted before v1.10.\n\nSigned-off-by: Harald Nordgren <haraldnordgren@gmail.com>\n---\n\nNotes:\n    Partial fixes from Jeff King's comments\n\n Documentation/git-ls-remote.txt | 15 ++++++++++++++-\n builtin/ls-remote.c             | 27 +++++++++++++++++++++++++--\n t/t5512-ls-remote.sh            | 41 ++++++++++++++++++++++++++++++++++++++++-\n 3 files changed, 79 insertions(+), 4 deletions(-)\n\ndiff --git a/Documentation/git-ls-remote.txt b/Documentation/git-ls-remote.txt\nindex 5f2628c8f..fa4505fd7 100644\n--- a/Documentation/git-ls-remote.txt\n+++ b/Documentation/git-ls-remote.txt\n@@ -10,7 +10,7 @@ SYNOPSIS\n --------\n [verse]\n 'git ls-remote' [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n-\t      [-q | --quiet] [--exit-code] [--get-url]\n+\t      [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n \t      [--symref] [<repository> [<refs>...]]\n \n DESCRIPTION\n@@ -60,6 +60,19 @@ OPTIONS\n \tupload-pack only shows the symref HEAD, so it will be the only\n \tone shown by ls-remote.\n \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 \"versionsort.suffix\"\n+\tconfiguration variable.\n+\tThe keys supported are the same as those in `git for-each-ref`,\n+\texcept that because `ls-remote` deals only with remotes, keys like\n+\t`committerdate` that require access to the objects themselves will\n+\tnot work.\n+\n <repository>::\n \tThe \"remote\" repository to query.  This parameter can be\n \teither a URL or the name of a remote (see the GIT URLS and\ndiff --git a/builtin/ls-remote.c b/builtin/ls-remote.c\nindex 540d56429..fbec2bc95 100644\n--- a/builtin/ls-remote.c\n+++ b/builtin/ls-remote.c\n@@ -1,6 +1,7 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n #include \"transport.h\"\n+#include \"ref-filter.h\"\n #include \"remote.h\"\n \n static const char * const ls_remote_usage[] = {\n@@ -43,10 +44,13 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \tint show_symref_target = 0;\n \tconst char *uploadpack = NULL;\n \tconst char **pattern = NULL;\n+\tint i;\n \n \tstruct remote *remote;\n \tstruct transport *transport;\n \tconst struct ref *ref;\n+\tstruct ref_array array;\n+\tstatic struct ref_sorting *sorting = NULL, **sorting_tail = &sorting;\n \n \tstruct option options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"do not print remote URL\")),\n@@ -60,6 +64,8 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \t\tOPT_BIT(0, \"refs\", &flags, N_(\"do not show peeled tags\"), REF_NORMAL),\n \t\tOPT_BOOL(0, \"get-url\", &get_url,\n \t\t\t N_(\"take url.<base>.insteadOf into account\")),\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\tOPT_SET_INT_F(0, \"exit-code\", &status,\n \t\t\t      N_(\"exit with exit code 2 if no matching refs are found\"),\n \t\t\t      2, PARSE_OPT_NOCOMPLETE),\n@@ -68,6 +74,8 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \t\tOPT_END()\n \t};\n \n+\tmemset(&array, 0, sizeof(array));\n+\n \targc = parse_options(argc, argv, prefix, options, ls_remote_usage,\n \t\t\t     PARSE_OPT_STOP_AT_NON_OPTION);\n \tdest = argv[0];\n@@ -104,13 +112,28 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \tif (!dest && !quiet)\n \t\tfprintf(stderr, \"From %s\\n\", *remote->url);\n \tfor ( ; ref; ref = ref->next) {\n+\t\tstruct ref_array_item *item;\n \t\tif (!check_ref_type(ref, flags))\n \t\t\tcontinue;\n \t\tif (!tail_match(pattern, ref->name))\n \t\t\tcontinue;\n+\n+\t\tFLEX_ALLOC_STR(item, refname, ref->name);\n+\t\titem->symref = xstrdup_or_null(ref->symref);\n+\t\toidcpy(&item->objectname, &ref->old_oid);\n+\n+\t\tALLOC_GROW(array.items, array.nr + 1, array.alloc);\n+\t\tarray.items[array.nr++] = item;\n+\t}\n+\n+\tif (sorting)\n+\t\tref_array_sort(sorting, &array);\n+\n+\tfor (i = 0; i < array.nr; i++) {\n+\t\tconst struct ref_array_item *ref = array.items[i];\n \t\tif (show_symref_target && ref->symref)\n-\t\t\tprintf(\"ref: %s\\t%s\\n\", ref->symref, ref->name);\n-\t\tprintf(\"%s\\t%s\\n\", oid_to_hex(&ref->old_oid), ref->name);\n+\t\t\tprintf(\"ref: %s\\t%s\\n\", ref->symref, ref->refname);\n+\t\tprintf(\"%s\\t%s\\n\", oid_to_hex(&ref->objectname), ref->refname);\n \t\tstatus = 0; /* we found something */\n \t}\n \treturn status;\ndiff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh\nindex 02106c922..66370cd88 100755\n--- a/t/t5512-ls-remote.sh\n+++ b/t/t5512-ls-remote.sh\n@@ -10,6 +10,9 @@ test_expect_success setup '\n \ttest_tick &&\n \tgit commit -m initial &&\n \tgit tag mark &&\n+\tgit tag mark1.1 &&\n+\tgit tag mark1.2 &&\n+\tgit tag mark1.10 &&\n \tgit show-ref --tags -d | sed -e \"s/ /\t/\" >expected.tag &&\n \t(\n \t\techo \"$(git rev-parse HEAD)\tHEAD\"\n@@ -39,6 +42,39 @@ test_expect_success 'ls-remote self' '\n \ttest_cmp expected.all actual\n '\n \n+test_expect_success 'ls-remote --sort=\"version:refname\" --tags self' '\n+\tcat >expect <<-\\EOF &&\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.1\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.2\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.10\n+\tEOF\n+\tgit ls-remote --sort=\"version:refname\" --tags self >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'ls-remote --sort=\"-version:refname\" --tags self' '\n+\tcat >expect <<-\\EOF &&\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.10\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.2\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.1\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark\n+\tEOF\n+\tgit ls-remote --sort=\"-version:refname\" --tags self >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'ls-remote --sort=\"-refname\" --tags self' '\n+\tcat >expect <<-\\EOF &&\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.2\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.10\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.1\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark\n+\tEOF\n+\tgit ls-remote --sort=\"-refname\" --tags self >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_expect_success 'dies when no remote specified and no default remotes found' '\n \ttest_must_fail git ls-remote\n '\n@@ -131,7 +167,7 @@ test_expect_success 'Report no-match with --exit-code' '\n \n test_expect_success 'Report match with --exit-code' '\n \tgit ls-remote --exit-code other.git \"refs/tags/*\" >actual &&\n-\tgit ls-remote . tags/mark >expect &&\n+\tgit ls-remote . tags/mark* >expect &&\n \ttest_cmp expect actual\n '\n \n@@ -178,6 +214,9 @@ test_expect_success 'ls-remote --symref' '\n \t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/remotes/origin/HEAD\n \t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/remotes/origin/master\n \t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.1\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.10\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.2\n \tEOF\n \tgit ls-remote --symref >actual &&\n \ttest_cmp expect actual\n-- \n2.14.3 (Apple Git-98)\n\n"},{"id":"343824","messageId":"CAHwyqnU4jv=wW_no4ff_E2TgvGtga1GOhZoDKd93J5MMUtLFCA@mail.gmail.com","threadId":"48197","inReplyTo":"20180404230110.9950-1-haraldnordgren@gmail.com","subject":"Re: [PATCH v8] ls-remote: create '--sort' option","fromName":"Harald Nordgren","fromEmail":"haraldnordgren@gmail.com","sentAt":"2018-04-04T23:11:34Z","receivedAt":"2018-04-04T23:12:22Z","isPatch":true,"sender":{"key":"haraldnordgren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9569897?v=4"},"body":"Without digging to much into the `ref-filter` code itself, it seems\nlike there is an opportunity to generalize and unfify the logic\nbetween these two cases. As well as using `ALLOC_GROW`. But maybe that\nis best left as a follow-up task? Especially since this patch focuses\non `ls-remote`. Seems possibly like too big of a change to start\nchanging a different sub-command.\n\nWouldn't a `ref_array_push()` also require `ref->symref`, maybe then\nwe could pass the whole ref? It needs to be very clear that it's a\n`ref` and not a `ref_array_item` that is being pushed. Much of my\nlogic here deals specifically with trying to treat a ref as\nref_array_item.\n\nFrom my viewpoint as implementer, I was very happy that I could\nimplement the feature *without* invoking `filter_refs` since that\n`filter->kind` switching looks a pretty daunting. I'm not exactly sure\nwhat a `git ls-remote --contains HEAD` would do, maybe you could\nexplain a bit more?\n\nOn Thu, Apr 5, 2018 at 1:01 AM, Harald Nordgren\n<haraldnordgren@gmail.com> wrote:\n> Create a '--sort' option for ls-remote, based on the one from\n> for-each-ref. This e.g. allows ref names to be sorted by version\n> semantics, so that v1.2 is sorted before v1.10.\n>\n> Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com>\n> ---\n>\n> Notes:\n>     Partial fixes from Jeff King's comments\n>\n>  Documentation/git-ls-remote.txt | 15 ++++++++++++++-\n>  builtin/ls-remote.c             | 27 +++++++++++++++++++++++++--\n>  t/t5512-ls-remote.sh            | 41 ++++++++++++++++++++++++++++++++++++++++-\n>  3 files changed, 79 insertions(+), 4 deletions(-)\n>\n> diff --git a/Documentation/git-ls-remote.txt b/Documentation/git-ls-remote.txt\n> index 5f2628c8f..fa4505fd7 100644\n> --- a/Documentation/git-ls-remote.txt\n> +++ b/Documentation/git-ls-remote.txt\n> @@ -10,7 +10,7 @@ SYNOPSIS\n>  --------\n>  [verse]\n>  'git ls-remote' [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n> -             [-q | --quiet] [--exit-code] [--get-url]\n> +             [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n>               [--symref] [<repository> [<refs>...]]\n>\n>  DESCRIPTION\n> @@ -60,6 +60,19 @@ OPTIONS\n>         upload-pack only shows the symref HEAD, so it will be the only\n>         one shown by ls-remote.\n>\n> +--sort=<key>::\n> +       Sort based on the key given.  Prefix `-` to sort in\n> +       descending order of the value. You may use the --sort=<key> option\n> +       multiple times, in which case the last key becomes the primary\n> +       key. Also supports \"version:refname\" or \"v:refname\" (tag\n> +       names are treated as versions). The \"version:refname\" sort\n> +       order can also be affected by the \"versionsort.suffix\"\n> +       configuration variable.\n> +       The keys supported are the same as those in `git for-each-ref`,\n> +       except that because `ls-remote` deals only with remotes, keys like\n> +       `committerdate` that require access to the objects themselves will\n> +       not work.\n> +\n>  <repository>::\n>         The \"remote\" repository to query.  This parameter can be\n>         either a URL or the name of a remote (see the GIT URLS and\n> diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c\n> index 540d56429..fbec2bc95 100644\n> --- a/builtin/ls-remote.c\n> +++ b/builtin/ls-remote.c\n> @@ -1,6 +1,7 @@\n>  #include \"builtin.h\"\n>  #include \"cache.h\"\n>  #include \"transport.h\"\n> +#include \"ref-filter.h\"\n>  #include \"remote.h\"\n>\n>  static const char * const ls_remote_usage[] = {\n> @@ -43,10 +44,13 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n>         int show_symref_target = 0;\n>         const char *uploadpack = NULL;\n>         const char **pattern = NULL;\n> +       int i;\n>\n>         struct remote *remote;\n>         struct transport *transport;\n>         const struct ref *ref;\n> +       struct ref_array array;\n> +       static struct ref_sorting *sorting = NULL, **sorting_tail = &sorting;\n>\n>         struct option options[] = {\n>                 OPT__QUIET(&quiet, N_(\"do not print remote URL\")),\n> @@ -60,6 +64,8 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n>                 OPT_BIT(0, \"refs\", &flags, N_(\"do not show peeled tags\"), REF_NORMAL),\n>                 OPT_BOOL(0, \"get-url\", &get_url,\n>                          N_(\"take url.<base>.insteadOf into account\")),\n> +               OPT_CALLBACK(0 , \"sort\", sorting_tail, N_(\"key\"),\n> +                            N_(\"field name to sort on\"), &parse_opt_ref_sorting),\n>                 OPT_SET_INT_F(0, \"exit-code\", &status,\n>                               N_(\"exit with exit code 2 if no matching refs are found\"),\n>                               2, PARSE_OPT_NOCOMPLETE),\n> @@ -68,6 +74,8 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n>                 OPT_END()\n>         };\n>\n> +       memset(&array, 0, sizeof(array));\n> +\n>         argc = parse_options(argc, argv, prefix, options, ls_remote_usage,\n>                              PARSE_OPT_STOP_AT_NON_OPTION);\n>         dest = argv[0];\n> @@ -104,13 +112,28 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n>         if (!dest && !quiet)\n>                 fprintf(stderr, \"From %s\\n\", *remote->url);\n>         for ( ; ref; ref = ref->next) {\n> +               struct ref_array_item *item;\n>                 if (!check_ref_type(ref, flags))\n>                         continue;\n>                 if (!tail_match(pattern, ref->name))\n>                         continue;\n> +\n> +               FLEX_ALLOC_STR(item, refname, ref->name);\n> +               item->symref = xstrdup_or_null(ref->symref);\n> +               oidcpy(&item->objectname, &ref->old_oid);\n> +\n> +               ALLOC_GROW(array.items, array.nr + 1, array.alloc);\n> +               array.items[array.nr++] = item;\n> +       }\n> +\n> +       if (sorting)\n> +               ref_array_sort(sorting, &array);\n> +\n> +       for (i = 0; i < array.nr; i++) {\n> +               const struct ref_array_item *ref = array.items[i];\n>                 if (show_symref_target && ref->symref)\n> -                       printf(\"ref: %s\\t%s\\n\", ref->symref, ref->name);\n> -               printf(\"%s\\t%s\\n\", oid_to_hex(&ref->old_oid), ref->name);\n> +                       printf(\"ref: %s\\t%s\\n\", ref->symref, ref->refname);\n> +               printf(\"%s\\t%s\\n\", oid_to_hex(&ref->objectname), ref->refname);\n>                 status = 0; /* we found something */\n>         }\n>         return status;\n> diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh\n> index 02106c922..66370cd88 100755\n> --- a/t/t5512-ls-remote.sh\n> +++ b/t/t5512-ls-remote.sh\n> @@ -10,6 +10,9 @@ test_expect_success setup '\n>         test_tick &&\n>         git commit -m initial &&\n>         git tag mark &&\n> +       git tag mark1.1 &&\n> +       git tag mark1.2 &&\n> +       git tag mark1.10 &&\n>         git show-ref --tags -d | sed -e \"s/ /   /\" >expected.tag &&\n>         (\n>                 echo \"$(git rev-parse HEAD)     HEAD\"\n> @@ -39,6 +42,39 @@ test_expect_success 'ls-remote self' '\n>         test_cmp expected.all actual\n>  '\n>\n> +test_expect_success 'ls-remote --sort=\"version:refname\" --tags self' '\n> +       cat >expect <<-\\EOF &&\n> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark\n> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark1.1\n> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark1.2\n> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark1.10\n> +       EOF\n> +       git ls-remote --sort=\"version:refname\" --tags self >actual &&\n> +       test_cmp expect actual\n> +'\n> +\n> +test_expect_success 'ls-remote --sort=\"-version:refname\" --tags self' '\n> +       cat >expect <<-\\EOF &&\n> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark1.10\n> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark1.2\n> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark1.1\n> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark\n> +       EOF\n> +       git ls-remote --sort=\"-version:refname\" --tags self >actual &&\n> +       test_cmp expect actual\n> +'\n> +\n> +test_expect_success 'ls-remote --sort=\"-refname\" --tags self' '\n> +       cat >expect <<-\\EOF &&\n> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark1.2\n> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark1.10\n> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark1.1\n> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark\n> +       EOF\n> +       git ls-remote --sort=\"-refname\" --tags self >actual &&\n> +       test_cmp expect actual\n> +'\n> +\n>  test_expect_success 'dies when no remote specified and no default remotes found' '\n>         test_must_fail git ls-remote\n>  '\n> @@ -131,7 +167,7 @@ test_expect_success 'Report no-match with --exit-code' '\n>\n>  test_expect_success 'Report match with --exit-code' '\n>         git ls-remote --exit-code other.git \"refs/tags/*\" >actual &&\n> -       git ls-remote . tags/mark >expect &&\n> +       git ls-remote . tags/mark* >expect &&\n>         test_cmp expect actual\n>  '\n>\n> @@ -178,6 +214,9 @@ test_expect_success 'ls-remote --symref' '\n>         1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/remotes/origin/HEAD\n>         1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/remotes/origin/master\n>         1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark\n> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark1.1\n> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark1.10\n> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark1.2\n>         EOF\n>         git ls-remote --symref >actual &&\n>         test_cmp expect actual\n> --\n> 2.14.3 (Apple Git-98)\n>\n"},{"id":"343825","messageId":"20180404233232.14913-1-haraldnordgren@gmail.com","threadId":"48197","inReplyTo":"20180402005248.52418-1-haraldnordgren@gmail.com","subject":"[PATCH v9] ls-remote: create '--sort' option","fromName":"Harald Nordgren","fromEmail":"haraldnordgren@gmail.com","sentAt":"2018-04-04T23:32:32Z","receivedAt":"2018-04-04T23:32:57Z","isPatch":true,"sender":{"key":"haraldnordgren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9569897?v=4"},"body":"Create a '--sort' option for ls-remote, based on the one from\nfor-each-ref. This e.g. allows ref names to be sorted by version\nsemantics, so that v1.2 is sorted before v1.10.\n\nSigned-off-by: Harald Nordgren <haraldnordgren@gmail.com>\n---\n\nNotes:\n    Create 'ref_array_push' function in ref-filter\n\n Documentation/git-ls-remote.txt | 15 ++++++++++++++-\n builtin/ls-remote.c             | 20 ++++++++++++++++++--\n ref-filter.c                    | 12 ++++++++++++\n ref-filter.h                    |  2 ++\n t/t5512-ls-remote.sh            | 41 ++++++++++++++++++++++++++++++++++++++++-\n 5 files changed, 86 insertions(+), 4 deletions(-)\n\ndiff --git a/Documentation/git-ls-remote.txt b/Documentation/git-ls-remote.txt\nindex 5f2628c8f..fa4505fd7 100644\n--- a/Documentation/git-ls-remote.txt\n+++ b/Documentation/git-ls-remote.txt\n@@ -10,7 +10,7 @@ SYNOPSIS\n --------\n [verse]\n 'git ls-remote' [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n-\t      [-q | --quiet] [--exit-code] [--get-url]\n+\t      [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n \t      [--symref] [<repository> [<refs>...]]\n \n DESCRIPTION\n@@ -60,6 +60,19 @@ OPTIONS\n \tupload-pack only shows the symref HEAD, so it will be the only\n \tone shown by ls-remote.\n \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 \"versionsort.suffix\"\n+\tconfiguration variable.\n+\tThe keys supported are the same as those in `git for-each-ref`,\n+\texcept that because `ls-remote` deals only with remotes, keys like\n+\t`committerdate` that require access to the objects themselves will\n+\tnot work.\n+\n <repository>::\n \tThe \"remote\" repository to query.  This parameter can be\n \teither a URL or the name of a remote (see the GIT URLS and\ndiff --git a/builtin/ls-remote.c b/builtin/ls-remote.c\nindex 540d56429..f87b2657c 100644\n--- a/builtin/ls-remote.c\n+++ b/builtin/ls-remote.c\n@@ -1,6 +1,7 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n #include \"transport.h\"\n+#include \"ref-filter.h\"\n #include \"remote.h\"\n \n static const char * const ls_remote_usage[] = {\n@@ -43,10 +44,13 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \tint show_symref_target = 0;\n \tconst char *uploadpack = NULL;\n \tconst char **pattern = NULL;\n+\tint i;\n \n \tstruct remote *remote;\n \tstruct transport *transport;\n \tconst struct ref *ref;\n+\tstruct ref_array array;\n+\tstatic struct ref_sorting *sorting = NULL, **sorting_tail = &sorting;\n \n \tstruct option options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"do not print remote URL\")),\n@@ -60,6 +64,8 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \t\tOPT_BIT(0, \"refs\", &flags, N_(\"do not show peeled tags\"), REF_NORMAL),\n \t\tOPT_BOOL(0, \"get-url\", &get_url,\n \t\t\t N_(\"take url.<base>.insteadOf into account\")),\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\tOPT_SET_INT_F(0, \"exit-code\", &status,\n \t\t\t      N_(\"exit with exit code 2 if no matching refs are found\"),\n \t\t\t      2, PARSE_OPT_NOCOMPLETE),\n@@ -68,6 +74,8 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \t\tOPT_END()\n \t};\n \n+\tmemset(&array, 0, sizeof(array));\n+\n \targc = parse_options(argc, argv, prefix, options, ls_remote_usage,\n \t\t\t     PARSE_OPT_STOP_AT_NON_OPTION);\n \tdest = argv[0];\n@@ -108,9 +116,17 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \t\t\tcontinue;\n \t\tif (!tail_match(pattern, ref->name))\n \t\t\tcontinue;\n+\t\tref_array_push(&array, ref);\n+\t}\n+\n+\tif (sorting)\n+\t\tref_array_sort(sorting, &array);\n+\n+\tfor (i = 0; i < array.nr; i++) {\n+\t\tconst struct ref_array_item *ref = array.items[i];\n \t\tif (show_symref_target && ref->symref)\n-\t\t\tprintf(\"ref: %s\\t%s\\n\", ref->symref, ref->name);\n-\t\tprintf(\"%s\\t%s\\n\", oid_to_hex(&ref->old_oid), ref->name);\n+\t\t\tprintf(\"ref: %s\\t%s\\n\", ref->symref, ref->refname);\n+\t\tprintf(\"%s\\t%s\\n\", oid_to_hex(&ref->objectname), ref->refname);\n \t\tstatus = 0; /* we found something */\n \t}\n \treturn status;\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 45fc56216..a5686dacd 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -1861,6 +1861,18 @@ static int ref_kind_from_refname(const char *refname)\n \treturn FILTER_REFS_OTHERS;\n }\n \n+void ref_array_push(struct ref_array *array, const struct ref *ref)\n+{\n+\tstruct ref_array_item *item;\n+\n+\tFLEX_ALLOC_STR(item, refname, ref->name);\n+\titem->symref = xstrdup_or_null(ref->symref);\n+\toidcpy(&item->objectname, &ref->old_oid);\n+\n+\tALLOC_GROW(array->items, array->nr + 1, array->alloc);\n+\tarray->items[array->nr++] = item;\n+}\n+\n static int filter_ref_kind(struct ref_filter *filter, const char *refname)\n {\n \tif (filter->kind == FILTER_REFS_BRANCHES ||\ndiff --git a/ref-filter.h b/ref-filter.h\nindex 0d98342b3..43e713a72 100644\n--- a/ref-filter.h\n+++ b/ref-filter.h\n@@ -127,6 +127,8 @@ int parse_opt_merge_filter(const struct option *opt, const char *arg, int unset)\n char *get_head_description(void);\n /*  Set up translated strings in the output. */\n void setup_ref_filter_porcelain_msg(void);\n+/*  Create a ref_array_item from a ref and push it to the ref_array */\n+void ref_array_push(struct ref_array *array, const struct ref *ref);\n \n /*\n  * Print a single ref, outside of any ref-filter. Note that the\ndiff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh\nindex 02106c922..66370cd88 100755\n--- a/t/t5512-ls-remote.sh\n+++ b/t/t5512-ls-remote.sh\n@@ -10,6 +10,9 @@ test_expect_success setup '\n \ttest_tick &&\n \tgit commit -m initial &&\n \tgit tag mark &&\n+\tgit tag mark1.1 &&\n+\tgit tag mark1.2 &&\n+\tgit tag mark1.10 &&\n \tgit show-ref --tags -d | sed -e \"s/ /\t/\" >expected.tag &&\n \t(\n \t\techo \"$(git rev-parse HEAD)\tHEAD\"\n@@ -39,6 +42,39 @@ test_expect_success 'ls-remote self' '\n \ttest_cmp expected.all actual\n '\n \n+test_expect_success 'ls-remote --sort=\"version:refname\" --tags self' '\n+\tcat >expect <<-\\EOF &&\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.1\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.2\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.10\n+\tEOF\n+\tgit ls-remote --sort=\"version:refname\" --tags self >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'ls-remote --sort=\"-version:refname\" --tags self' '\n+\tcat >expect <<-\\EOF &&\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.10\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.2\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.1\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark\n+\tEOF\n+\tgit ls-remote --sort=\"-version:refname\" --tags self >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'ls-remote --sort=\"-refname\" --tags self' '\n+\tcat >expect <<-\\EOF &&\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.2\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.10\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.1\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark\n+\tEOF\n+\tgit ls-remote --sort=\"-refname\" --tags self >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_expect_success 'dies when no remote specified and no default remotes found' '\n \ttest_must_fail git ls-remote\n '\n@@ -131,7 +167,7 @@ test_expect_success 'Report no-match with --exit-code' '\n \n test_expect_success 'Report match with --exit-code' '\n \tgit ls-remote --exit-code other.git \"refs/tags/*\" >actual &&\n-\tgit ls-remote . tags/mark >expect &&\n+\tgit ls-remote . tags/mark* >expect &&\n \ttest_cmp expect actual\n '\n \n@@ -178,6 +214,9 @@ test_expect_success 'ls-remote --symref' '\n \t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/remotes/origin/HEAD\n \t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/remotes/origin/master\n \t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.1\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.10\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.2\n \tEOF\n \tgit ls-remote --symref >actual &&\n \ttest_cmp expect actual\n-- \n2.14.3 (Apple Git-98)\n\n"},{"id":"343826","messageId":"20180405000447.19443-1-haraldnordgren@gmail.com","threadId":"48197","inReplyTo":"20180402005248.52418-1-haraldnordgren@gmail.com","subject":"[PATCH v10] ls-remote: create '--sort' option","fromName":"Harald Nordgren","fromEmail":"haraldnordgren@gmail.com","sentAt":"2018-04-05T00:04:47Z","receivedAt":"2018-04-05T00:05:14Z","isPatch":true,"sender":{"key":"haraldnordgren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9569897?v=4"},"body":"Create a '--sort' option for ls-remote, based on the one from\nfor-each-ref. This e.g. allows ref names to be sorted by version\nsemantics, so that v1.2 is sorted before v1.10.\n\nSigned-off-by: Harald Nordgren <haraldnordgren@gmail.com>\n---\n\nNotes:\n    Use 'ref_array_item_push' to fix 'REALLOC_ARRAY' call in ref-filter\n\n Documentation/git-ls-remote.txt | 15 ++++++++++++++-\n builtin/ls-remote.c             | 20 ++++++++++++++++++--\n ref-filter.c                    | 20 ++++++++++++++++++--\n ref-filter.h                    |  2 ++\n t/t5512-ls-remote.sh            | 41 ++++++++++++++++++++++++++++++++++++++++-\n 5 files changed, 92 insertions(+), 6 deletions(-)\n\ndiff --git a/Documentation/git-ls-remote.txt b/Documentation/git-ls-remote.txt\nindex 5f2628c8f..fa4505fd7 100644\n--- a/Documentation/git-ls-remote.txt\n+++ b/Documentation/git-ls-remote.txt\n@@ -10,7 +10,7 @@ SYNOPSIS\n --------\n [verse]\n 'git ls-remote' [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n-\t      [-q | --quiet] [--exit-code] [--get-url]\n+\t      [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n \t      [--symref] [<repository> [<refs>...]]\n \n DESCRIPTION\n@@ -60,6 +60,19 @@ OPTIONS\n \tupload-pack only shows the symref HEAD, so it will be the only\n \tone shown by ls-remote.\n \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 \"versionsort.suffix\"\n+\tconfiguration variable.\n+\tThe keys supported are the same as those in `git for-each-ref`,\n+\texcept that because `ls-remote` deals only with remotes, keys like\n+\t`committerdate` that require access to the objects themselves will\n+\tnot work.\n+\n <repository>::\n \tThe \"remote\" repository to query.  This parameter can be\n \teither a URL or the name of a remote (see the GIT URLS and\ndiff --git a/builtin/ls-remote.c b/builtin/ls-remote.c\nindex 540d56429..f87b2657c 100644\n--- a/builtin/ls-remote.c\n+++ b/builtin/ls-remote.c\n@@ -1,6 +1,7 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n #include \"transport.h\"\n+#include \"ref-filter.h\"\n #include \"remote.h\"\n \n static const char * const ls_remote_usage[] = {\n@@ -43,10 +44,13 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \tint show_symref_target = 0;\n \tconst char *uploadpack = NULL;\n \tconst char **pattern = NULL;\n+\tint i;\n \n \tstruct remote *remote;\n \tstruct transport *transport;\n \tconst struct ref *ref;\n+\tstruct ref_array array;\n+\tstatic struct ref_sorting *sorting = NULL, **sorting_tail = &sorting;\n \n \tstruct option options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"do not print remote URL\")),\n@@ -60,6 +64,8 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \t\tOPT_BIT(0, \"refs\", &flags, N_(\"do not show peeled tags\"), REF_NORMAL),\n \t\tOPT_BOOL(0, \"get-url\", &get_url,\n \t\t\t N_(\"take url.<base>.insteadOf into account\")),\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\tOPT_SET_INT_F(0, \"exit-code\", &status,\n \t\t\t      N_(\"exit with exit code 2 if no matching refs are found\"),\n \t\t\t      2, PARSE_OPT_NOCOMPLETE),\n@@ -68,6 +74,8 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \t\tOPT_END()\n \t};\n \n+\tmemset(&array, 0, sizeof(array));\n+\n \targc = parse_options(argc, argv, prefix, options, ls_remote_usage,\n \t\t\t     PARSE_OPT_STOP_AT_NON_OPTION);\n \tdest = argv[0];\n@@ -108,9 +116,17 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \t\t\tcontinue;\n \t\tif (!tail_match(pattern, ref->name))\n \t\t\tcontinue;\n+\t\tref_array_push(&array, ref);\n+\t}\n+\n+\tif (sorting)\n+\t\tref_array_sort(sorting, &array);\n+\n+\tfor (i = 0; i < array.nr; i++) {\n+\t\tconst struct ref_array_item *ref = array.items[i];\n \t\tif (show_symref_target && ref->symref)\n-\t\t\tprintf(\"ref: %s\\t%s\\n\", ref->symref, ref->name);\n-\t\tprintf(\"%s\\t%s\\n\", oid_to_hex(&ref->old_oid), ref->name);\n+\t\t\tprintf(\"ref: %s\\t%s\\n\", ref->symref, ref->refname);\n+\t\tprintf(\"%s\\t%s\\n\", oid_to_hex(&ref->objectname), ref->refname);\n \t\tstatus = 0; /* we found something */\n \t}\n \treturn status;\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 45fc56216..6dbafba07 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -1861,6 +1861,23 @@ static int ref_kind_from_refname(const char *refname)\n \treturn FILTER_REFS_OTHERS;\n }\n \n+void ref_array_item_push(struct ref_array *array, struct ref_array_item *item)\n+{\n+\tALLOC_GROW(array->items, array->nr + 1, array->alloc);\n+\tarray->items[array->nr++] = item;\n+}\n+\n+void ref_array_push(struct ref_array *array, const struct ref *ref)\n+{\n+\tstruct ref_array_item *item;\n+\n+\tFLEX_ALLOC_STR(item, refname, ref->name);\n+\titem->symref = xstrdup_or_null(ref->symref);\n+\toidcpy(&item->objectname, &ref->old_oid);\n+\n+\tref_array_item_push(array, item);\n+}\n+\n static int filter_ref_kind(struct ref_filter *filter, const char *refname)\n {\n \tif (filter->kind == FILTER_REFS_BRANCHES ||\n@@ -1930,8 +1947,7 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,\n \tref = new_ref_array_item(refname, oid->hash, flag);\n \tref->commit = commit;\n \n-\tREALLOC_ARRAY(ref_cbdata->array->items, ref_cbdata->array->nr + 1);\n-\tref_cbdata->array->items[ref_cbdata->array->nr++] = ref;\n+\tref_array_item_push(ref_cbdata->array, ref);\n \tref->kind = kind;\n \treturn 0;\n }\ndiff --git a/ref-filter.h b/ref-filter.h\nindex 0d98342b3..43e713a72 100644\n--- a/ref-filter.h\n+++ b/ref-filter.h\n@@ -127,6 +127,8 @@ int parse_opt_merge_filter(const struct option *opt, const char *arg, int unset)\n char *get_head_description(void);\n /*  Set up translated strings in the output. */\n void setup_ref_filter_porcelain_msg(void);\n+/*  Create a ref_array_item from a ref and push it to the ref_array */\n+void ref_array_push(struct ref_array *array, const struct ref *ref);\n \n /*\n  * Print a single ref, outside of any ref-filter. Note that the\ndiff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh\nindex 02106c922..66370cd88 100755\n--- a/t/t5512-ls-remote.sh\n+++ b/t/t5512-ls-remote.sh\n@@ -10,6 +10,9 @@ test_expect_success setup '\n \ttest_tick &&\n \tgit commit -m initial &&\n \tgit tag mark &&\n+\tgit tag mark1.1 &&\n+\tgit tag mark1.2 &&\n+\tgit tag mark1.10 &&\n \tgit show-ref --tags -d | sed -e \"s/ /\t/\" >expected.tag &&\n \t(\n \t\techo \"$(git rev-parse HEAD)\tHEAD\"\n@@ -39,6 +42,39 @@ test_expect_success 'ls-remote self' '\n \ttest_cmp expected.all actual\n '\n \n+test_expect_success 'ls-remote --sort=\"version:refname\" --tags self' '\n+\tcat >expect <<-\\EOF &&\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.1\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.2\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.10\n+\tEOF\n+\tgit ls-remote --sort=\"version:refname\" --tags self >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'ls-remote --sort=\"-version:refname\" --tags self' '\n+\tcat >expect <<-\\EOF &&\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.10\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.2\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.1\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark\n+\tEOF\n+\tgit ls-remote --sort=\"-version:refname\" --tags self >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'ls-remote --sort=\"-refname\" --tags self' '\n+\tcat >expect <<-\\EOF &&\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.2\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.10\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.1\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark\n+\tEOF\n+\tgit ls-remote --sort=\"-refname\" --tags self >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_expect_success 'dies when no remote specified and no default remotes found' '\n \ttest_must_fail git ls-remote\n '\n@@ -131,7 +167,7 @@ test_expect_success 'Report no-match with --exit-code' '\n \n test_expect_success 'Report match with --exit-code' '\n \tgit ls-remote --exit-code other.git \"refs/tags/*\" >actual &&\n-\tgit ls-remote . tags/mark >expect &&\n+\tgit ls-remote . tags/mark* >expect &&\n \ttest_cmp expect actual\n '\n \n@@ -178,6 +214,9 @@ test_expect_success 'ls-remote --symref' '\n \t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/remotes/origin/HEAD\n \t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/remotes/origin/master\n \t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.1\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.10\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.2\n \tEOF\n \tgit ls-remote --symref >actual &&\n \ttest_cmp expect actual\n-- \n2.14.3 (Apple Git-98)\n\n"},{"id":"343981","messageId":"20180406185801.GA921@sigill.intra.peff.net","threadId":"48197","inReplyTo":"CAHwyqnU4jv=wW_no4ff_E2TgvGtga1GOhZoDKd93J5MMUtLFCA@mail.gmail.com","subject":"Re: [PATCH v8] ls-remote: create '--sort' option","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-04-06T18:58:01Z","receivedAt":"2018-04-06T18:58:08Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Apr 05, 2018 at 01:11:34AM +0200, Harald Nordgren wrote:\n\n> Without digging to much into the `ref-filter` code itself, it seems\n> like there is an opportunity to generalize and unfify the logic\n> between these two cases. As well as using `ALLOC_GROW`. But maybe that\n> is best left as a follow-up task? Especially since this patch focuses\n> on `ls-remote`. Seems possibly like too big of a change to start\n> changing a different sub-command.\n\nYes and no. By refactoring we have the potential to regress another\nunrelated command. But by not refactoring, we set up a potential misuse\nof the other interface which may lead to more bugs down the road.\n\nI think an important thing is to split out the refactoring steps into\ntheir own patches, so it's easy to see that they're not hurting the\nexisting uses. I have some sample patches, which I'll send in a moment.\n\n> Wouldn't a `ref_array_push()` also require `ref->symref`, maybe then\n> we could pass the whole ref? It needs to be very clear that it's a\n> `ref` and not a `ref_array_item` that is being pushed. Much of my\n> logic here deals specifically with trying to treat a ref as\n> ref_array_item.\n\nI think it would be OK to have the push operation return the actual\nitem, which can then be filled in more. That's how the internal\nref-filter code does it already.\n\n> From my viewpoint as implementer, I was very happy that I could\n> implement the feature *without* invoking `filter_refs` since that\n> `filter->kind` switching looks a pretty daunting. I'm not exactly sure\n> what a `git ls-remote --contains HEAD` would do, maybe you could\n> explain a bit more?\n\nI agree it would be a bit larger of a retro-fit to adapt filter_refs()\nfor our purpose here. And since we're not doing any filtering at this\npoint, there's not much benefit.\n\nHere are the refactoring patches I came up with. I think they're a\nbenefit to ref-filter on their own, and then it should be pretty easy\nfor you to build your patch on top.\n\n  [1/3]: ref-filter: use \"struct object_id\" consistently\n  [2/3]: ref-filter: make ref_array_item allocation more consistent\n  [3/3]: ref-filter: factor ref_array pushing into its own function\n\n builtin/tag.c        |  2 +-\n builtin/verify-tag.c |  2 +-\n ref-filter.c         | 36 +++++++++++++++++++++++++-----------\n ref-filter.h         | 10 +++++++++-\n 4 files changed, 36 insertions(+), 14 deletions(-)\n\n-Peff\n\nPS I'm going to be offline for a few weeks starting tomorrow, so I won't\n   be responsive to this thread. :) If you like the direction, please\n   feel free to pick up those patches, rebase yours on top, and then\n   send them all out as a series.\n\n   In case it's easier than applying from the list, you can fetch them\n   from the \"jk/ref-array-push\" branch of https://github.com/peff/git.\n"},{"id":"343982","messageId":"20180406185831.GA11108@sigill.intra.peff.net","threadId":"48197","inReplyTo":"20180406185801.GA921@sigill.intra.peff.net","subject":"[PATCH 1/3] ref-filter: use \"struct object_id\" consistently","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-04-06T18:58:32Z","receivedAt":"2018-04-06T18:58:39Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"Internally we store a \"struct object_id\", and all of our\ncallers have one to pass us. But we insist that they peel it\nto its bare-sha1 hash, which we then hashcpy() into place.\nLet's pass it around as an object_id, which future-proofs us\nfor a post-sha1 world.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n builtin/tag.c        |  2 +-\n builtin/verify-tag.c |  2 +-\n ref-filter.c         | 10 +++++-----\n ref-filter.h         |  2 +-\n 4 files changed, 8 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/tag.c b/builtin/tag.c\nindex da186691ed..42278f5167 100644\n--- a/builtin/tag.c\n+++ b/builtin/tag.c\n@@ -117,7 +117,7 @@ static int verify_tag(const char *name, const char *ref,\n \t\treturn -1;\n \n \tif (format->format)\n-\t\tpretty_print_ref(name, oid->hash, format);\n+\t\tpretty_print_ref(name, oid, format);\n \n \treturn 0;\n }\ndiff --git a/builtin/verify-tag.c b/builtin/verify-tag.c\nindex ad7b79fa5c..6fa04b751a 100644\n--- a/builtin/verify-tag.c\n+++ b/builtin/verify-tag.c\n@@ -72,7 +72,7 @@ int cmd_verify_tag(int argc, const char **argv, const char *prefix)\n \t\t}\n \n \t\tif (format.format)\n-\t\t\tpretty_print_ref(name, oid.hash, &format);\n+\t\t\tpretty_print_ref(name, &oid, &format);\n \t}\n \treturn had_error;\n }\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 45fc56216a..ade97a8486 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -1826,12 +1826,12 @@ static const struct object_id *match_points_at(struct oid_array *points_at,\n \n /* Allocate space for a new ref_array_item and copy the objectname and flag to it */\n static struct ref_array_item *new_ref_array_item(const char *refname,\n-\t\t\t\t\t\t const unsigned char *objectname,\n+\t\t\t\t\t\t const struct object_id *oid,\n \t\t\t\t\t\t int flag)\n {\n \tstruct ref_array_item *ref;\n \tFLEX_ALLOC_STR(ref, refname, refname);\n-\thashcpy(ref->objectname.hash, objectname);\n+\toidcpy(&ref->objectname, oid);\n \tref->flag = flag;\n \n \treturn ref;\n@@ -1927,7 +1927,7 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,\n \t * to do its job and the resulting list may yet to be pruned\n \t * by maxcount logic.\n \t */\n-\tref = new_ref_array_item(refname, oid->hash, flag);\n+\tref = new_ref_array_item(refname, oid, flag);\n \tref->commit = commit;\n \n \tREALLOC_ARRAY(ref_cbdata->array->items, ref_cbdata->array->nr + 1);\n@@ -2165,11 +2165,11 @@ void show_ref_array_item(struct ref_array_item *info,\n \tputchar('\\n');\n }\n \n-void pretty_print_ref(const char *name, const unsigned char *sha1,\n+void pretty_print_ref(const char *name, const struct object_id *oid,\n \t\t      const struct ref_format *format)\n {\n \tstruct ref_array_item *ref_item;\n-\tref_item = new_ref_array_item(name, sha1, 0);\n+\tref_item = new_ref_array_item(name, oid, 0);\n \tref_item->kind = ref_kind_from_refname(name);\n \tshow_ref_array_item(ref_item, format);\n \tfree_array_item(ref_item);\ndiff --git a/ref-filter.h b/ref-filter.h\nindex 0d98342b34..68268f9ebc 100644\n--- a/ref-filter.h\n+++ b/ref-filter.h\n@@ -132,7 +132,7 @@ void setup_ref_filter_porcelain_msg(void);\n  * Print a single ref, outside of any ref-filter. Note that the\n  * name must be a fully qualified refname.\n  */\n-void pretty_print_ref(const char *name, const unsigned char *sha1,\n+void pretty_print_ref(const char *name, const struct object_id *oid,\n \t\t      const struct ref_format *format);\n \n #endif /*  REF_FILTER_H  */\n-- \n2.17.0.686.g08b0810b04\n\n"},{"id":"343983","messageId":"20180406185925.GB11108@sigill.intra.peff.net","threadId":"48197","inReplyTo":"20180406185801.GA921@sigill.intra.peff.net","subject":"[PATCH 2/3] ref-filter: make ref_array_item allocation more consistent","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-04-06T18:59:26Z","receivedAt":"2018-04-06T18:59:31Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"We have a helper function to allocate ref_array_item\nstructs, but it only takes a subset of the possible fields\nin the struct as initializers. We could have it accept an\nargument for _every_ field, but that becomes a pain for the\nfields which some callers don't want to set initially.\n\nInstead, let's be explicit that it takes only the minimum\nrequired to create the ref, and that callers should then\nfill in the rest themselves.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\nTechnically we don't need the oid to create the struct, just the name,\nbut I figured that every caller is going to have to have some oid.\n\n ref-filter.c | 18 +++++++++++-------\n 1 file changed, 11 insertions(+), 7 deletions(-)\n\ndiff --git a/ref-filter.c b/ref-filter.c\nindex ade97a8486..c1c3cc9480 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -1824,15 +1824,18 @@ static const struct object_id *match_points_at(struct oid_array *points_at,\n \treturn NULL;\n }\n \n-/* Allocate space for a new ref_array_item and copy the objectname and flag to it */\n+/*\n+ * Allocate space for a new ref_array_item and copy the name and oid to it.\n+ *\n+ * Callers can then fill in other struct members at their leisure.\n+ */\n static struct ref_array_item *new_ref_array_item(const char *refname,\n-\t\t\t\t\t\t const struct object_id *oid,\n-\t\t\t\t\t\t int flag)\n+\t\t\t\t\t\t const struct object_id *oid)\n {\n \tstruct ref_array_item *ref;\n+\n \tFLEX_ALLOC_STR(ref, refname, refname);\n \toidcpy(&ref->objectname, oid);\n-\tref->flag = flag;\n \n \treturn ref;\n }\n@@ -1927,12 +1930,13 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,\n \t * to do its job and the resulting list may yet to be pruned\n \t * by maxcount logic.\n \t */\n-\tref = new_ref_array_item(refname, oid, flag);\n+\tref = new_ref_array_item(refname, oid);\n \tref->commit = commit;\n+\tref->flag = flag;\n+\tref->kind = kind;\n \n \tREALLOC_ARRAY(ref_cbdata->array->items, ref_cbdata->array->nr + 1);\n \tref_cbdata->array->items[ref_cbdata->array->nr++] = ref;\n-\tref->kind = kind;\n \treturn 0;\n }\n \n@@ -2169,7 +2173,7 @@ void pretty_print_ref(const char *name, const struct object_id *oid,\n \t\t      const struct ref_format *format)\n {\n \tstruct ref_array_item *ref_item;\n-\tref_item = new_ref_array_item(name, oid, 0);\n+\tref_item = new_ref_array_item(name, oid);\n \tref_item->kind = ref_kind_from_refname(name);\n \tshow_ref_array_item(ref_item, format);\n \tfree_array_item(ref_item);\n-- \n2.17.0.686.g08b0810b04\n\n"},{"id":"343984","messageId":"20180406185945.GC11108@sigill.intra.peff.net","threadId":"48197","inReplyTo":"20180406185801.GA921@sigill.intra.peff.net","subject":"[PATCH 3/3] ref-filter: factor ref_array pushing into its own function","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-04-06T18:59:45Z","receivedAt":"2018-04-06T18:59:51Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"In preparation for callers constructing their own ref_array\nstructs, let's move our own internal push operation into its\nown function.\n\nWhile we're at it, we can replace REALLOC_ARRAY() with\nALLOC_GROW(), which should give the growth operation\namortized linear complexity (as opposed to growing by one,\nwhich is potentially quadratic, though in-place realloc\ngrowth often makes this faster in practice).\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n ref-filter.c | 16 +++++++++++++---\n ref-filter.h |  8 ++++++++\n 2 files changed, 21 insertions(+), 3 deletions(-)\n\ndiff --git a/ref-filter.c b/ref-filter.c\nindex c1c3cc9480..6e9328b274 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -1840,6 +1840,18 @@ static struct ref_array_item *new_ref_array_item(const char *refname,\n \treturn ref;\n }\n \n+struct ref_array_item *ref_array_push(struct ref_array *array,\n+\t\t\t\t      const char *refname,\n+\t\t\t\t      const struct object_id *oid)\n+{\n+\tstruct ref_array_item *ref = new_ref_array_item(refname, oid);\n+\n+\tALLOC_GROW(array->items, array->nr + 1, array->alloc);\n+\tarray->items[array->nr++] = ref;\n+\n+\treturn ref;\n+}\n+\n static int ref_kind_from_refname(const char *refname)\n {\n \tunsigned int i;\n@@ -1930,13 +1942,11 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,\n \t * to do its job and the resulting list may yet to be pruned\n \t * by maxcount logic.\n \t */\n-\tref = new_ref_array_item(refname, oid);\n+\tref = ref_array_push(ref_cbdata->array, refname, oid);\n \tref->commit = commit;\n \tref->flag = flag;\n \tref->kind = kind;\n \n-\tREALLOC_ARRAY(ref_cbdata->array->items, ref_cbdata->array->nr + 1);\n-\tref_cbdata->array->items[ref_cbdata->array->nr++] = ref;\n \treturn 0;\n }\n \ndiff --git a/ref-filter.h b/ref-filter.h\nindex 68268f9ebc..76cf87cb6c 100644\n--- a/ref-filter.h\n+++ b/ref-filter.h\n@@ -135,4 +135,12 @@ void setup_ref_filter_porcelain_msg(void);\n void pretty_print_ref(const char *name, const struct object_id *oid,\n \t\t      const struct ref_format *format);\n \n+/*\n+ * Push a single ref onto the array; this can be used to construct your own\n+ * ref_array without using filter_refs().\n+ */\n+struct ref_array_item *ref_array_push(struct ref_array *array,\n+\t\t\t\t      const char *refname,\n+\t\t\t\t      const struct object_id *oid);\n+\n #endif /*  REF_FILTER_H  */\n-- \n2.17.0.686.g08b0810b04\n"},{"id":"343991","messageId":"51135137-97ea-354a-7acd-4e905ee69a80@gmail.com","threadId":"48197","inReplyTo":"20180406185945.GC11108@sigill.intra.peff.net","subject":"Re: [PATCH 3/3] ref-filter: factor ref_array pushing into its own function","fromName":"Derrick Stolee","fromEmail":"stolee@gmail.com","sentAt":"2018-04-06T19:27:13Z","receivedAt":"2018-04-06T19:27:26Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"On 4/6/2018 2:59 PM, Jeff King wrote:\n> In preparation for callers constructing their own ref_array\n> structs, let's move our own internal push operation into its\n> own function.\n>\n> While we're at it, we can replace REALLOC_ARRAY() with\n> ALLOC_GROW(), which should give the growth operation\n> amortized linear complexity (as opposed to growing by one,\n> which is potentially quadratic, though in-place realloc\n> growth often makes this faster in practice).\n>\n> Signed-off-by: Jeff King <peff@peff.net>\n> ---\n>   ref-filter.c | 16 +++++++++++++---\n>   ref-filter.h |  8 ++++++++\n>   2 files changed, 21 insertions(+), 3 deletions(-)\n>\n> diff --git a/ref-filter.c b/ref-filter.c\n> index c1c3cc9480..6e9328b274 100644\n> --- a/ref-filter.c\n> +++ b/ref-filter.c\n> @@ -1840,6 +1840,18 @@ static struct ref_array_item *new_ref_array_item(const char *refname,\n>   \treturn ref;\n>   }\n>   \n> +struct ref_array_item *ref_array_push(struct ref_array *array,\n> +\t\t\t\t      const char *refname,\n> +\t\t\t\t      const struct object_id *oid)\n> +{\n> +\tstruct ref_array_item *ref = new_ref_array_item(refname, oid);\n> +\n> +\tALLOC_GROW(array->items, array->nr + 1, array->alloc);\n> +\tarray->items[array->nr++] = ref;\n> +\n> +\treturn ref;\n> +}\n> +\n>   static int ref_kind_from_refname(const char *refname)\n>   {\n>   \tunsigned int i;\n> @@ -1930,13 +1942,11 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,\n>   \t * to do its job and the resulting list may yet to be pruned\n>   \t * by maxcount logic.\n>   \t */\n> -\tref = new_ref_array_item(refname, oid);\n> +\tref = ref_array_push(ref_cbdata->array, refname, oid);\n>   \tref->commit = commit;\n>   \tref->flag = flag;\n>   \tref->kind = kind;\n>   \n> -\tREALLOC_ARRAY(ref_cbdata->array->items, ref_cbdata->array->nr + 1);\n> -\tref_cbdata->array->items[ref_cbdata->array->nr++] = ref;\n>   \treturn 0;\n>   }\n>   \n> diff --git a/ref-filter.h b/ref-filter.h\n> index 68268f9ebc..76cf87cb6c 100644\n> --- a/ref-filter.h\n> +++ b/ref-filter.h\n> @@ -135,4 +135,12 @@ void setup_ref_filter_porcelain_msg(void);\n>   void pretty_print_ref(const char *name, const struct object_id *oid,\n>   \t\t      const struct ref_format *format);\n>   \n> +/*\n> + * Push a single ref onto the array; this can be used to construct your own\n> + * ref_array without using filter_refs().\n> + */\n> +struct ref_array_item *ref_array_push(struct ref_array *array,\n> +\t\t\t\t      const char *refname,\n> +\t\t\t\t      const struct object_id *oid);\n> +\n>   #endif /*  REF_FILTER_H  */\n\nThe three patches in this series look good to me.\n\nReviewed-by: Derrick Stolee <dstolee@microsoft.com>\n"},{"id":"344065","messageId":"CAHwyqnV5JcW_ffMWDUqyioVS7fwAndixA8Xgjqx7TPq0huUWTQ@mail.gmail.com","threadId":"48197","inReplyTo":"51135137-97ea-354a-7acd-4e905ee69a80@gmail.com","subject":"Re: [PATCH 3/3] ref-filter: factor ref_array pushing into its own function","fromName":"Harald Nordgren","fromEmail":"haraldnordgren@gmail.com","sentAt":"2018-04-07T15:22:14Z","receivedAt":"2018-04-07T15:23:01Z","isPatch":true,"sender":{"key":"haraldnordgren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9569897?v=4"},"body":"Looks good to me.\n\nReviewed-by: Harald Nordgren <haraldnordgren@gmail.com>\n\nOn Fri, Apr 6, 2018 at 9:27 PM, Derrick Stolee <stolee@gmail.com> wrote:\n> On 4/6/2018 2:59 PM, Jeff King wrote:\n>>\n>> In preparation for callers constructing their own ref_array\n>> structs, let's move our own internal push operation into its\n>> own function.\n>>\n>> While we're at it, we can replace REALLOC_ARRAY() with\n>> ALLOC_GROW(), which should give the growth operation\n>> amortized linear complexity (as opposed to growing by one,\n>> which is potentially quadratic, though in-place realloc\n>> growth often makes this faster in practice).\n>>\n>> Signed-off-by: Jeff King <peff@peff.net>\n>> ---\n>>   ref-filter.c | 16 +++++++++++++---\n>>   ref-filter.h |  8 ++++++++\n>>   2 files changed, 21 insertions(+), 3 deletions(-)\n>>\n>> diff --git a/ref-filter.c b/ref-filter.c\n>> index c1c3cc9480..6e9328b274 100644\n>> --- a/ref-filter.c\n>> +++ b/ref-filter.c\n>> @@ -1840,6 +1840,18 @@ static struct ref_array_item\n>> *new_ref_array_item(const char *refname,\n>>         return ref;\n>>   }\n>>   +struct ref_array_item *ref_array_push(struct ref_array *array,\n>> +                                     const char *refname,\n>> +                                     const struct object_id *oid)\n>> +{\n>> +       struct ref_array_item *ref = new_ref_array_item(refname, oid);\n>> +\n>> +       ALLOC_GROW(array->items, array->nr + 1, array->alloc);\n>> +       array->items[array->nr++] = ref;\n>> +\n>> +       return ref;\n>> +}\n>> +\n>>   static int ref_kind_from_refname(const char *refname)\n>>   {\n>>         unsigned int i;\n>> @@ -1930,13 +1942,11 @@ static int ref_filter_handler(const char *refname,\n>> const struct object_id *oid,\n>>          * to do its job and the resulting list may yet to be pruned\n>>          * by maxcount logic.\n>>          */\n>> -       ref = new_ref_array_item(refname, oid);\n>> +       ref = ref_array_push(ref_cbdata->array, refname, oid);\n>>         ref->commit = commit;\n>>         ref->flag = flag;\n>>         ref->kind = kind;\n>>   -     REALLOC_ARRAY(ref_cbdata->array->items, ref_cbdata->array->nr +\n>> 1);\n>> -       ref_cbdata->array->items[ref_cbdata->array->nr++] = ref;\n>>         return 0;\n>>   }\n>>   diff --git a/ref-filter.h b/ref-filter.h\n>> index 68268f9ebc..76cf87cb6c 100644\n>> --- a/ref-filter.h\n>> +++ b/ref-filter.h\n>> @@ -135,4 +135,12 @@ void setup_ref_filter_porcelain_msg(void);\n>>   void pretty_print_ref(const char *name, const struct object_id *oid,\n>>                       const struct ref_format *format);\n>>   +/*\n>> + * Push a single ref onto the array; this can be used to construct your\n>> own\n>> + * ref_array without using filter_refs().\n>> + */\n>> +struct ref_array_item *ref_array_push(struct ref_array *array,\n>> +                                     const char *refname,\n>> +                                     const struct object_id *oid);\n>> +\n>>   #endif /*  REF_FILTER_H  */\n>\n>\n> The three patches in this series look good to me.\n>\n> Reviewed-by: Derrick Stolee <dstolee@microsoft.com>\n"},{"id":"344066","messageId":"20180407164250.54303-1-haraldnordgren@gmail.com","threadId":"48197","inReplyTo":"20180402005248.52418-1-haraldnordgren@gmail.com","subject":"[PATCH v11 1/4] ref-filter: use \"struct object_id\" consistently","fromName":"Harald Nordgren","fromEmail":"haraldnordgren@gmail.com","sentAt":"2018-04-07T16:42:47Z","receivedAt":"2018-04-07T16:43:23Z","isPatch":true,"sender":{"key":"haraldnordgren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9569897?v=4"},"body":"From: Jeff King <peff@peff.net>\n\nInternally we store a \"struct object_id\", and all of our\ncallers have one to pass us. But we insist that they peel it\nto its bare-sha1 hash, which we then hashcpy() into place.\nLet's pass it around as an object_id, which future-proofs us\nfor a post-sha1 world.\n---\n builtin/tag.c        |  2 +-\n builtin/verify-tag.c |  2 +-\n ref-filter.c         | 10 +++++-----\n ref-filter.h         |  2 +-\n 4 files changed, 8 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/tag.c b/builtin/tag.c\nindex da186691e..42278f516 100644\n--- a/builtin/tag.c\n+++ b/builtin/tag.c\n@@ -117,7 +117,7 @@ static int verify_tag(const char *name, const char *ref,\n \t\treturn -1;\n \n \tif (format->format)\n-\t\tpretty_print_ref(name, oid->hash, format);\n+\t\tpretty_print_ref(name, oid, format);\n \n \treturn 0;\n }\ndiff --git a/builtin/verify-tag.c b/builtin/verify-tag.c\nindex ad7b79fa5..6fa04b751 100644\n--- a/builtin/verify-tag.c\n+++ b/builtin/verify-tag.c\n@@ -72,7 +72,7 @@ int cmd_verify_tag(int argc, const char **argv, const char *prefix)\n \t\t}\n \n \t\tif (format.format)\n-\t\t\tpretty_print_ref(name, oid.hash, &format);\n+\t\t\tpretty_print_ref(name, &oid, &format);\n \t}\n \treturn had_error;\n }\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 45fc56216..ade97a848 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -1826,12 +1826,12 @@ static const struct object_id *match_points_at(struct oid_array *points_at,\n \n /* Allocate space for a new ref_array_item and copy the objectname and flag to it */\n static struct ref_array_item *new_ref_array_item(const char *refname,\n-\t\t\t\t\t\t const unsigned char *objectname,\n+\t\t\t\t\t\t const struct object_id *oid,\n \t\t\t\t\t\t int flag)\n {\n \tstruct ref_array_item *ref;\n \tFLEX_ALLOC_STR(ref, refname, refname);\n-\thashcpy(ref->objectname.hash, objectname);\n+\toidcpy(&ref->objectname, oid);\n \tref->flag = flag;\n \n \treturn ref;\n@@ -1927,7 +1927,7 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,\n \t * to do its job and the resulting list may yet to be pruned\n \t * by maxcount logic.\n \t */\n-\tref = new_ref_array_item(refname, oid->hash, flag);\n+\tref = new_ref_array_item(refname, oid, flag);\n \tref->commit = commit;\n \n \tREALLOC_ARRAY(ref_cbdata->array->items, ref_cbdata->array->nr + 1);\n@@ -2165,11 +2165,11 @@ void show_ref_array_item(struct ref_array_item *info,\n \tputchar('\\n');\n }\n \n-void pretty_print_ref(const char *name, const unsigned char *sha1,\n+void pretty_print_ref(const char *name, const struct object_id *oid,\n \t\t      const struct ref_format *format)\n {\n \tstruct ref_array_item *ref_item;\n-\tref_item = new_ref_array_item(name, sha1, 0);\n+\tref_item = new_ref_array_item(name, oid, 0);\n \tref_item->kind = ref_kind_from_refname(name);\n \tshow_ref_array_item(ref_item, format);\n \tfree_array_item(ref_item);\ndiff --git a/ref-filter.h b/ref-filter.h\nindex 0d98342b3..68268f9eb 100644\n--- a/ref-filter.h\n+++ b/ref-filter.h\n@@ -132,7 +132,7 @@ void setup_ref_filter_porcelain_msg(void);\n  * Print a single ref, outside of any ref-filter. Note that the\n  * name must be a fully qualified refname.\n  */\n-void pretty_print_ref(const char *name, const unsigned char *sha1,\n+void pretty_print_ref(const char *name, const struct object_id *oid,\n \t\t      const struct ref_format *format);\n \n #endif /*  REF_FILTER_H  */\n-- \n2.14.3 (Apple Git-98)\n\n"},{"id":"344067","messageId":"20180407164250.54303-2-haraldnordgren@gmail.com","threadId":"48197","inReplyTo":"20180407164250.54303-1-haraldnordgren@gmail.com","subject":"[PATCH v11 2/4] ref-filter: make ref_array_item allocation more consistent","fromName":"Harald Nordgren","fromEmail":"haraldnordgren@gmail.com","sentAt":"2018-04-07T16:42:48Z","receivedAt":"2018-04-07T16:43:39Z","isPatch":true,"sender":{"key":"haraldnordgren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9569897?v=4"},"body":"From: Jeff King <peff@peff.net>\n\nWe have a helper function to allocate ref_array_item\nstructs, but it only takes a subset of the possible fields\nin the struct as initializers. We could have it accept an\nargument for _every_ field, but that becomes a pain for the\nfields which some callers don't want to set initially.\n\nInstead, let's be explicit that it takes only the minimum\nrequired to create the ref, and that callers should then\nfill in the rest themselves.\n---\n ref-filter.c | 18 +++++++++++-------\n 1 file changed, 11 insertions(+), 7 deletions(-)\n\ndiff --git a/ref-filter.c b/ref-filter.c\nindex ade97a848..c1c3cc948 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -1824,15 +1824,18 @@ static const struct object_id *match_points_at(struct oid_array *points_at,\n \treturn NULL;\n }\n \n-/* Allocate space for a new ref_array_item and copy the objectname and flag to it */\n+/*\n+ * Allocate space for a new ref_array_item and copy the name and oid to it.\n+ *\n+ * Callers can then fill in other struct members at their leisure.\n+ */\n static struct ref_array_item *new_ref_array_item(const char *refname,\n-\t\t\t\t\t\t const struct object_id *oid,\n-\t\t\t\t\t\t int flag)\n+\t\t\t\t\t\t const struct object_id *oid)\n {\n \tstruct ref_array_item *ref;\n+\n \tFLEX_ALLOC_STR(ref, refname, refname);\n \toidcpy(&ref->objectname, oid);\n-\tref->flag = flag;\n \n \treturn ref;\n }\n@@ -1927,12 +1930,13 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,\n \t * to do its job and the resulting list may yet to be pruned\n \t * by maxcount logic.\n \t */\n-\tref = new_ref_array_item(refname, oid, flag);\n+\tref = new_ref_array_item(refname, oid);\n \tref->commit = commit;\n+\tref->flag = flag;\n+\tref->kind = kind;\n \n \tREALLOC_ARRAY(ref_cbdata->array->items, ref_cbdata->array->nr + 1);\n \tref_cbdata->array->items[ref_cbdata->array->nr++] = ref;\n-\tref->kind = kind;\n \treturn 0;\n }\n \n@@ -2169,7 +2173,7 @@ void pretty_print_ref(const char *name, const struct object_id *oid,\n \t\t      const struct ref_format *format)\n {\n \tstruct ref_array_item *ref_item;\n-\tref_item = new_ref_array_item(name, oid, 0);\n+\tref_item = new_ref_array_item(name, oid);\n \tref_item->kind = ref_kind_from_refname(name);\n \tshow_ref_array_item(ref_item, format);\n \tfree_array_item(ref_item);\n-- \n2.14.3 (Apple Git-98)\n\n"},{"id":"344068","messageId":"20180407164250.54303-3-haraldnordgren@gmail.com","threadId":"48197","inReplyTo":"20180407164250.54303-1-haraldnordgren@gmail.com","subject":"[PATCH v11 3/4] ref-filter: factor ref_array pushing into its own function","fromName":"Harald Nordgren","fromEmail":"haraldnordgren@gmail.com","sentAt":"2018-04-07T16:42:49Z","receivedAt":"2018-04-07T16:43:40Z","isPatch":true,"sender":{"key":"haraldnordgren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9569897?v=4"},"body":"From: Jeff King <peff@peff.net>\n\nIn preparation for callers constructing their own ref_array\nstructs, let's move our own internal push operation into its\nown function.\n\nWhile we're at it, we can replace REALLOC_ARRAY() with\nALLOC_GROW(), which should give the growth operation\namortized linear complexity (as opposed to growing by one,\nwhich is potentially quadratic, though in-place realloc\ngrowth often makes this faster in practice).\n---\n ref-filter.c | 16 +++++++++++++---\n ref-filter.h |  8 ++++++++\n 2 files changed, 21 insertions(+), 3 deletions(-)\n\ndiff --git a/ref-filter.c b/ref-filter.c\nindex c1c3cc948..6e9328b27 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -1840,6 +1840,18 @@ static struct ref_array_item *new_ref_array_item(const char *refname,\n \treturn ref;\n }\n \n+struct ref_array_item *ref_array_push(struct ref_array *array,\n+\t\t\t\t      const char *refname,\n+\t\t\t\t      const struct object_id *oid)\n+{\n+\tstruct ref_array_item *ref = new_ref_array_item(refname, oid);\n+\n+\tALLOC_GROW(array->items, array->nr + 1, array->alloc);\n+\tarray->items[array->nr++] = ref;\n+\n+\treturn ref;\n+}\n+\n static int ref_kind_from_refname(const char *refname)\n {\n \tunsigned int i;\n@@ -1930,13 +1942,11 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,\n \t * to do its job and the resulting list may yet to be pruned\n \t * by maxcount logic.\n \t */\n-\tref = new_ref_array_item(refname, oid);\n+\tref = ref_array_push(ref_cbdata->array, refname, oid);\n \tref->commit = commit;\n \tref->flag = flag;\n \tref->kind = kind;\n \n-\tREALLOC_ARRAY(ref_cbdata->array->items, ref_cbdata->array->nr + 1);\n-\tref_cbdata->array->items[ref_cbdata->array->nr++] = ref;\n \treturn 0;\n }\n \ndiff --git a/ref-filter.h b/ref-filter.h\nindex 68268f9eb..76cf87cb6 100644\n--- a/ref-filter.h\n+++ b/ref-filter.h\n@@ -135,4 +135,12 @@ void setup_ref_filter_porcelain_msg(void);\n void pretty_print_ref(const char *name, const struct object_id *oid,\n \t\t      const struct ref_format *format);\n \n+/*\n+ * Push a single ref onto the array; this can be used to construct your own\n+ * ref_array without using filter_refs().\n+ */\n+struct ref_array_item *ref_array_push(struct ref_array *array,\n+\t\t\t\t      const char *refname,\n+\t\t\t\t      const struct object_id *oid);\n+\n #endif /*  REF_FILTER_H  */\n-- \n2.14.3 (Apple Git-98)\n\n"},{"id":"344069","messageId":"20180407164250.54303-4-haraldnordgren@gmail.com","threadId":"48197","inReplyTo":"20180407164250.54303-1-haraldnordgren@gmail.com","subject":"[PATCH v11 4/4] ls-remote: create '--sort' option","fromName":"Harald Nordgren","fromEmail":"haraldnordgren@gmail.com","sentAt":"2018-04-07T16:42:50Z","receivedAt":"2018-04-07T16:43:42Z","isPatch":true,"sender":{"key":"haraldnordgren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9569897?v=4"},"body":"Create a '--sort' option for ls-remote, based on the one from\nfor-each-ref. This e.g. allows ref names to be sorted by version\nsemantics, so that v1.2 is sorted before v1.10.\n\nSigned-off-by: Harald Nordgren <haraldnordgren@gmail.com>\n---\n\nNotes:\n    Rebasing my patch on Jeff King's refatoring patches\n\n Documentation/git-ls-remote.txt | 15 ++++++++++++++-\n builtin/ls-remote.c             | 22 ++++++++++++++++++++--\n t/t5512-ls-remote.sh            | 41 ++++++++++++++++++++++++++++++++++++++++-\n 3 files changed, 74 insertions(+), 4 deletions(-)\n\ndiff --git a/Documentation/git-ls-remote.txt b/Documentation/git-ls-remote.txt\nindex 5f2628c8f..fa4505fd7 100644\n--- a/Documentation/git-ls-remote.txt\n+++ b/Documentation/git-ls-remote.txt\n@@ -10,7 +10,7 @@ SYNOPSIS\n --------\n [verse]\n 'git ls-remote' [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n-\t      [-q | --quiet] [--exit-code] [--get-url]\n+\t      [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n \t      [--symref] [<repository> [<refs>...]]\n \n DESCRIPTION\n@@ -60,6 +60,19 @@ OPTIONS\n \tupload-pack only shows the symref HEAD, so it will be the only\n \tone shown by ls-remote.\n \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 \"versionsort.suffix\"\n+\tconfiguration variable.\n+\tThe keys supported are the same as those in `git for-each-ref`,\n+\texcept that because `ls-remote` deals only with remotes, keys like\n+\t`committerdate` that require access to the objects themselves will\n+\tnot work.\n+\n <repository>::\n \tThe \"remote\" repository to query.  This parameter can be\n \teither a URL or the name of a remote (see the GIT URLS and\ndiff --git a/builtin/ls-remote.c b/builtin/ls-remote.c\nindex 540d56429..4375e8322 100644\n--- a/builtin/ls-remote.c\n+++ b/builtin/ls-remote.c\n@@ -1,6 +1,7 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n #include \"transport.h\"\n+#include \"ref-filter.h\"\n #include \"remote.h\"\n \n static const char * const ls_remote_usage[] = {\n@@ -43,10 +44,13 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \tint show_symref_target = 0;\n \tconst char *uploadpack = NULL;\n \tconst char **pattern = NULL;\n+\tint i;\n \n \tstruct remote *remote;\n \tstruct transport *transport;\n \tconst struct ref *ref;\n+\tstruct ref_array array;\n+\tstatic struct ref_sorting *sorting = NULL, **sorting_tail = &sorting;\n \n \tstruct option options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"do not print remote URL\")),\n@@ -60,6 +64,8 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \t\tOPT_BIT(0, \"refs\", &flags, N_(\"do not show peeled tags\"), REF_NORMAL),\n \t\tOPT_BOOL(0, \"get-url\", &get_url,\n \t\t\t N_(\"take url.<base>.insteadOf into account\")),\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\tOPT_SET_INT_F(0, \"exit-code\", &status,\n \t\t\t      N_(\"exit with exit code 2 if no matching refs are found\"),\n \t\t\t      2, PARSE_OPT_NOCOMPLETE),\n@@ -68,6 +74,8 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \t\tOPT_END()\n \t};\n \n+\tmemset(&array, 0, sizeof(array));\n+\n \targc = parse_options(argc, argv, prefix, options, ls_remote_usage,\n \t\t\t     PARSE_OPT_STOP_AT_NON_OPTION);\n \tdest = argv[0];\n@@ -104,13 +112,23 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \tif (!dest && !quiet)\n \t\tfprintf(stderr, \"From %s\\n\", *remote->url);\n \tfor ( ; ref; ref = ref->next) {\n+\t\tstruct ref_array_item *item;\n \t\tif (!check_ref_type(ref, flags))\n \t\t\tcontinue;\n \t\tif (!tail_match(pattern, ref->name))\n \t\t\tcontinue;\n+\t\titem = ref_array_push(&array, ref->name, &ref->old_oid);\n+\t\titem->symref = xstrdup_or_null(ref->symref);\n+\t}\n+\n+\tif (sorting)\n+\t\tref_array_sort(sorting, &array);\n+\n+\tfor (i = 0; i < array.nr; i++) {\n+\t\tconst struct ref_array_item *ref = array.items[i];\n \t\tif (show_symref_target && ref->symref)\n-\t\t\tprintf(\"ref: %s\\t%s\\n\", ref->symref, ref->name);\n-\t\tprintf(\"%s\\t%s\\n\", oid_to_hex(&ref->old_oid), ref->name);\n+\t\t\tprintf(\"ref: %s\\t%s\\n\", ref->symref, ref->refname);\n+\t\tprintf(\"%s\\t%s\\n\", oid_to_hex(&ref->objectname), ref->refname);\n \t\tstatus = 0; /* we found something */\n \t}\n \treturn status;\ndiff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh\nindex 02106c922..66370cd88 100755\n--- a/t/t5512-ls-remote.sh\n+++ b/t/t5512-ls-remote.sh\n@@ -10,6 +10,9 @@ test_expect_success setup '\n \ttest_tick &&\n \tgit commit -m initial &&\n \tgit tag mark &&\n+\tgit tag mark1.1 &&\n+\tgit tag mark1.2 &&\n+\tgit tag mark1.10 &&\n \tgit show-ref --tags -d | sed -e \"s/ /\t/\" >expected.tag &&\n \t(\n \t\techo \"$(git rev-parse HEAD)\tHEAD\"\n@@ -39,6 +42,39 @@ test_expect_success 'ls-remote self' '\n \ttest_cmp expected.all actual\n '\n \n+test_expect_success 'ls-remote --sort=\"version:refname\" --tags self' '\n+\tcat >expect <<-\\EOF &&\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.1\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.2\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.10\n+\tEOF\n+\tgit ls-remote --sort=\"version:refname\" --tags self >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'ls-remote --sort=\"-version:refname\" --tags self' '\n+\tcat >expect <<-\\EOF &&\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.10\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.2\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.1\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark\n+\tEOF\n+\tgit ls-remote --sort=\"-version:refname\" --tags self >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'ls-remote --sort=\"-refname\" --tags self' '\n+\tcat >expect <<-\\EOF &&\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.2\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.10\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.1\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark\n+\tEOF\n+\tgit ls-remote --sort=\"-refname\" --tags self >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_expect_success 'dies when no remote specified and no default remotes found' '\n \ttest_must_fail git ls-remote\n '\n@@ -131,7 +167,7 @@ test_expect_success 'Report no-match with --exit-code' '\n \n test_expect_success 'Report match with --exit-code' '\n \tgit ls-remote --exit-code other.git \"refs/tags/*\" >actual &&\n-\tgit ls-remote . tags/mark >expect &&\n+\tgit ls-remote . tags/mark* >expect &&\n \ttest_cmp expect actual\n '\n \n@@ -178,6 +214,9 @@ test_expect_success 'ls-remote --symref' '\n \t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/remotes/origin/HEAD\n \t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/remotes/origin/master\n \t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.1\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.10\n+\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark1.2\n \tEOF\n \tgit ls-remote --symref >actual &&\n \ttest_cmp expect actual\n-- \n2.14.3 (Apple Git-98)\n\n"},{"id":"344081","messageId":"CAPig+cTQ1ZzWTp6Qsj96nE8QwhuRuqB51orTNsCQjGKD=_veyg@mail.gmail.com","threadId":"48197","inReplyTo":"20180407164250.54303-1-haraldnordgren@gmail.com","subject":"Re: [PATCH v11 1/4] ref-filter: use \"struct object_id\" consistently","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2018-04-08T01:06:08Z","receivedAt":"2018-04-08T01:06:15Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Sat, Apr 7, 2018 at 12:42 PM, Harald Nordgren\n<haraldnordgren@gmail.com> wrote:\n> From: Jeff King <peff@peff.net>\n>\n> Internally we store a \"struct object_id\", and all of our\n> callers have one to pass us. But we insist that they peel it\n> to its bare-sha1 hash, which we then hashcpy() into place.\n> Let's pass it around as an object_id, which future-proofs us\n> for a post-sha1 world.\n> ---\n\nYou incorrectly dropped Peff's sign-off[1] when re-sending the patches\nhe authored in the series. And, your sign-off should follow his.\n\nAlso, if you made any changes to Peff's patch, it's a good idea to\nstate so with a bracketed comment at the end of the commit message\n(before the sign-offs). For instance:\n\n    [hn: tweaked doodle blap]\n\nor such.\n\n[1]: https://public-inbox.org/git/20180406185831.GA11108@sigill.intra.peff.net/\n"},{"id":"344084","messageId":"CAPig+cQnkvs8uPU-=woEzYC=mu1Bbi2u_TgH60aVUyh+m3DKDA@mail.gmail.com","threadId":"48197","inReplyTo":"20180407164250.54303-4-haraldnordgren@gmail.com","subject":"Re: [PATCH v11 4/4] ls-remote: create '--sort' option","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2018-04-08T01:48:10Z","receivedAt":"2018-04-08T01:48:59Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Sat, Apr 7, 2018 at 12:42 PM, Harald Nordgren\n<haraldnordgren@gmail.com> wrote:\n> Create a '--sort' option for ls-remote, based on the one from\n> for-each-ref. This e.g. allows ref names to be sorted by version\n> semantics, so that v1.2 is sorted before v1.10.\n>\n> Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com>\n> ---\n> diff --git a/Documentation/git-ls-remote.txt b/Documentation/git-ls-remote.txt\n> @@ -60,6 +60,19 @@ OPTIONS\n> +--sort=<key>::\n> +       Sort based on the key given.  Prefix `-` to sort in\n> +       descending order of the value. You may use the --sort=<key> option\n> +       multiple times, in which case the last key becomes the primary\n\nThis \"last becomes primary key\" feels counterintuitive to me, however,\nI see it mirrors precedence of other Git commands.\n\nIn what situations would it make sense to specify --sort= multiple\ntimes in the context of ls-remote? If there are none, then I wonder if\nthis should instead be documented as \"last wins\"...\n\n> +       key. Also supports \"version:refname\" or \"v:refname\" (tag\n\nTo what does \"Also\" refer?\n\n> +       names are treated as versions). The \"version:refname\" sort\n> +       order can also be affected by the \"versionsort.suffix\"\n> +       configuration variable.\n> +       The keys supported are the same as those in `git for-each-ref`,\n> +       except that because `ls-remote` deals only with remotes, keys like\n> +       `committerdate` that require access to the objects themselves will\n> +       not work.\n\nWhat does \"not work\" mean in this context? Will the command crash\noutright? Will it emit a suitable error message or warning? Will the\nsorting be somehow dysfunctional?\n\nIt seems like the sentence \"The keys supported...\" should go above the\n\"Also supports...\" sentence for this explanation to be more cohesive.\n\nFinally, how about adding a linkgit:git-for-each-ref[1] to give the\nuser an easy way to access the referenced documentation. For instance:\n\n    The keys supported are the same as those accepted by the\n    `--sort=` option of linkgit:git-for-each-ref[1], except...\n\n> diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c\n> @@ -43,10 +44,13 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n> +       struct ref_array array;\n> +       static struct ref_sorting *sorting = NULL, **sorting_tail = &sorting;\n> @@ -68,6 +74,8 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n> +       memset(&array, 0, sizeof(array));\n\nCan we have a more meaningful name than 'array'? Even a name a simple\nas 'refs' would convey more information.\n\n> @@ -104,13 +112,23 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n>         for ( ; ref; ref = ref->next) {\n> +               struct ref_array_item *item;\n>                 if (!check_ref_type(ref, flags))\n>                         continue;\n>                 if (!tail_match(pattern, ref->name))\n>                         continue;\n> +               item = ref_array_push(&array, ref->name, &ref->old_oid);\n> +               item->symref = xstrdup_or_null(ref->symref);\n\nDo we need to worry about freeing memory allocated by these two lines?\n\nMore generally, do we care that 'array' and 'sorting' are being\nleaked? If not, perhaps they should be annotated by UNLEAK.\n\n> +       }\n> diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh\n> @@ -39,6 +42,39 @@ test_expect_success 'ls-remote self' '\n> +test_expect_success 'ls-remote --sort=\"version:refname\" --tags self' '\n> +       cat >expect <<-\\EOF &&\n> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark\n> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark1.1\n> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark1.2\n> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark1.10\n> +       EOF\n> +       git ls-remote --sort=\"version:refname\" --tags self >actual &&\n> +       test_cmp expect actual\n> +'\n\nThis test script is already filled with these hardcoded SHA-1's, so\nthis is not a new problem, but work is under way to make it possible\nto replace SHA-1 with some other hashing algorithm. Test scripts are\nbeing retrofitted to avoid hard-coding them; instead determining the\nhash value dynamically (for example, [1]). It would be nice if the new\ntests followed suit, thus saving someone else extra work down the\nroad. (This, itself, is not worth a re-roll, but something to consider\nif you do re-roll.)\n\n[1]: https://public-inbox.org/git/20180325192055.841459-10-sandals@crustytoothpaste.net/\n\n> +test_expect_success 'ls-remote --sort=\"-version:refname\" --tags self' '\n> +       cat >expect <<-\\EOF &&\n> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark1.10\n> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark1.2\n> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark1.1\n> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark\n> +       EOF\n> +       git ls-remote --sort=\"-version:refname\" --tags self >actual &&\n> +       test_cmp expect actual\n> +'\n> +\n> +test_expect_success 'ls-remote --sort=\"-refname\" --tags self' '\n> +       cat >expect <<-\\EOF &&\n> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark1.2\n> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark1.10\n> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark1.1\n> +       1bd44cb9d13204b0fe1958db0082f5028a16eb3a        refs/tags/mark\n> +       EOF\n> +       git ls-remote --sort=\"-refname\" --tags self >actual &&\n> +       test_cmp expect actual\n> +'\n\nDo we want a test verifying that multiple sort keys are respected? (Is\nit even possible to construct such a test?)\n\n> @@ -131,7 +167,7 @@ test_expect_success 'Report no-match with --exit-code' '\n>  test_expect_success 'Report match with --exit-code' '\n>         git ls-remote --exit-code other.git \"refs/tags/*\" >actual &&\n> -       git ls-remote . tags/mark >expect &&\n> +       git ls-remote . tags/mark* >expect &&\n>         test_cmp expect actual\n>  '\n\nWhy this change?\n"},{"id":"344099","messageId":"CAHwyqnVWhwmDKhgoJ1p-UuxL-=pAczMCe3KdDbkhayh4n88jPg@mail.gmail.com","threadId":"48197","inReplyTo":"CAPig+cTQ1ZzWTp6Qsj96nE8QwhuRuqB51orTNsCQjGKD=_veyg@mail.gmail.com","subject":"Re: [PATCH v11 1/4] ref-filter: use \"struct object_id\" consistently","fromName":"Harald Nordgren","fromEmail":"haraldnordgren@gmail.com","sentAt":"2018-04-08T12:27:35Z","receivedAt":"2018-04-08T12:28:21Z","isPatch":true,"sender":{"key":"haraldnordgren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9569897?v=4"},"body":"Thanks for your very thorough review Eric! I think I address all the\npoints, but if I missed something please let me know.\n\n\nOn Sun, Apr 8, 2018 at 3:06 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n\n>\n> You incorrectly dropped Peff's sign-off[1] when re-sending the patches\n> he authored in the series. And, your sign-off should follow his.\n\nI just rebased on https://github.com/peff/git/tree/jk/ref-array-push\nwhere there were no sign-off tags.\n\nBut I amended the commit messages now to add the sign-off. And also\nadded my own sign-off.\n\n> Also, if you made any changes to Peff's patch, it's a good idea to\n> state so with a bracketed comment at the end of the commit message\n> (before the sign-offs). For instance:\n>\n>     [hn: tweaked doodle blap]\n>\n> or such.\n>\n> [1]: https://public-inbox.org/git/20180406185831.GA11108@sigill.intra.peff.net/\n\nAs a sign of respect I probably wouldn't want to tweak the patches.\n\nThey currently work well together with my implementation, so there is no need.\n\n> This \"last becomes primary key\" feels counterintuitive to me, however,\n> I see it mirrors precedence of other Git commands.\n>\n> In what situations would it make sense to specify --sort= multiple\n> times in the context of ls-remote? If there are none, then I wonder if\n> this should instead be documented as \"last wins\"...\n>\n> To what does \"Also\" refer?\n\nThis was copied wholesale from Documentation/git-tag.txt.\n\nI minimized the text now and removed all the references to using\n'sort' multiple times. Although you technically could use multiple\nkeys, since 'ls-remote' only outputs two columns, I guess it's never\nneeded.\n\n> What does \"not work\" mean in this context? Will the command crash\n> outright? Will it emit a suitable error message or warning? Will the\n> sorting be somehow dysfunctional?\n\nThis will be the output when trying to sort by commiterdate:\n\n    From git@github.com:git/git.git\n    fatal: missing object f0d0fd3a5985d5e588da1e1d11c85fba0ae132f8 for\nrefs/pull/10/head\n\nI added a a note in the documentation saying that it will \"cause a\nfailure\". Should we be even more explicit than that?\n\nThis is one side-effect of borrowing the ref-filter logic in this\npatch. We inherit things that won't work on remotes.\n\n> It seems like the sentence \"The keys supported...\" should go above the\n> \"Also supports...\" sentence for this explanation to be more cohesive.\n>\n> Finally, how about adding a linkgit:git-for-each-ref[1] to give the\n> user an easy way to access the referenced documentation. For instance:\n>\n>     The keys supported are the same as those accepted by the\n>     `--sort=` option of linkgit:git-for-each-ref[1], except...\n>\n\nAdded a \"linkgit\" to git-for-each-ref. And a \"See also\" section at the bottom.\n\n> Can we have a more meaningful name than 'array'? Even a name a simple\n> as 'refs' would convey more information.\n\nI think 'refs' would be confusing considering that the return value of\n'transport_get_remote_refs' is stored as 'ref'. I renamed it to\n'ref_array'. I hope it's not a problem that is shadows its struct\nname. But I've seen us this naming paradigm in other places -- and in\nthis file.\n\n> Do we need to worry about freeing memory allocated by these two lines?\n>\n> More generally, do we care that 'array' and 'sorting' are being\n> leaked? If not, perhaps they should be annotated by UNLEAK.\n\nSince 'cmd_ls_remote' is always (?) called from another process I\ndon't think we need to worry explicitly freeing the memory. I added\nUNLEAK annotations to my code.\n\n> This test script is already filled with these hardcoded SHA-1's, so\n> this is not a new problem, but work is under way to make it possible\n> to replace SHA-1 with some other hashing algorithm. Test scripts are\n> being retrofitted to avoid hard-coding them; instead determining the\n> hash value dynamically (for example, [1]). It would be nice if the new\n> tests followed suit, thus saving someone else extra work down the\n> road. (This, itself, is not worth a re-roll, but something to consider\n> if you do re-roll.)\n>\n> [1]: https://public-inbox.org/git/20180325192055.841459-10-sandals@crustytoothpaste.net/\n\nAdded 'git rev-parse' calls to my tests do decrease the reliance on\nSHA-1's. For the test\n\n    ls-remote --symref\n\nI couldn't figure out a way to extract the hash for\n'refs/remotes/origin/HEAD' so I re-used HEAD. I tried different ways\nof fetching origin, making another commit and pushing, but origin/HEAD\nis still unavailable.\n\nBy calling 'git fetch origin' before the test, at least I am able to\nextract 'git rev-parse refs/remotes/origin/master'.\n\nThis all makes the tests a bit more complicated, so I hope it helps us\nin the future! :)\n\n> Do we want a test verifying that multiple sort keys are respected? (Is\n> it even possible to construct such a test?)\n\nTo add to my previous point: Since 'ls-remote' outputs only two\ncolumns, I don't see a use case for multiple keys.\n\nAnd I don't know what the test would look like either.\n\n>> @@ -131,7 +167,7 @@ test_expect_success 'Report no-match with --exit-code' '\n>>  test_expect_success 'Report match with --exit-code' '\n>>         git ls-remote --exit-code other.git \"refs/tags/*\" >actual &&\n>> -       git ls-remote . tags/mark >expect &&\n>> +       git ls-remote . tags/mark* >expect &&\n>>         test_cmp expect actual\n>>  '\n>\n> Why this change?\n\nI added the asterisk to 'mark*' because without it, the test\n\n    Report match with --exit-code\n\nwill fail because the input 'git ls-remote refs/tags/*' now gives\ngives back more tags (mark, mark1.1, mark1.2, mark1.10). So I think\nthe asterisk is the cleanest solution to not have to create e.g. two\nseparate setup functions.\n"},{"id":"344100","messageId":"20180408122832.65414-1-haraldnordgren@gmail.com","threadId":"48197","inReplyTo":"20180402005248.52418-1-haraldnordgren@gmail.com","subject":"[PATCH v12 1/4] ref-filter: use \"struct object_id\" consistently","fromName":"Harald Nordgren","fromEmail":"haraldnordgren@gmail.com","sentAt":"2018-04-08T12:28:29Z","receivedAt":"2018-04-08T12:28:56Z","isPatch":true,"sender":{"key":"haraldnordgren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9569897?v=4"},"body":"From: Jeff King <peff@peff.net>\n\nInternally we store a \"struct object_id\", and all of our\ncallers have one to pass us. But we insist that they peel it\nto its bare-sha1 hash, which we then hashcpy() into place.\nLet's pass it around as an object_id, which future-proofs us\nfor a post-sha1 world.\n\nSigned-off-by: Jeff King <peff@peff.net>\nSigned-off-by: Harald Nordgren <haraldnordgren@gmail.com>\n---\n builtin/tag.c        |  2 +-\n builtin/verify-tag.c |  2 +-\n ref-filter.c         | 10 +++++-----\n ref-filter.h         |  2 +-\n 4 files changed, 8 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/tag.c b/builtin/tag.c\nindex da186691e..42278f516 100644\n--- a/builtin/tag.c\n+++ b/builtin/tag.c\n@@ -117,7 +117,7 @@ static int verify_tag(const char *name, const char *ref,\n \t\treturn -1;\n \n \tif (format->format)\n-\t\tpretty_print_ref(name, oid->hash, format);\n+\t\tpretty_print_ref(name, oid, format);\n \n \treturn 0;\n }\ndiff --git a/builtin/verify-tag.c b/builtin/verify-tag.c\nindex ad7b79fa5..6fa04b751 100644\n--- a/builtin/verify-tag.c\n+++ b/builtin/verify-tag.c\n@@ -72,7 +72,7 @@ int cmd_verify_tag(int argc, const char **argv, const char *prefix)\n \t\t}\n \n \t\tif (format.format)\n-\t\t\tpretty_print_ref(name, oid.hash, &format);\n+\t\t\tpretty_print_ref(name, &oid, &format);\n \t}\n \treturn had_error;\n }\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 45fc56216..ade97a848 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -1826,12 +1826,12 @@ static const struct object_id *match_points_at(struct oid_array *points_at,\n \n /* Allocate space for a new ref_array_item and copy the objectname and flag to it */\n static struct ref_array_item *new_ref_array_item(const char *refname,\n-\t\t\t\t\t\t const unsigned char *objectname,\n+\t\t\t\t\t\t const struct object_id *oid,\n \t\t\t\t\t\t int flag)\n {\n \tstruct ref_array_item *ref;\n \tFLEX_ALLOC_STR(ref, refname, refname);\n-\thashcpy(ref->objectname.hash, objectname);\n+\toidcpy(&ref->objectname, oid);\n \tref->flag = flag;\n \n \treturn ref;\n@@ -1927,7 +1927,7 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,\n \t * to do its job and the resulting list may yet to be pruned\n \t * by maxcount logic.\n \t */\n-\tref = new_ref_array_item(refname, oid->hash, flag);\n+\tref = new_ref_array_item(refname, oid, flag);\n \tref->commit = commit;\n \n \tREALLOC_ARRAY(ref_cbdata->array->items, ref_cbdata->array->nr + 1);\n@@ -2165,11 +2165,11 @@ void show_ref_array_item(struct ref_array_item *info,\n \tputchar('\\n');\n }\n \n-void pretty_print_ref(const char *name, const unsigned char *sha1,\n+void pretty_print_ref(const char *name, const struct object_id *oid,\n \t\t      const struct ref_format *format)\n {\n \tstruct ref_array_item *ref_item;\n-\tref_item = new_ref_array_item(name, sha1, 0);\n+\tref_item = new_ref_array_item(name, oid, 0);\n \tref_item->kind = ref_kind_from_refname(name);\n \tshow_ref_array_item(ref_item, format);\n \tfree_array_item(ref_item);\ndiff --git a/ref-filter.h b/ref-filter.h\nindex 0d98342b3..68268f9eb 100644\n--- a/ref-filter.h\n+++ b/ref-filter.h\n@@ -132,7 +132,7 @@ void setup_ref_filter_porcelain_msg(void);\n  * Print a single ref, outside of any ref-filter. Note that the\n  * name must be a fully qualified refname.\n  */\n-void pretty_print_ref(const char *name, const unsigned char *sha1,\n+void pretty_print_ref(const char *name, const struct object_id *oid,\n \t\t      const struct ref_format *format);\n \n #endif /*  REF_FILTER_H  */\n-- \n2.14.3 (Apple Git-98)\n\n"},{"id":"344101","messageId":"20180408122832.65414-3-haraldnordgren@gmail.com","threadId":"48197","inReplyTo":"20180408122832.65414-1-haraldnordgren@gmail.com","subject":"[PATCH v12 3/4] ref-filter: factor ref_array pushing into its own function","fromName":"Harald Nordgren","fromEmail":"haraldnordgren@gmail.com","sentAt":"2018-04-08T12:28:31Z","receivedAt":"2018-04-08T12:28:59Z","isPatch":true,"sender":{"key":"haraldnordgren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9569897?v=4"},"body":"From: Jeff King <peff@peff.net>\n\nIn preparation for callers constructing their own ref_array\nstructs, let's move our own internal push operation into its\nown function.\n\nWhile we're at it, we can replace REALLOC_ARRAY() with\nALLOC_GROW(), which should give the growth operation\namortized linear complexity (as opposed to growing by one,\nwhich is potentially quadratic, though in-place realloc\ngrowth often makes this faster in practice).\n\nSigned-off-by: Jeff King <peff@peff.net>\nSigned-off-by: Harald Nordgren <haraldnordgren@gmail.com>\n---\n ref-filter.c | 16 +++++++++++++---\n ref-filter.h |  8 ++++++++\n 2 files changed, 21 insertions(+), 3 deletions(-)\n\ndiff --git a/ref-filter.c b/ref-filter.c\nindex c1c3cc948..6e9328b27 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -1840,6 +1840,18 @@ static struct ref_array_item *new_ref_array_item(const char *refname,\n \treturn ref;\n }\n \n+struct ref_array_item *ref_array_push(struct ref_array *array,\n+\t\t\t\t      const char *refname,\n+\t\t\t\t      const struct object_id *oid)\n+{\n+\tstruct ref_array_item *ref = new_ref_array_item(refname, oid);\n+\n+\tALLOC_GROW(array->items, array->nr + 1, array->alloc);\n+\tarray->items[array->nr++] = ref;\n+\n+\treturn ref;\n+}\n+\n static int ref_kind_from_refname(const char *refname)\n {\n \tunsigned int i;\n@@ -1930,13 +1942,11 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,\n \t * to do its job and the resulting list may yet to be pruned\n \t * by maxcount logic.\n \t */\n-\tref = new_ref_array_item(refname, oid);\n+\tref = ref_array_push(ref_cbdata->array, refname, oid);\n \tref->commit = commit;\n \tref->flag = flag;\n \tref->kind = kind;\n \n-\tREALLOC_ARRAY(ref_cbdata->array->items, ref_cbdata->array->nr + 1);\n-\tref_cbdata->array->items[ref_cbdata->array->nr++] = ref;\n \treturn 0;\n }\n \ndiff --git a/ref-filter.h b/ref-filter.h\nindex 68268f9eb..76cf87cb6 100644\n--- a/ref-filter.h\n+++ b/ref-filter.h\n@@ -135,4 +135,12 @@ void setup_ref_filter_porcelain_msg(void);\n void pretty_print_ref(const char *name, const struct object_id *oid,\n \t\t      const struct ref_format *format);\n \n+/*\n+ * Push a single ref onto the array; this can be used to construct your own\n+ * ref_array without using filter_refs().\n+ */\n+struct ref_array_item *ref_array_push(struct ref_array *array,\n+\t\t\t\t      const char *refname,\n+\t\t\t\t      const struct object_id *oid);\n+\n #endif /*  REF_FILTER_H  */\n-- \n2.14.3 (Apple Git-98)\n\n"},{"id":"344102","messageId":"20180408122832.65414-4-haraldnordgren@gmail.com","threadId":"48197","inReplyTo":"20180408122832.65414-1-haraldnordgren@gmail.com","subject":"[PATCH v12 4/4] ls-remote: create '--sort' option","fromName":"Harald Nordgren","fromEmail":"haraldnordgren@gmail.com","sentAt":"2018-04-08T12:28:32Z","receivedAt":"2018-04-08T12:29:02Z","isPatch":true,"sender":{"key":"haraldnordgren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9569897?v=4"},"body":"Create a '--sort' option for ls-remote, based on the one from\nfor-each-ref. This e.g. allows ref names to be sorted by version\nsemantics, so that v1.2 is sorted before v1.10.\n\nSigned-off-by: Harald Nordgren <haraldnordgren@gmail.com>\n---\n\nNotes:\n    Changes according to Eric Sunshine's code review\n\n Documentation/git-ls-remote.txt | 16 ++++++++++++-\n builtin/ls-remote.c             | 30 +++++++++++++++++++++---\n t/t5512-ls-remote.sh            | 52 ++++++++++++++++++++++++++++++++++++-----\n 3 files changed, 88 insertions(+), 10 deletions(-)\n\ndiff --git a/Documentation/git-ls-remote.txt b/Documentation/git-ls-remote.txt\nindex 5f2628c8f..80a09b518 100644\n--- a/Documentation/git-ls-remote.txt\n+++ b/Documentation/git-ls-remote.txt\n@@ -10,7 +10,7 @@ SYNOPSIS\n --------\n [verse]\n 'git ls-remote' [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n-\t      [-q | --quiet] [--exit-code] [--get-url]\n+\t      [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n \t      [--symref] [<repository> [<refs>...]]\n \n DESCRIPTION\n@@ -60,6 +60,16 @@ OPTIONS\n \tupload-pack only shows the symref HEAD, so it will be the only\n \tone shown by ls-remote.\n \n+--sort=<key>::\n+\tSort based on the key given. Prefix `-` to sort in descending order\n+\tof the value. Supports \"version:refname\" or \"v:refname\" (tag names\n+\tare treated as versions). The \"version:refname\" sort order can also\n+\tbe affected by the \"versionsort.suffix\" configuration variable.\n+\tSee linkgit:git-for-each-ref[1] for more sort options, but be aware\n+\tthat because `ls-remote` deals only with remotes, any key like\n+\t`committerdate` that requires access to the object itself will\n+\tcause a failure.\n+\n <repository>::\n \tThe \"remote\" repository to query.  This parameter can be\n \teither a URL or the name of a remote (see the GIT URLS and\n@@ -90,6 +100,10 @@ EXAMPLES\n \tc5db5456ae3b0873fc659c19fafdde22313cc441\trefs/tags/v0.99.2\n \t7ceca275d047c90c0c7d5afb13ab97efdf51bd6e\trefs/tags/v0.99.3\n \n+SEE ALSO\n+--------\n+linkgit:git-check-ref-format[1].\n+\n GIT\n ---\n Part of the linkgit:git[1] suite\ndiff --git a/builtin/ls-remote.c b/builtin/ls-remote.c\nindex 540d56429..d3851074c 100644\n--- a/builtin/ls-remote.c\n+++ b/builtin/ls-remote.c\n@@ -1,6 +1,7 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n #include \"transport.h\"\n+#include \"ref-filter.h\"\n #include \"remote.h\"\n \n static const char * const ls_remote_usage[] = {\n@@ -43,10 +44,13 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \tint show_symref_target = 0;\n \tconst char *uploadpack = NULL;\n \tconst char **pattern = NULL;\n+\tint i;\n \n \tstruct remote *remote;\n \tstruct transport *transport;\n \tconst struct ref *ref;\n+\tstruct ref_array ref_array;\n+\tstatic struct ref_sorting *sorting = NULL, **sorting_tail = &sorting;\n \n \tstruct option options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"do not print remote URL\")),\n@@ -60,6 +64,8 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \t\tOPT_BIT(0, \"refs\", &flags, N_(\"do not show peeled tags\"), REF_NORMAL),\n \t\tOPT_BOOL(0, \"get-url\", &get_url,\n \t\t\t N_(\"take url.<base>.insteadOf into account\")),\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\tOPT_SET_INT_F(0, \"exit-code\", &status,\n \t\t\t      N_(\"exit with exit code 2 if no matching refs are found\"),\n \t\t\t      2, PARSE_OPT_NOCOMPLETE),\n@@ -68,6 +74,8 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \t\tOPT_END()\n \t};\n \n+\tmemset(&ref_array, 0, sizeof(ref_array));\n+\n \targc = parse_options(argc, argv, prefix, options, ls_remote_usage,\n \t\t\t     PARSE_OPT_STOP_AT_NON_OPTION);\n \tdest = argv[0];\n@@ -90,6 +98,7 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \n \tif (get_url) {\n \t\tprintf(\"%s\\n\", *remote->url);\n+\t\tUNLEAK(sorting);\n \t\treturn 0;\n \t}\n \n@@ -98,20 +107,35 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \t\ttransport_set_option(transport, TRANS_OPT_UPLOADPACK, uploadpack);\n \n \tref = transport_get_remote_refs(transport);\n-\tif (transport_disconnect(transport))\n+\tif (transport_disconnect(transport)) {\n+\t\tUNLEAK(sorting);\n \t\treturn 1;\n+\t}\n \n \tif (!dest && !quiet)\n \t\tfprintf(stderr, \"From %s\\n\", *remote->url);\n \tfor ( ; ref; ref = ref->next) {\n+\t\tstruct ref_array_item *item;\n \t\tif (!check_ref_type(ref, flags))\n \t\t\tcontinue;\n \t\tif (!tail_match(pattern, ref->name))\n \t\t\tcontinue;\n+\t\titem = ref_array_push(&ref_array, ref->name, &ref->old_oid);\n+\t\titem->symref = xstrdup_or_null(ref->symref);\n+\t}\n+\n+\tif (sorting)\n+\t\tref_array_sort(sorting, &ref_array);\n+\n+\tfor (i = 0; i < ref_array.nr; i++) {\n+\t\tconst struct ref_array_item *ref = ref_array.items[i];\n \t\tif (show_symref_target && ref->symref)\n-\t\t\tprintf(\"ref: %s\\t%s\\n\", ref->symref, ref->name);\n-\t\tprintf(\"%s\\t%s\\n\", oid_to_hex(&ref->old_oid), ref->name);\n+\t\t\tprintf(\"ref: %s\\t%s\\n\", ref->symref, ref->refname);\n+\t\tprintf(\"%s\\t%s\\n\", oid_to_hex(&ref->objectname), ref->refname);\n \t\tstatus = 0; /* we found something */\n \t}\n+\n+\tUNLEAK(sorting);\n+\tUNLEAK(ref_array);\n \treturn status;\n }\ndiff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh\nindex 02106c922..e8df4c7e0 100755\n--- a/t/t5512-ls-remote.sh\n+++ b/t/t5512-ls-remote.sh\n@@ -10,6 +10,9 @@ test_expect_success setup '\n \ttest_tick &&\n \tgit commit -m initial &&\n \tgit tag mark &&\n+\tgit tag mark1.1 &&\n+\tgit tag mark1.2 &&\n+\tgit tag mark1.10 &&\n \tgit show-ref --tags -d | sed -e \"s/ /\t/\" >expected.tag &&\n \t(\n \t\techo \"$(git rev-parse HEAD)\tHEAD\"\n@@ -39,6 +42,39 @@ test_expect_success 'ls-remote self' '\n \ttest_cmp expected.all actual\n '\n \n+test_expect_success 'ls-remote --sort=\"version:refname\" --tags self' '\n+\tcat >expect <<-\\EOF &&\n+\t'$(git rev-parse mark)'\trefs/tags/mark\n+\t'$(git rev-parse mark1.1)'\trefs/tags/mark1.1\n+\t'$(git rev-parse mark1.2)'\trefs/tags/mark1.2\n+\t'$(git rev-parse mark1.10)'\trefs/tags/mark1.10\n+\tEOF\n+\tgit ls-remote --sort=\"version:refname\" --tags self >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'ls-remote --sort=\"-version:refname\" --tags self' '\n+\tcat >expect <<-\\EOF &&\n+\t'$(git rev-parse mark1.10)'\trefs/tags/mark1.10\n+\t'$(git rev-parse mark1.2)'\trefs/tags/mark1.2\n+\t'$(git rev-parse mark1.1)'\trefs/tags/mark1.1\n+\t'$(git rev-parse mark)'\trefs/tags/mark\n+\tEOF\n+\tgit ls-remote --sort=\"-version:refname\" --tags self >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'ls-remote --sort=\"-refname\" --tags self' '\n+\tcat >expect <<-\\EOF &&\n+\t'$(git rev-parse mark1.2)'\trefs/tags/mark1.2\n+\t'$(git rev-parse mark1.10)'\trefs/tags/mark1.10\n+\t'$(git rev-parse mark1.1)'\trefs/tags/mark1.1\n+\t'$(git rev-parse mark)'\trefs/tags/mark\n+\tEOF\n+\tgit ls-remote --sort=\"-refname\" --tags self >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_expect_success 'dies when no remote specified and no default remotes found' '\n \ttest_must_fail git ls-remote\n '\n@@ -131,7 +167,7 @@ test_expect_success 'Report no-match with --exit-code' '\n \n test_expect_success 'Report match with --exit-code' '\n \tgit ls-remote --exit-code other.git \"refs/tags/*\" >actual &&\n-\tgit ls-remote . tags/mark >expect &&\n+\tgit ls-remote . tags/mark* >expect &&\n \ttest_cmp expect actual\n '\n \n@@ -170,14 +206,18 @@ test_expect_success 'overrides work between mixed transfer/upload-pack hideRefs'\n \tgrep refs/tags/magic actual\n '\n \n+git fetch origin\n test_expect_success 'ls-remote --symref' '\n \tcat >expect <<-\\EOF &&\n \tref: refs/heads/master\tHEAD\n-\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\tHEAD\n-\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/heads/master\n-\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/remotes/origin/HEAD\n-\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/remotes/origin/master\n-\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark\n+\t'$(git rev-parse HEAD)'\tHEAD\n+\t'$(git rev-parse refs/heads/master)'\trefs/heads/master\n+\t'$(git rev-parse HEAD)'\trefs/remotes/origin/HEAD\n+\t'$(git rev-parse refs/remotes/origin/master)'\trefs/remotes/origin/master\n+\t'$(git rev-parse refs/tags/mark)'\trefs/tags/mark\n+\t'$(git rev-parse refs/tags/mark1.1)'\trefs/tags/mark1.1\n+\t'$(git rev-parse refs/tags/mark1.10)'\trefs/tags/mark1.10\n+\t'$(git rev-parse refs/tags/mark1.2)'\trefs/tags/mark1.2\n \tEOF\n \tgit ls-remote --symref >actual &&\n \ttest_cmp expect actual\n-- \n2.14.3 (Apple Git-98)\n\n"},{"id":"344103","messageId":"20180408122832.65414-2-haraldnordgren@gmail.com","threadId":"48197","inReplyTo":"20180408122832.65414-1-haraldnordgren@gmail.com","subject":"[PATCH v12 2/4] ref-filter: make ref_array_item allocation more consistent","fromName":"Harald Nordgren","fromEmail":"haraldnordgren@gmail.com","sentAt":"2018-04-08T12:28:30Z","receivedAt":"2018-04-08T12:29:05Z","isPatch":true,"sender":{"key":"haraldnordgren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9569897?v=4"},"body":"From: Jeff King <peff@peff.net>\n\nWe have a helper function to allocate ref_array_item\nstructs, but it only takes a subset of the possible fields\nin the struct as initializers. We could have it accept an\nargument for _every_ field, but that becomes a pain for the\nfields which some callers don't want to set initially.\n\nInstead, let's be explicit that it takes only the minimum\nrequired to create the ref, and that callers should then\nfill in the rest themselves.\n\nSigned-off-by: Jeff King <peff@peff.net>\nSigned-off-by: Harald Nordgren <haraldnordgren@gmail.com>\n---\n ref-filter.c | 18 +++++++++++-------\n 1 file changed, 11 insertions(+), 7 deletions(-)\n\ndiff --git a/ref-filter.c b/ref-filter.c\nindex ade97a848..c1c3cc948 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -1824,15 +1824,18 @@ static const struct object_id *match_points_at(struct oid_array *points_at,\n \treturn NULL;\n }\n \n-/* Allocate space for a new ref_array_item and copy the objectname and flag to it */\n+/*\n+ * Allocate space for a new ref_array_item and copy the name and oid to it.\n+ *\n+ * Callers can then fill in other struct members at their leisure.\n+ */\n static struct ref_array_item *new_ref_array_item(const char *refname,\n-\t\t\t\t\t\t const struct object_id *oid,\n-\t\t\t\t\t\t int flag)\n+\t\t\t\t\t\t const struct object_id *oid)\n {\n \tstruct ref_array_item *ref;\n+\n \tFLEX_ALLOC_STR(ref, refname, refname);\n \toidcpy(&ref->objectname, oid);\n-\tref->flag = flag;\n \n \treturn ref;\n }\n@@ -1927,12 +1930,13 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,\n \t * to do its job and the resulting list may yet to be pruned\n \t * by maxcount logic.\n \t */\n-\tref = new_ref_array_item(refname, oid, flag);\n+\tref = new_ref_array_item(refname, oid);\n \tref->commit = commit;\n+\tref->flag = flag;\n+\tref->kind = kind;\n \n \tREALLOC_ARRAY(ref_cbdata->array->items, ref_cbdata->array->nr + 1);\n \tref_cbdata->array->items[ref_cbdata->array->nr++] = ref;\n-\tref->kind = kind;\n \treturn 0;\n }\n \n@@ -2169,7 +2173,7 @@ void pretty_print_ref(const char *name, const struct object_id *oid,\n \t\t      const struct ref_format *format)\n {\n \tstruct ref_array_item *ref_item;\n-\tref_item = new_ref_array_item(name, oid, 0);\n+\tref_item = new_ref_array_item(name, oid);\n \tref_item->kind = ref_kind_from_refname(name);\n \tshow_ref_array_item(ref_item, format);\n \tfree_array_item(ref_item);\n-- \n2.14.3 (Apple Git-98)\n\n"},{"id":"344117","messageId":"xmqq7eph9wds.fsf@gitster-ct.c.googlers.com","threadId":"48197","inReplyTo":"20180408122832.65414-4-haraldnordgren@gmail.com","subject":"Re: [PATCH v12 4/4] ls-remote: create '--sort' option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-04-08T22:16:47Z","receivedAt":"2018-04-08T22:16:56Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Harald Nordgren <haraldnordgren@gmail.com> writes:\n\n> +--sort=<key>::\n> +\tSort based on the key given. Prefix `-` to sort in descending order\n> +\tof the value. Supports \"version:refname\" or \"v:refname\" (tag names\n> +\tare treated as versions). The \"version:refname\" sort order can also\n> +\tbe affected by the \"versionsort.suffix\" configuration variable.\n> +\tSee linkgit:git-for-each-ref[1] for more sort options, but be aware\n> +\tthat because `ls-remote` deals only with remotes, any key like\n> +\t`committerdate` that requires access to the object itself will\n> +\tcause a failure.\n\nI can connect \"because it deals only with remotes\" and \"access to\nthe object may fail\", but I wonder if we can clarify the former a\nbit better to make it easier to understand for those who are not yet\nfamiliar with Git.  \n\n    Keys like `committerdate` that require access to the object will\n    not work [***HOW??? Do we get a segfault or something???***] for\n    refs whose objects have not yet been fetched from the remote.\n\nI added \"for refs whose objects have not yet been fetched\", whose\nexplicit-ness made \"will not work\" to be an OK expression, but\nwithout it I would have suggested to rephrase it to \"may not work\".\n\nThis is a tangent but I suspect that the description of --sort in\ngit-for-each-ref documentation is wrong on the use of multiple\noptions, or I am misreading parse_opt_ref_sorting(), which I think\nappends later keys to the end of the list, and compare_refs() which\nI think yields results when an earlier key in the last decides two\nare not equal and ignores the later keys.  The commit that added the\ndescription was c0f6dc9b (\"git-for-each-ref.txt: minor\nimprovements\", 2008-06-05), and I think even back then the code in\nbuiltin-for-each-ref.c appended later keys at the end, and it seems\nnobody complained, so it is possible I am not reading the code right\nbefore fully adjusting to timezone change ;-)\n\n> +\tfor (i = 0; i < ref_array.nr; i++) {\n> +\t\tconst struct ref_array_item *ref = ref_array.items[i];\n>  \t\tif (show_symref_target && ref->symref)\n> -\t\t\tprintf(\"ref: %s\\t%s\\n\", ref->symref, ref->name);\n> -\t\tprintf(\"%s\\t%s\\n\", oid_to_hex(&ref->old_oid), ref->name);\n> +\t\t\tprintf(\"ref: %s\\t%s\\n\", ref->symref, ref->refname);\n> +\t\tprintf(\"%s\\t%s\\n\", oid_to_hex(&ref->objectname), ref->refname);\n>  \t\tstatus = 0; /* we found something */\n>  \t}\n> +\n> +\tUNLEAK(sorting);\n> +\tUNLEAK(ref_array);\n>  \treturn status;\n>  }\n\nIt is not too big a deal, but I find that liberal sprinkling of\nUNLEAK() is somewhat unsightly.  From the code we leave with this\nchange, it is clear what we'd need to do when we make the code fully\nleak-proof (i.e. we'd have a several lines to free resources held by\nthese two variables here, and then UNLEAK() that appear earlier in\nthe function will become a \"goto cleanup;\" after setting appropriate\nvalue to \"status\"), so let's not worry about it.\n\n> +test_expect_success 'ls-remote --sort=\"version:refname\" --tags self' '\n> +\tcat >expect <<-\\EOF &&\n> +\t'$(git rev-parse mark)'\trefs/tags/mark\n> +\t'$(git rev-parse mark1.1)'\trefs/tags/mark1.1\n> +\t'$(git rev-parse mark1.2)'\trefs/tags/mark1.2\n> +\t'$(git rev-parse mark1.10)'\trefs/tags/mark1.10\n> +\tEOF\n\nPlease do *NOT* step outside the pair of single quotes that protects\nthe body of the test scriptlet and execute commands like \"git\nrev-parse\".  These execute in order to prepare the command line\nargument strings BEFORE test_expect_success can run (or the test\nframework decides if the test will be skipped via GIT_TEST_SKIP).\n\nInstead do it like so:\n\n\tcat >expect <<-EOF &&\n\t$(git rev-parse mark)\trefs/tags/mark\n\t$(git rev-parse mark1.1)\trefs/tags/mark1.1\n\t$(git rev-parse mark1.2)\trefs/tags/mark1.2\n\t$(git rev-parse mark1.10)\trefs/tags/mark1.10\n\tEOF\n\nI.e. the end token for << that is not quoted allows $var and $(cmd)\nto be substituted.\n\nSame comment applies throughout the remainder of this file.\n\nOther than that, this patch was a very pleasant read.  Thanks.\n\n\n"},{"id":"344125","messageId":"xmqqy3hx70dw.fsf@gitster-ct.c.googlers.com","threadId":"48197","inReplyTo":"20180406185945.GC11108@sigill.intra.peff.net","subject":"Re: [PATCH 3/3] ref-filter: factor ref_array pushing into its own function","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-04-08T23:18:35Z","receivedAt":"2018-04-08T23:18:41Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> In preparation for callers constructing their own ref_array\n> structs, let's move our own internal push operation into its\n> own function.\n>\n> While we're at it, we can replace REALLOC_ARRAY() with\n> ALLOC_GROW(), which should give the growth operation\n> amortized linear complexity (as opposed to growing by one,\n> which is potentially quadratic, though in-place realloc\n> growth often makes this faster in practice).\n\nSorry, but I do not quite get the last part this paragraph.  Up to\nbut not including \", though in-place...\" I would understand as:\n\n     - With ALLOC_GROW(), we are explicit in that we are amortizing\n       the allocation cost by growing in exponential batches.\n\n     - With REALLOC_ARRAY(), we are telling the underlying\n       realloc(3) that it is OK to pretend that we grow by one, but\n       if that permission is literally followed, it could end up\n       quadratic.\n\n    So if you have really a bad realloc(3) implementation, switching\n    to use ALLOC_GROW() is an improvement.\n\nBut after that I am not sure what you are getting at.  Do you mean\n\"In practice, a well-done realloc(3) does the amortizing internally\nanyway, which makes it faster than the grow-by-one quadratic, so\nthis change may not make that much of a difference\"?  Or do you mean\n\"In practice, a well-done realloc(3) internally amortizes better\nthan we do manually, so this change may hurt performance\"?\n\nIn either case, I think this splitting into a helper is obviously a\ngood move, and using ALLOC_GROW() is conceptually cleaner, as we use\nit everywhere and tend to avoid realloc(3) just to add one item.\n\nOther than that small confusion (not even a nit), three patches were\npleasant read.  Thanks.\n"},{"id":"344129","messageId":"20180408235815.36582-1-haraldnordgren@gmail.com","threadId":"48197","inReplyTo":"20180402005248.52418-1-haraldnordgren@gmail.com","subject":"[PATCH v13 1/4] ref-filter: use \"struct object_id\" consistently","fromName":"Harald Nordgren","fromEmail":"haraldnordgren@gmail.com","sentAt":"2018-04-08T23:58:12Z","receivedAt":"2018-04-08T23:58:37Z","isPatch":true,"sender":{"key":"haraldnordgren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9569897?v=4"},"body":"From: Jeff King <peff@peff.net>\n\nInternally we store a \"struct object_id\", and all of our\ncallers have one to pass us. But we insist that they peel it\nto its bare-sha1 hash, which we then hashcpy() into place.\nLet's pass it around as an object_id, which future-proofs us\nfor a post-sha1 world.\n\nSigned-off-by: Jeff King <peff@peff.net>\nSigned-off-by: Harald Nordgren <haraldnordgren@gmail.com>\n---\n builtin/tag.c        |  2 +-\n builtin/verify-tag.c |  2 +-\n ref-filter.c         | 10 +++++-----\n ref-filter.h         |  2 +-\n 4 files changed, 8 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/tag.c b/builtin/tag.c\nindex da186691e..42278f516 100644\n--- a/builtin/tag.c\n+++ b/builtin/tag.c\n@@ -117,7 +117,7 @@ static int verify_tag(const char *name, const char *ref,\n \t\treturn -1;\n \n \tif (format->format)\n-\t\tpretty_print_ref(name, oid->hash, format);\n+\t\tpretty_print_ref(name, oid, format);\n \n \treturn 0;\n }\ndiff --git a/builtin/verify-tag.c b/builtin/verify-tag.c\nindex ad7b79fa5..6fa04b751 100644\n--- a/builtin/verify-tag.c\n+++ b/builtin/verify-tag.c\n@@ -72,7 +72,7 @@ int cmd_verify_tag(int argc, const char **argv, const char *prefix)\n \t\t}\n \n \t\tif (format.format)\n-\t\t\tpretty_print_ref(name, oid.hash, &format);\n+\t\t\tpretty_print_ref(name, &oid, &format);\n \t}\n \treturn had_error;\n }\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 45fc56216..ade97a848 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -1826,12 +1826,12 @@ static const struct object_id *match_points_at(struct oid_array *points_at,\n \n /* Allocate space for a new ref_array_item and copy the objectname and flag to it */\n static struct ref_array_item *new_ref_array_item(const char *refname,\n-\t\t\t\t\t\t const unsigned char *objectname,\n+\t\t\t\t\t\t const struct object_id *oid,\n \t\t\t\t\t\t int flag)\n {\n \tstruct ref_array_item *ref;\n \tFLEX_ALLOC_STR(ref, refname, refname);\n-\thashcpy(ref->objectname.hash, objectname);\n+\toidcpy(&ref->objectname, oid);\n \tref->flag = flag;\n \n \treturn ref;\n@@ -1927,7 +1927,7 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,\n \t * to do its job and the resulting list may yet to be pruned\n \t * by maxcount logic.\n \t */\n-\tref = new_ref_array_item(refname, oid->hash, flag);\n+\tref = new_ref_array_item(refname, oid, flag);\n \tref->commit = commit;\n \n \tREALLOC_ARRAY(ref_cbdata->array->items, ref_cbdata->array->nr + 1);\n@@ -2165,11 +2165,11 @@ void show_ref_array_item(struct ref_array_item *info,\n \tputchar('\\n');\n }\n \n-void pretty_print_ref(const char *name, const unsigned char *sha1,\n+void pretty_print_ref(const char *name, const struct object_id *oid,\n \t\t      const struct ref_format *format)\n {\n \tstruct ref_array_item *ref_item;\n-\tref_item = new_ref_array_item(name, sha1, 0);\n+\tref_item = new_ref_array_item(name, oid, 0);\n \tref_item->kind = ref_kind_from_refname(name);\n \tshow_ref_array_item(ref_item, format);\n \tfree_array_item(ref_item);\ndiff --git a/ref-filter.h b/ref-filter.h\nindex 0d98342b3..68268f9eb 100644\n--- a/ref-filter.h\n+++ b/ref-filter.h\n@@ -132,7 +132,7 @@ void setup_ref_filter_porcelain_msg(void);\n  * Print a single ref, outside of any ref-filter. Note that the\n  * name must be a fully qualified refname.\n  */\n-void pretty_print_ref(const char *name, const unsigned char *sha1,\n+void pretty_print_ref(const char *name, const struct object_id *oid,\n \t\t      const struct ref_format *format);\n \n #endif /*  REF_FILTER_H  */\n-- \n2.14.3 (Apple Git-98)\n\n"},{"id":"344130","messageId":"20180408235815.36582-2-haraldnordgren@gmail.com","threadId":"48197","inReplyTo":"20180408235815.36582-1-haraldnordgren@gmail.com","subject":"[PATCH v13 2/4] ref-filter: make ref_array_item allocation more consistent","fromName":"Harald Nordgren","fromEmail":"haraldnordgren@gmail.com","sentAt":"2018-04-08T23:58:13Z","receivedAt":"2018-04-08T23:58:39Z","isPatch":true,"sender":{"key":"haraldnordgren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9569897?v=4"},"body":"From: Jeff King <peff@peff.net>\n\nWe have a helper function to allocate ref_array_item\nstructs, but it only takes a subset of the possible fields\nin the struct as initializers. We could have it accept an\nargument for _every_ field, but that becomes a pain for the\nfields which some callers don't want to set initially.\n\nInstead, let's be explicit that it takes only the minimum\nrequired to create the ref, and that callers should then\nfill in the rest themselves.\n\nSigned-off-by: Jeff King <peff@peff.net>\nSigned-off-by: Harald Nordgren <haraldnordgren@gmail.com>\n---\n ref-filter.c | 18 +++++++++++-------\n 1 file changed, 11 insertions(+), 7 deletions(-)\n\ndiff --git a/ref-filter.c b/ref-filter.c\nindex ade97a848..c1c3cc948 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -1824,15 +1824,18 @@ static const struct object_id *match_points_at(struct oid_array *points_at,\n \treturn NULL;\n }\n \n-/* Allocate space for a new ref_array_item and copy the objectname and flag to it */\n+/*\n+ * Allocate space for a new ref_array_item and copy the name and oid to it.\n+ *\n+ * Callers can then fill in other struct members at their leisure.\n+ */\n static struct ref_array_item *new_ref_array_item(const char *refname,\n-\t\t\t\t\t\t const struct object_id *oid,\n-\t\t\t\t\t\t int flag)\n+\t\t\t\t\t\t const struct object_id *oid)\n {\n \tstruct ref_array_item *ref;\n+\n \tFLEX_ALLOC_STR(ref, refname, refname);\n \toidcpy(&ref->objectname, oid);\n-\tref->flag = flag;\n \n \treturn ref;\n }\n@@ -1927,12 +1930,13 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,\n \t * to do its job and the resulting list may yet to be pruned\n \t * by maxcount logic.\n \t */\n-\tref = new_ref_array_item(refname, oid, flag);\n+\tref = new_ref_array_item(refname, oid);\n \tref->commit = commit;\n+\tref->flag = flag;\n+\tref->kind = kind;\n \n \tREALLOC_ARRAY(ref_cbdata->array->items, ref_cbdata->array->nr + 1);\n \tref_cbdata->array->items[ref_cbdata->array->nr++] = ref;\n-\tref->kind = kind;\n \treturn 0;\n }\n \n@@ -2169,7 +2173,7 @@ void pretty_print_ref(const char *name, const struct object_id *oid,\n \t\t      const struct ref_format *format)\n {\n \tstruct ref_array_item *ref_item;\n-\tref_item = new_ref_array_item(name, oid, 0);\n+\tref_item = new_ref_array_item(name, oid);\n \tref_item->kind = ref_kind_from_refname(name);\n \tshow_ref_array_item(ref_item, format);\n \tfree_array_item(ref_item);\n-- \n2.14.3 (Apple Git-98)\n\n"},{"id":"344131","messageId":"20180408235815.36582-4-haraldnordgren@gmail.com","threadId":"48197","inReplyTo":"20180408235815.36582-1-haraldnordgren@gmail.com","subject":"[PATCH v13 4/4] ls-remote: create '--sort' option","fromName":"Harald Nordgren","fromEmail":"haraldnordgren@gmail.com","sentAt":"2018-04-08T23:58:15Z","receivedAt":"2018-04-08T23:58:44Z","isPatch":true,"sender":{"key":"haraldnordgren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9569897?v=4"},"body":"Create a '--sort' option for ls-remote, based on the one from\nfor-each-ref. This e.g. allows ref names to be sorted by version\nsemantics, so that v1.2 is sorted before v1.10.\n\nSigned-off-by: Harald Nordgren <haraldnordgren@gmail.com>\n---\n\nNotes:\n    Changes according to Junio Hamano's code review\n\n Documentation/git-ls-remote.txt | 17 ++++++++++++-\n builtin/ls-remote.c             | 25 +++++++++++++++++--\n t/t5512-ls-remote.sh            | 54 +++++++++++++++++++++++++++++++++++------\n 3 files changed, 86 insertions(+), 10 deletions(-)\n\ndiff --git a/Documentation/git-ls-remote.txt b/Documentation/git-ls-remote.txt\nindex 5f2628c8f..0e26a67a1 100644\n--- a/Documentation/git-ls-remote.txt\n+++ b/Documentation/git-ls-remote.txt\n@@ -10,7 +10,7 @@ SYNOPSIS\n --------\n [verse]\n 'git ls-remote' [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n-\t      [-q | --quiet] [--exit-code] [--get-url]\n+\t      [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n \t      [--symref] [<repository> [<refs>...]]\n \n DESCRIPTION\n@@ -60,6 +60,17 @@ OPTIONS\n \tupload-pack only shows the symref HEAD, so it will be the only\n \tone shown by ls-remote.\n \n+--sort=<key>::\n+\tSort based on the key given. Prefix `-` to sort in descending order\n+\tof the value. Supports \"version:refname\" or \"v:refname\" (tag names\n+\tare treated as versions). The \"version:refname\" sort order can also\n+\tbe affected by the \"versionsort.suffix\" configuration variable.\n+\tSee linkgit:git-for-each-ref[1] for more sort options, but be aware\n+\tthat because `ls-remote` deals only with remotes, keys like\n+\t`committerdate` that requires access to the objects themselves will\n+\tnot work for refs whose objects have not yet been fetched from the\n+\tremote.\n+\n <repository>::\n \tThe \"remote\" repository to query.  This parameter can be\n \teither a URL or the name of a remote (see the GIT URLS and\n@@ -90,6 +101,10 @@ EXAMPLES\n \tc5db5456ae3b0873fc659c19fafdde22313cc441\trefs/tags/v0.99.2\n \t7ceca275d047c90c0c7d5afb13ab97efdf51bd6e\trefs/tags/v0.99.3\n \n+SEE ALSO\n+--------\n+linkgit:git-check-ref-format[1].\n+\n GIT\n ---\n Part of the linkgit:git[1] suite\ndiff --git a/builtin/ls-remote.c b/builtin/ls-remote.c\nindex 540d56429..b5ca67167 100644\n--- a/builtin/ls-remote.c\n+++ b/builtin/ls-remote.c\n@@ -1,6 +1,7 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n #include \"transport.h\"\n+#include \"ref-filter.h\"\n #include \"remote.h\"\n \n static const char * const ls_remote_usage[] = {\n@@ -43,10 +44,13 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \tint show_symref_target = 0;\n \tconst char *uploadpack = NULL;\n \tconst char **pattern = NULL;\n+\tint i;\n \n \tstruct remote *remote;\n \tstruct transport *transport;\n \tconst struct ref *ref;\n+\tstruct ref_array ref_array;\n+\tstatic struct ref_sorting *sorting = NULL, **sorting_tail = &sorting;\n \n \tstruct option options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"do not print remote URL\")),\n@@ -60,6 +64,8 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \t\tOPT_BIT(0, \"refs\", &flags, N_(\"do not show peeled tags\"), REF_NORMAL),\n \t\tOPT_BOOL(0, \"get-url\", &get_url,\n \t\t\t N_(\"take url.<base>.insteadOf into account\")),\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\tOPT_SET_INT_F(0, \"exit-code\", &status,\n \t\t\t      N_(\"exit with exit code 2 if no matching refs are found\"),\n \t\t\t      2, PARSE_OPT_NOCOMPLETE),\n@@ -68,6 +74,8 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \t\tOPT_END()\n \t};\n \n+\tmemset(&ref_array, 0, sizeof(ref_array));\n+\n \targc = parse_options(argc, argv, prefix, options, ls_remote_usage,\n \t\t\t     PARSE_OPT_STOP_AT_NON_OPTION);\n \tdest = argv[0];\n@@ -104,14 +112,27 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \tif (!dest && !quiet)\n \t\tfprintf(stderr, \"From %s\\n\", *remote->url);\n \tfor ( ; ref; ref = ref->next) {\n+\t\tstruct ref_array_item *item;\n \t\tif (!check_ref_type(ref, flags))\n \t\t\tcontinue;\n \t\tif (!tail_match(pattern, ref->name))\n \t\t\tcontinue;\n+\t\titem = ref_array_push(&ref_array, ref->name, &ref->old_oid);\n+\t\titem->symref = xstrdup_or_null(ref->symref);\n+\t}\n+\n+\tif (sorting)\n+\t\tref_array_sort(sorting, &ref_array);\n+\n+\tfor (i = 0; i < ref_array.nr; i++) {\n+\t\tconst struct ref_array_item *ref = ref_array.items[i];\n \t\tif (show_symref_target && ref->symref)\n-\t\t\tprintf(\"ref: %s\\t%s\\n\", ref->symref, ref->name);\n-\t\tprintf(\"%s\\t%s\\n\", oid_to_hex(&ref->old_oid), ref->name);\n+\t\t\tprintf(\"ref: %s\\t%s\\n\", ref->symref, ref->refname);\n+\t\tprintf(\"%s\\t%s\\n\", oid_to_hex(&ref->objectname), ref->refname);\n \t\tstatus = 0; /* we found something */\n \t}\n+\n+\tUNLEAK(sorting);\n+\tUNLEAK(ref_array);\n \treturn status;\n }\ndiff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh\nindex 02106c922..83cd35c39 100755\n--- a/t/t5512-ls-remote.sh\n+++ b/t/t5512-ls-remote.sh\n@@ -10,6 +10,9 @@ test_expect_success setup '\n \ttest_tick &&\n \tgit commit -m initial &&\n \tgit tag mark &&\n+\tgit tag mark1.1 &&\n+\tgit tag mark1.2 &&\n+\tgit tag mark1.10 &&\n \tgit show-ref --tags -d | sed -e \"s/ /\t/\" >expected.tag &&\n \t(\n \t\techo \"$(git rev-parse HEAD)\tHEAD\"\n@@ -39,6 +42,39 @@ test_expect_success 'ls-remote self' '\n \ttest_cmp expected.all actual\n '\n \n+test_expect_success 'ls-remote --sort=\"version:refname\" --tags self' '\n+\tcat >expect <<-EOF &&\n+\t$(git rev-parse mark)\trefs/tags/mark\n+\t$(git rev-parse mark1.1)\trefs/tags/mark1.1\n+\t$(git rev-parse mark1.2)\trefs/tags/mark1.2\n+\t$(git rev-parse mark1.10)\trefs/tags/mark1.10\n+\tEOF\n+\tgit ls-remote --sort=\"version:refname\" --tags self >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'ls-remote --sort=\"-version:refname\" --tags self' '\n+\tcat >expect <<-EOF &&\n+\t$(git rev-parse mark1.10)\trefs/tags/mark1.10\n+\t$(git rev-parse mark1.2)\trefs/tags/mark1.2\n+\t$(git rev-parse mark1.1)\trefs/tags/mark1.1\n+\t$(git rev-parse mark)\trefs/tags/mark\n+\tEOF\n+\tgit ls-remote --sort=\"-version:refname\" --tags self >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'ls-remote --sort=\"-refname\" --tags self' '\n+\tcat >expect <<-EOF &&\n+\t$(git rev-parse mark1.2)\trefs/tags/mark1.2\n+\t$(git rev-parse mark1.10)\trefs/tags/mark1.10\n+\t$(git rev-parse mark1.1)\trefs/tags/mark1.1\n+\t$(git rev-parse mark)\trefs/tags/mark\n+\tEOF\n+\tgit ls-remote --sort=\"-refname\" --tags self >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_expect_success 'dies when no remote specified and no default remotes found' '\n \ttest_must_fail git ls-remote\n '\n@@ -131,7 +167,7 @@ test_expect_success 'Report no-match with --exit-code' '\n \n test_expect_success 'Report match with --exit-code' '\n \tgit ls-remote --exit-code other.git \"refs/tags/*\" >actual &&\n-\tgit ls-remote . tags/mark >expect &&\n+\tgit ls-remote . tags/mark* >expect &&\n \ttest_cmp expect actual\n '\n \n@@ -170,14 +206,18 @@ test_expect_success 'overrides work between mixed transfer/upload-pack hideRefs'\n \tgrep refs/tags/magic actual\n '\n \n+git fetch origin\n test_expect_success 'ls-remote --symref' '\n-\tcat >expect <<-\\EOF &&\n+\tcat >expect <<-EOF &&\n \tref: refs/heads/master\tHEAD\n-\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\tHEAD\n-\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/heads/master\n-\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/remotes/origin/HEAD\n-\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/remotes/origin/master\n-\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark\n+\t$(git rev-parse HEAD)\tHEAD\n+\t$(git rev-parse refs/heads/master)\trefs/heads/master\n+\t$(git rev-parse HEAD)\trefs/remotes/origin/HEAD\n+\t$(git rev-parse refs/remotes/origin/master)\trefs/remotes/origin/master\n+\t$(git rev-parse refs/tags/mark)\trefs/tags/mark\n+\t$(git rev-parse refs/tags/mark1.1)\trefs/tags/mark1.1\n+\t$(git rev-parse refs/tags/mark1.10)\trefs/tags/mark1.10\n+\t$(git rev-parse refs/tags/mark1.2)\trefs/tags/mark1.2\n \tEOF\n \tgit ls-remote --symref >actual &&\n \ttest_cmp expect actual\n-- \n2.14.3 (Apple Git-98)\n\n"},{"id":"344132","messageId":"20180408235815.36582-3-haraldnordgren@gmail.com","threadId":"48197","inReplyTo":"20180408235815.36582-1-haraldnordgren@gmail.com","subject":"[PATCH v13 3/4] ref-filter: factor ref_array pushing into its own function","fromName":"Harald Nordgren","fromEmail":"haraldnordgren@gmail.com","sentAt":"2018-04-08T23:58:14Z","receivedAt":"2018-04-08T23:58:58Z","isPatch":true,"sender":{"key":"haraldnordgren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9569897?v=4"},"body":"From: Jeff King <peff@peff.net>\n\nIn preparation for callers constructing their own ref_array\nstructs, let's move our own internal push operation into its\nown function.\n\nWhile we're at it, we can replace REALLOC_ARRAY() with\nALLOC_GROW(), which should give the growth operation\namortized linear complexity (as opposed to growing by one,\nwhich is potentially quadratic, though in-place realloc\ngrowth often makes this faster in practice).\n\nSigned-off-by: Jeff King <peff@peff.net>\nSigned-off-by: Harald Nordgren <haraldnordgren@gmail.com>\n---\n ref-filter.c | 16 +++++++++++++---\n ref-filter.h |  8 ++++++++\n 2 files changed, 21 insertions(+), 3 deletions(-)\n\ndiff --git a/ref-filter.c b/ref-filter.c\nindex c1c3cc948..6e9328b27 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -1840,6 +1840,18 @@ static struct ref_array_item *new_ref_array_item(const char *refname,\n \treturn ref;\n }\n \n+struct ref_array_item *ref_array_push(struct ref_array *array,\n+\t\t\t\t      const char *refname,\n+\t\t\t\t      const struct object_id *oid)\n+{\n+\tstruct ref_array_item *ref = new_ref_array_item(refname, oid);\n+\n+\tALLOC_GROW(array->items, array->nr + 1, array->alloc);\n+\tarray->items[array->nr++] = ref;\n+\n+\treturn ref;\n+}\n+\n static int ref_kind_from_refname(const char *refname)\n {\n \tunsigned int i;\n@@ -1930,13 +1942,11 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,\n \t * to do its job and the resulting list may yet to be pruned\n \t * by maxcount logic.\n \t */\n-\tref = new_ref_array_item(refname, oid);\n+\tref = ref_array_push(ref_cbdata->array, refname, oid);\n \tref->commit = commit;\n \tref->flag = flag;\n \tref->kind = kind;\n \n-\tREALLOC_ARRAY(ref_cbdata->array->items, ref_cbdata->array->nr + 1);\n-\tref_cbdata->array->items[ref_cbdata->array->nr++] = ref;\n \treturn 0;\n }\n \ndiff --git a/ref-filter.h b/ref-filter.h\nindex 68268f9eb..76cf87cb6 100644\n--- a/ref-filter.h\n+++ b/ref-filter.h\n@@ -135,4 +135,12 @@ void setup_ref_filter_porcelain_msg(void);\n void pretty_print_ref(const char *name, const struct object_id *oid,\n \t\t      const struct ref_format *format);\n \n+/*\n+ * Push a single ref onto the array; this can be used to construct your own\n+ * ref_array without using filter_refs().\n+ */\n+struct ref_array_item *ref_array_push(struct ref_array *array,\n+\t\t\t\t      const char *refname,\n+\t\t\t\t      const struct object_id *oid);\n+\n #endif /*  REF_FILTER_H  */\n-- \n2.14.3 (Apple Git-98)\n\n"},{"id":"344134","messageId":"CAHwyqnWe=KmmdGJJ_DnCK+D_FoC0sAQG_8=_p+4+Yxmr8s8sPA@mail.gmail.com","threadId":"48197","inReplyTo":"xmqq7eph9wds.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v12 4/4] ls-remote: create '--sort' option","fromName":"Harald Nordgren","fromEmail":"haraldnordgren@gmail.com","sentAt":"2018-04-09T00:09:15Z","receivedAt":"2018-04-09T00:10:01Z","isPatch":true,"sender":{"key":"haraldnordgren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9569897?v=4"},"body":"On Mon, Apr 9, 2018 at 12:16 AM, Junio C Hamano <gitster@pobox.com> wrote:\n>\n> I can connect \"because it deals only with remotes\" and \"access to\n> the object may fail\", but I wonder if we can clarify the former a\n> bit better to make it easier to understand for those who are not yet\n> familiar with Git.\n>\n>     Keys like `committerdate` that require access to the object will\n>     not work [***HOW??? Do we get a segfault or something???***] for\n>     refs whose objects have not yet been fetched from the remote.\n>\n> I added \"for refs whose objects have not yet been fetched\", whose\n> explicit-ness made \"will not work\" to be an OK expression, but\n> without it I would have suggested to rephrase it to \"may not work\".\n>\n> This is a tangent but I suspect that the description of --sort in\n> git-for-each-ref documentation is wrong on the use of multiple\n> options, or I am misreading parse_opt_ref_sorting(), which I think\n> appends later keys to the end of the list, and compare_refs() which\n> I think yields results when an earlier key in the last decides two\n> are not equal and ignores the later keys.  The commit that added the\n> description was c0f6dc9b (\"git-for-each-ref.txt: minor\n> improvements\", 2008-06-05), and I think even back then the code in\n> builtin-for-each-ref.c appended later keys at the end, and it seems\n> nobody complained, so it is possible I am not reading the code right\n> before fully adjusting to timezone change ;-)\n\nUpdated the docs.\n\n>\n> It is not too big a deal, but I find that liberal sprinkling of\n> UNLEAK() is somewhat unsightly.  From the code we leave with this\n> change, it is clear what we'd need to do when we make the code fully\n> leak-proof (i.e. we'd have a several lines to free resources held by\n> these two variables here, and then UNLEAK() that appear earlier in\n> the function will become a \"goto cleanup;\" after setting appropriate\n> value to \"status\"), so let's not worry about it.\n\nRemoved the \"extra\" unleak annotations within the if-return blocks,\nbut kept them at the end.\n\n> Please do *NOT* step outside the pair of single quotes that protects\n> the body of the test scriptlet and execute commands like \"git\n> rev-parse\".  These execute in order to prepare the command line\n> argument strings BEFORE test_expect_success can run (or the test\n> framework decides if the test will be skipped via GIT_TEST_SKIP).\n>\n> Instead do it like so:\n>\n>         cat >expect <<-EOF &&\n>         $(git rev-parse mark)   refs/tags/mark\n>         $(git rev-parse mark1.1)        refs/tags/mark1.1\n>         $(git rev-parse mark1.2)        refs/tags/mark1.2\n>         $(git rev-parse mark1.10)       refs/tags/mark1.10\n>         EOF\n>\n> I.e. the end token for << that is not quoted allows $var and $(cmd)\n> to be substituted.\n>\n> Same comment applies throughout the remainder of this file.\n\nAh, thanks! I was looking for some way to allow the values to expand\nwithin the proper test context.\n\nSo turns out '<<-\\EOF' vs '<<-EOF' makes all the difference :)\n\n> Other than that, this patch was a very pleasant read.  Thanks.\n\nThank you!\n"},{"id":"344137","messageId":"xmqqmuyd6w7d.fsf@gitster-ct.c.googlers.com","threadId":"48197","inReplyTo":"CAHwyqnWe=KmmdGJJ_DnCK+D_FoC0sAQG_8=_p+4+Yxmr8s8sPA@mail.gmail.com","subject":"Re: [PATCH v12 4/4] ls-remote: create '--sort' option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-04-09T00:48:54Z","receivedAt":"2018-04-09T00:49:04Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Harald Nordgren <haraldnordgren@gmail.com> writes:\n\n>> It is not too big a deal, but I find that liberal sprinkling of\n>> UNLEAK() is somewhat unsightly.  From the code we leave with this\n>> change, it is clear what we'd need to do when we make the code fully\n>> leak-proof (i.e. we'd have a several lines to free resources held by\n>> these two variables here, and then UNLEAK() that appear earlier in\n>> the function will become a \"goto cleanup;\" after setting appropriate\n>> value to \"status\"), so let's not worry about it.\n>\n> Removed the \"extra\" unleak annotations within the if-return blocks,\n> but kept them at the end.\n\nI actually think that is worse.  The UNLEAK()s near early-return\nserve to remind us: \"here we are making early return and when we\nproperly plug the leak, here is one of the places we need to fix\".\nPlease keep them, unless (and I do not recommend to do this) you are\nplugging the leaks for real.\n"},{"id":"344138","messageId":"xmqqin916vu6.fsf@gitster-ct.c.googlers.com","threadId":"48197","inReplyTo":"20180408235815.36582-4-haraldnordgren@gmail.com","subject":"Re: [PATCH v13 4/4] ls-remote: create '--sort' option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-04-09T00:56:49Z","receivedAt":"2018-04-09T00:56:58Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Harald Nordgren <haraldnordgren@gmail.com> writes:\n\n> Create a '--sort' option for ls-remote, based on the one from\n> for-each-ref. This e.g. allows ref names to be sorted by version\n> semantics, so that v1.2 is sorted before v1.10.\n>\n> Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com>\n> ---\n\nThanks.\n\n> +--sort=<key>::\n> +\tSort based on the key given. Prefix `-` to sort in descending order\n> +\tof the value. Supports \"version:refname\" or \"v:refname\" (tag names\n> +\tare treated as versions). The \"version:refname\" sort order can also\n> +\tbe affected by the \"versionsort.suffix\" configuration variable.\n> +\tSee linkgit:git-for-each-ref[1] for more sort options, but be aware\n> +\tthat because `ls-remote` deals only with remotes, keys like\n> +\t`committerdate` that requires access to the objects themselves will\n> +\tnot work for refs whose objects have not yet been fetched from the\n> +\tremote.\n\nWith the update since v12, I think \"because `ls-remote` deals only\nwith remotes,\" can be dropped entirely, and still convey what needs\nto be told: \"Be aware some keys that needs access to objects that\nare not here won't work\".\n\nInstead, it is probably a better idea to spend that half-line worth\nof characters to describe in what way they do not work (do they try\nto deref a NULL pointer and dump core?  do they notice we need\nmissing objects and give an error?).\n\n> diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c\n> index 540d56429..b5ca67167 100644\n> --- a/builtin/ls-remote.c\n> +++ b/builtin/ls-remote.c\n\nAs I said earlier, let's keep these extra UNLEAK() near early\nreturn; they point developers at the places that needs future work.\n\nThanks.\n\n\n\ndiff --git a/builtin/ls-remote.c b/builtin/ls-remote.c\nindex b5ca67167d..d3851074c2 100644\n--- a/builtin/ls-remote.c\n+++ b/builtin/ls-remote.c\n@@ -98,6 +98,7 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \n \tif (get_url) {\n \t\tprintf(\"%s\\n\", *remote->url);\n+\t\tUNLEAK(sorting);\n \t\treturn 0;\n \t}\n \n@@ -106,8 +107,10 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \t\ttransport_set_option(transport, TRANS_OPT_UPLOADPACK, uploadpack);\n \n \tref = transport_get_remote_refs(transport);\n-\tif (transport_disconnect(transport))\n+\tif (transport_disconnect(transport)) {\n+\t\tUNLEAK(sorting);\n \t\treturn 1;\n+\t}\n \n \tif (!dest && !quiet)\n \t\tfprintf(stderr, \"From %s\\n\", *remote->url);\n\n\n"},{"id":"344139","messageId":"20180409014226.2647-1-haraldnordgren@gmail.com","threadId":"48197","inReplyTo":"20180402005248.52418-1-haraldnordgren@gmail.com","subject":"[PATCH v14 1/4] ref-filter: use \"struct object_id\" consistently","fromName":"Harald Nordgren","fromEmail":"haraldnordgren@gmail.com","sentAt":"2018-04-09T01:42:23Z","receivedAt":"2018-04-09T01:42:53Z","isPatch":true,"sender":{"key":"haraldnordgren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9569897?v=4"},"body":"From: Jeff King <peff@peff.net>\n\nInternally we store a \"struct object_id\", and all of our\ncallers have one to pass us. But we insist that they peel it\nto its bare-sha1 hash, which we then hashcpy() into place.\nLet's pass it around as an object_id, which future-proofs us\nfor a post-sha1 world.\n\nSigned-off-by: Jeff King <peff@peff.net>\nSigned-off-by: Harald Nordgren <haraldnordgren@gmail.com>\n---\n builtin/tag.c        |  2 +-\n builtin/verify-tag.c |  2 +-\n ref-filter.c         | 10 +++++-----\n ref-filter.h         |  2 +-\n 4 files changed, 8 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/tag.c b/builtin/tag.c\nindex da186691e..42278f516 100644\n--- a/builtin/tag.c\n+++ b/builtin/tag.c\n@@ -117,7 +117,7 @@ static int verify_tag(const char *name, const char *ref,\n \t\treturn -1;\n \n \tif (format->format)\n-\t\tpretty_print_ref(name, oid->hash, format);\n+\t\tpretty_print_ref(name, oid, format);\n \n \treturn 0;\n }\ndiff --git a/builtin/verify-tag.c b/builtin/verify-tag.c\nindex ad7b79fa5..6fa04b751 100644\n--- a/builtin/verify-tag.c\n+++ b/builtin/verify-tag.c\n@@ -72,7 +72,7 @@ int cmd_verify_tag(int argc, const char **argv, const char *prefix)\n \t\t}\n \n \t\tif (format.format)\n-\t\t\tpretty_print_ref(name, oid.hash, &format);\n+\t\t\tpretty_print_ref(name, &oid, &format);\n \t}\n \treturn had_error;\n }\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 45fc56216..ade97a848 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -1826,12 +1826,12 @@ static const struct object_id *match_points_at(struct oid_array *points_at,\n \n /* Allocate space for a new ref_array_item and copy the objectname and flag to it */\n static struct ref_array_item *new_ref_array_item(const char *refname,\n-\t\t\t\t\t\t const unsigned char *objectname,\n+\t\t\t\t\t\t const struct object_id *oid,\n \t\t\t\t\t\t int flag)\n {\n \tstruct ref_array_item *ref;\n \tFLEX_ALLOC_STR(ref, refname, refname);\n-\thashcpy(ref->objectname.hash, objectname);\n+\toidcpy(&ref->objectname, oid);\n \tref->flag = flag;\n \n \treturn ref;\n@@ -1927,7 +1927,7 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,\n \t * to do its job and the resulting list may yet to be pruned\n \t * by maxcount logic.\n \t */\n-\tref = new_ref_array_item(refname, oid->hash, flag);\n+\tref = new_ref_array_item(refname, oid, flag);\n \tref->commit = commit;\n \n \tREALLOC_ARRAY(ref_cbdata->array->items, ref_cbdata->array->nr + 1);\n@@ -2165,11 +2165,11 @@ void show_ref_array_item(struct ref_array_item *info,\n \tputchar('\\n');\n }\n \n-void pretty_print_ref(const char *name, const unsigned char *sha1,\n+void pretty_print_ref(const char *name, const struct object_id *oid,\n \t\t      const struct ref_format *format)\n {\n \tstruct ref_array_item *ref_item;\n-\tref_item = new_ref_array_item(name, sha1, 0);\n+\tref_item = new_ref_array_item(name, oid, 0);\n \tref_item->kind = ref_kind_from_refname(name);\n \tshow_ref_array_item(ref_item, format);\n \tfree_array_item(ref_item);\ndiff --git a/ref-filter.h b/ref-filter.h\nindex 0d98342b3..68268f9eb 100644\n--- a/ref-filter.h\n+++ b/ref-filter.h\n@@ -132,7 +132,7 @@ void setup_ref_filter_porcelain_msg(void);\n  * Print a single ref, outside of any ref-filter. Note that the\n  * name must be a fully qualified refname.\n  */\n-void pretty_print_ref(const char *name, const unsigned char *sha1,\n+void pretty_print_ref(const char *name, const struct object_id *oid,\n \t\t      const struct ref_format *format);\n \n #endif /*  REF_FILTER_H  */\n-- \n2.14.3 (Apple Git-98)\n\n"},{"id":"344140","messageId":"20180409014226.2647-2-haraldnordgren@gmail.com","threadId":"48197","inReplyTo":"20180409014226.2647-1-haraldnordgren@gmail.com","subject":"[PATCH v14 2/4] ref-filter: make ref_array_item allocation more consistent","fromName":"Harald Nordgren","fromEmail":"haraldnordgren@gmail.com","sentAt":"2018-04-09T01:42:24Z","receivedAt":"2018-04-09T01:42:56Z","isPatch":true,"sender":{"key":"haraldnordgren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9569897?v=4"},"body":"From: Jeff King <peff@peff.net>\n\nWe have a helper function to allocate ref_array_item\nstructs, but it only takes a subset of the possible fields\nin the struct as initializers. We could have it accept an\nargument for _every_ field, but that becomes a pain for the\nfields which some callers don't want to set initially.\n\nInstead, let's be explicit that it takes only the minimum\nrequired to create the ref, and that callers should then\nfill in the rest themselves.\n\nSigned-off-by: Jeff King <peff@peff.net>\nSigned-off-by: Harald Nordgren <haraldnordgren@gmail.com>\n---\n ref-filter.c | 18 +++++++++++-------\n 1 file changed, 11 insertions(+), 7 deletions(-)\n\ndiff --git a/ref-filter.c b/ref-filter.c\nindex ade97a848..c1c3cc948 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -1824,15 +1824,18 @@ static const struct object_id *match_points_at(struct oid_array *points_at,\n \treturn NULL;\n }\n \n-/* Allocate space for a new ref_array_item and copy the objectname and flag to it */\n+/*\n+ * Allocate space for a new ref_array_item and copy the name and oid to it.\n+ *\n+ * Callers can then fill in other struct members at their leisure.\n+ */\n static struct ref_array_item *new_ref_array_item(const char *refname,\n-\t\t\t\t\t\t const struct object_id *oid,\n-\t\t\t\t\t\t int flag)\n+\t\t\t\t\t\t const struct object_id *oid)\n {\n \tstruct ref_array_item *ref;\n+\n \tFLEX_ALLOC_STR(ref, refname, refname);\n \toidcpy(&ref->objectname, oid);\n-\tref->flag = flag;\n \n \treturn ref;\n }\n@@ -1927,12 +1930,13 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,\n \t * to do its job and the resulting list may yet to be pruned\n \t * by maxcount logic.\n \t */\n-\tref = new_ref_array_item(refname, oid, flag);\n+\tref = new_ref_array_item(refname, oid);\n \tref->commit = commit;\n+\tref->flag = flag;\n+\tref->kind = kind;\n \n \tREALLOC_ARRAY(ref_cbdata->array->items, ref_cbdata->array->nr + 1);\n \tref_cbdata->array->items[ref_cbdata->array->nr++] = ref;\n-\tref->kind = kind;\n \treturn 0;\n }\n \n@@ -2169,7 +2173,7 @@ void pretty_print_ref(const char *name, const struct object_id *oid,\n \t\t      const struct ref_format *format)\n {\n \tstruct ref_array_item *ref_item;\n-\tref_item = new_ref_array_item(name, oid, 0);\n+\tref_item = new_ref_array_item(name, oid);\n \tref_item->kind = ref_kind_from_refname(name);\n \tshow_ref_array_item(ref_item, format);\n \tfree_array_item(ref_item);\n-- \n2.14.3 (Apple Git-98)\n\n"},{"id":"344141","messageId":"20180409014226.2647-3-haraldnordgren@gmail.com","threadId":"48197","inReplyTo":"20180409014226.2647-1-haraldnordgren@gmail.com","subject":"[PATCH v14 3/4] ref-filter: factor ref_array pushing into its own function","fromName":"Harald Nordgren","fromEmail":"haraldnordgren@gmail.com","sentAt":"2018-04-09T01:42:25Z","receivedAt":"2018-04-09T01:42:58Z","isPatch":true,"sender":{"key":"haraldnordgren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9569897?v=4"},"body":"From: Jeff King <peff@peff.net>\n\nIn preparation for callers constructing their own ref_array\nstructs, let's move our own internal push operation into its\nown function.\n\nWhile we're at it, we can replace REALLOC_ARRAY() with\nALLOC_GROW(), which should give the growth operation\namortized linear complexity (as opposed to growing by one,\nwhich is potentially quadratic, though in-place realloc\ngrowth often makes this faster in practice).\n\nSigned-off-by: Jeff King <peff@peff.net>\nSigned-off-by: Harald Nordgren <haraldnordgren@gmail.com>\n---\n ref-filter.c | 16 +++++++++++++---\n ref-filter.h |  8 ++++++++\n 2 files changed, 21 insertions(+), 3 deletions(-)\n\ndiff --git a/ref-filter.c b/ref-filter.c\nindex c1c3cc948..6e9328b27 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -1840,6 +1840,18 @@ static struct ref_array_item *new_ref_array_item(const char *refname,\n \treturn ref;\n }\n \n+struct ref_array_item *ref_array_push(struct ref_array *array,\n+\t\t\t\t      const char *refname,\n+\t\t\t\t      const struct object_id *oid)\n+{\n+\tstruct ref_array_item *ref = new_ref_array_item(refname, oid);\n+\n+\tALLOC_GROW(array->items, array->nr + 1, array->alloc);\n+\tarray->items[array->nr++] = ref;\n+\n+\treturn ref;\n+}\n+\n static int ref_kind_from_refname(const char *refname)\n {\n \tunsigned int i;\n@@ -1930,13 +1942,11 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,\n \t * to do its job and the resulting list may yet to be pruned\n \t * by maxcount logic.\n \t */\n-\tref = new_ref_array_item(refname, oid);\n+\tref = ref_array_push(ref_cbdata->array, refname, oid);\n \tref->commit = commit;\n \tref->flag = flag;\n \tref->kind = kind;\n \n-\tREALLOC_ARRAY(ref_cbdata->array->items, ref_cbdata->array->nr + 1);\n-\tref_cbdata->array->items[ref_cbdata->array->nr++] = ref;\n \treturn 0;\n }\n \ndiff --git a/ref-filter.h b/ref-filter.h\nindex 68268f9eb..76cf87cb6 100644\n--- a/ref-filter.h\n+++ b/ref-filter.h\n@@ -135,4 +135,12 @@ void setup_ref_filter_porcelain_msg(void);\n void pretty_print_ref(const char *name, const struct object_id *oid,\n \t\t      const struct ref_format *format);\n \n+/*\n+ * Push a single ref onto the array; this can be used to construct your own\n+ * ref_array without using filter_refs().\n+ */\n+struct ref_array_item *ref_array_push(struct ref_array *array,\n+\t\t\t\t      const char *refname,\n+\t\t\t\t      const struct object_id *oid);\n+\n #endif /*  REF_FILTER_H  */\n-- \n2.14.3 (Apple Git-98)\n\n"},{"id":"344142","messageId":"20180409014226.2647-4-haraldnordgren@gmail.com","threadId":"48197","inReplyTo":"20180409014226.2647-1-haraldnordgren@gmail.com","subject":"[PATCH v14 4/4] ls-remote: create '--sort' option","fromName":"Harald Nordgren","fromEmail":"haraldnordgren@gmail.com","sentAt":"2018-04-09T01:42:26Z","receivedAt":"2018-04-09T01:42:59Z","isPatch":true,"sender":{"key":"haraldnordgren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9569897?v=4"},"body":"Create a '--sort' option for ls-remote, based on the one from\nfor-each-ref. This e.g. allows ref names to be sorted by version\nsemantics, so that v1.2 is sorted before v1.10.\n\nSigned-off-by: Harald Nordgren <haraldnordgren@gmail.com>\n---\n\nNotes:\n    Changes according to Junio Hamano's code review (2)\n\n Documentation/git-ls-remote.txt | 16 +++++++++++-\n builtin/ls-remote.c             | 28 ++++++++++++++++++---\n t/t5512-ls-remote.sh            | 54 +++++++++++++++++++++++++++++++++++------\n 3 files changed, 87 insertions(+), 11 deletions(-)\n\ndiff --git a/Documentation/git-ls-remote.txt b/Documentation/git-ls-remote.txt\nindex 5f2628c8f..6ad1e34af 100644\n--- a/Documentation/git-ls-remote.txt\n+++ b/Documentation/git-ls-remote.txt\n@@ -10,7 +10,7 @@ SYNOPSIS\n --------\n [verse]\n 'git ls-remote' [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n-\t      [-q | --quiet] [--exit-code] [--get-url]\n+\t      [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n \t      [--symref] [<repository> [<refs>...]]\n \n DESCRIPTION\n@@ -60,6 +60,16 @@ OPTIONS\n \tupload-pack only shows the symref HEAD, so it will be the only\n \tone shown by ls-remote.\n \n+--sort=<key>::\n+\tSort based on the key given. Prefix `-` to sort in descending order\n+\tof the value. Supports \"version:refname\" or \"v:refname\" (tag names\n+\tare treated as versions). The \"version:refname\" sort order can also\n+\tbe affected by the \"versionsort.suffix\" configuration variable.\n+\tSee linkgit:git-for-each-ref[1] for more sort options, but be aware\n+\tkeys like `committerdate` that require access to the objects\n+\tthemselves will not work for refs whose objects have not yet been\n+\tfetched from the remote, and will give a `missing object` error.\n+\n <repository>::\n \tThe \"remote\" repository to query.  This parameter can be\n \teither a URL or the name of a remote (see the GIT URLS and\n@@ -90,6 +100,10 @@ EXAMPLES\n \tc5db5456ae3b0873fc659c19fafdde22313cc441\trefs/tags/v0.99.2\n \t7ceca275d047c90c0c7d5afb13ab97efdf51bd6e\trefs/tags/v0.99.3\n \n+SEE ALSO\n+--------\n+linkgit:git-check-ref-format[1].\n+\n GIT\n ---\n Part of the linkgit:git[1] suite\ndiff --git a/builtin/ls-remote.c b/builtin/ls-remote.c\nindex 540d56429..b26c53670 100644\n--- a/builtin/ls-remote.c\n+++ b/builtin/ls-remote.c\n@@ -1,6 +1,7 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n #include \"transport.h\"\n+#include \"ref-filter.h\"\n #include \"remote.h\"\n \n static const char * const ls_remote_usage[] = {\n@@ -43,10 +44,13 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \tint show_symref_target = 0;\n \tconst char *uploadpack = NULL;\n \tconst char **pattern = NULL;\n+\tint i;\n \n \tstruct remote *remote;\n \tstruct transport *transport;\n \tconst struct ref *ref;\n+\tstruct ref_array ref_array;\n+\tstatic struct ref_sorting *sorting = NULL, **sorting_tail = &sorting;\n \n \tstruct option options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"do not print remote URL\")),\n@@ -60,6 +64,8 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \t\tOPT_BIT(0, \"refs\", &flags, N_(\"do not show peeled tags\"), REF_NORMAL),\n \t\tOPT_BOOL(0, \"get-url\", &get_url,\n \t\t\t N_(\"take url.<base>.insteadOf into account\")),\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\tOPT_SET_INT_F(0, \"exit-code\", &status,\n \t\t\t      N_(\"exit with exit code 2 if no matching refs are found\"),\n \t\t\t      2, PARSE_OPT_NOCOMPLETE),\n@@ -68,6 +74,8 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \t\tOPT_END()\n \t};\n \n+\tmemset(&ref_array, 0, sizeof(ref_array));\n+\n \targc = parse_options(argc, argv, prefix, options, ls_remote_usage,\n \t\t\t     PARSE_OPT_STOP_AT_NON_OPTION);\n \tdest = argv[0];\n@@ -90,6 +98,7 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \n \tif (get_url) {\n \t\tprintf(\"%s\\n\", *remote->url);\n+\t\tUNLEAK(sorting);\n \t\treturn 0;\n \t}\n \n@@ -98,20 +107,33 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)\n \t\ttransport_set_option(transport, TRANS_OPT_UPLOADPACK, uploadpack);\n \n \tref = transport_get_remote_refs(transport);\n-\tif (transport_disconnect(transport))\n+\tif (transport_disconnect(transport)) {\n+\t\tUNLEAK(sorting);\n \t\treturn 1;\n+\t}\n \n \tif (!dest && !quiet)\n \t\tfprintf(stderr, \"From %s\\n\", *remote->url);\n \tfor ( ; ref; ref = ref->next) {\n+\t\tstruct ref_array_item *item;\n \t\tif (!check_ref_type(ref, flags))\n \t\t\tcontinue;\n \t\tif (!tail_match(pattern, ref->name))\n \t\t\tcontinue;\n+\t\titem = ref_array_push(&ref_array, ref->name, &ref->old_oid);\n+\t\titem->symref = xstrdup_or_null(ref->symref);\n+\t}\n+\n+\tif (sorting)\n+\t\tref_array_sort(sorting, &ref_array);\n+\n+\tfor (i = 0; i < ref_array.nr; i++) {\n+\t\tconst struct ref_array_item *ref = ref_array.items[i];\n \t\tif (show_symref_target && ref->symref)\n-\t\t\tprintf(\"ref: %s\\t%s\\n\", ref->symref, ref->name);\n-\t\tprintf(\"%s\\t%s\\n\", oid_to_hex(&ref->old_oid), ref->name);\n+\t\t\tprintf(\"ref: %s\\t%s\\n\", ref->symref, ref->refname);\n+\t\tprintf(\"%s\\t%s\\n\", oid_to_hex(&ref->objectname), ref->refname);\n \t\tstatus = 0; /* we found something */\n \t}\n+\n \treturn status;\n }\ndiff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh\nindex 02106c922..83cd35c39 100755\n--- a/t/t5512-ls-remote.sh\n+++ b/t/t5512-ls-remote.sh\n@@ -10,6 +10,9 @@ test_expect_success setup '\n \ttest_tick &&\n \tgit commit -m initial &&\n \tgit tag mark &&\n+\tgit tag mark1.1 &&\n+\tgit tag mark1.2 &&\n+\tgit tag mark1.10 &&\n \tgit show-ref --tags -d | sed -e \"s/ /\t/\" >expected.tag &&\n \t(\n \t\techo \"$(git rev-parse HEAD)\tHEAD\"\n@@ -39,6 +42,39 @@ test_expect_success 'ls-remote self' '\n \ttest_cmp expected.all actual\n '\n \n+test_expect_success 'ls-remote --sort=\"version:refname\" --tags self' '\n+\tcat >expect <<-EOF &&\n+\t$(git rev-parse mark)\trefs/tags/mark\n+\t$(git rev-parse mark1.1)\trefs/tags/mark1.1\n+\t$(git rev-parse mark1.2)\trefs/tags/mark1.2\n+\t$(git rev-parse mark1.10)\trefs/tags/mark1.10\n+\tEOF\n+\tgit ls-remote --sort=\"version:refname\" --tags self >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'ls-remote --sort=\"-version:refname\" --tags self' '\n+\tcat >expect <<-EOF &&\n+\t$(git rev-parse mark1.10)\trefs/tags/mark1.10\n+\t$(git rev-parse mark1.2)\trefs/tags/mark1.2\n+\t$(git rev-parse mark1.1)\trefs/tags/mark1.1\n+\t$(git rev-parse mark)\trefs/tags/mark\n+\tEOF\n+\tgit ls-remote --sort=\"-version:refname\" --tags self >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'ls-remote --sort=\"-refname\" --tags self' '\n+\tcat >expect <<-EOF &&\n+\t$(git rev-parse mark1.2)\trefs/tags/mark1.2\n+\t$(git rev-parse mark1.10)\trefs/tags/mark1.10\n+\t$(git rev-parse mark1.1)\trefs/tags/mark1.1\n+\t$(git rev-parse mark)\trefs/tags/mark\n+\tEOF\n+\tgit ls-remote --sort=\"-refname\" --tags self >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_expect_success 'dies when no remote specified and no default remotes found' '\n \ttest_must_fail git ls-remote\n '\n@@ -131,7 +167,7 @@ test_expect_success 'Report no-match with --exit-code' '\n \n test_expect_success 'Report match with --exit-code' '\n \tgit ls-remote --exit-code other.git \"refs/tags/*\" >actual &&\n-\tgit ls-remote . tags/mark >expect &&\n+\tgit ls-remote . tags/mark* >expect &&\n \ttest_cmp expect actual\n '\n \n@@ -170,14 +206,18 @@ test_expect_success 'overrides work between mixed transfer/upload-pack hideRefs'\n \tgrep refs/tags/magic actual\n '\n \n+git fetch origin\n test_expect_success 'ls-remote --symref' '\n-\tcat >expect <<-\\EOF &&\n+\tcat >expect <<-EOF &&\n \tref: refs/heads/master\tHEAD\n-\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\tHEAD\n-\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/heads/master\n-\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/remotes/origin/HEAD\n-\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/remotes/origin/master\n-\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark\n+\t$(git rev-parse HEAD)\tHEAD\n+\t$(git rev-parse refs/heads/master)\trefs/heads/master\n+\t$(git rev-parse HEAD)\trefs/remotes/origin/HEAD\n+\t$(git rev-parse refs/remotes/origin/master)\trefs/remotes/origin/master\n+\t$(git rev-parse refs/tags/mark)\trefs/tags/mark\n+\t$(git rev-parse refs/tags/mark1.1)\trefs/tags/mark1.1\n+\t$(git rev-parse refs/tags/mark1.10)\trefs/tags/mark1.10\n+\t$(git rev-parse refs/tags/mark1.2)\trefs/tags/mark1.2\n \tEOF\n \tgit ls-remote --symref >actual &&\n \ttest_cmp expect actual\n-- \n2.14.3 (Apple Git-98)\n\n"},{"id":"344143","messageId":"CAHwyqnU-hyRboVDG8BBRJU_uURRdoh4UPg7=PjsJ+V9YPwqYcw@mail.gmail.com","threadId":"48197","inReplyTo":"xmqqin916vu6.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v13 4/4] ls-remote: create '--sort' option","fromName":"Harald Nordgren","fromEmail":"haraldnordgren@gmail.com","sentAt":"2018-04-09T01:45:43Z","receivedAt":"2018-04-09T01:46:32Z","isPatch":true,"sender":{"key":"haraldnordgren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9569897?v=4"},"body":"On Mon, Apr 9, 2018 at 2:56 AM, Junio C Hamano <gitster@pobox.com> wrote:\n>\n> With the update since v12, I think \"because `ls-remote` deals only\n> with remotes,\" can be dropped entirely, and still convey what needs\n> to be told: \"Be aware some keys that needs access to objects that\n> are not here won't work\".\n>\n> Instead, it is probably a better idea to spend that half-line worth\n> of characters to describe in what way they do not work (do they try\n> to deref a NULL pointer and dump core?  do they notice we need\n> missing objects and give an error?).\n\nUpdated the docs again. The specific error we get on commiterdate is\n\n    fatal: missing object f0d0fd3a5985d5e588da1e1d11c85fba0ae132f8 for\nrefs/pull/10/head\n\nSo no core dump. But a fatal error with a possibly confusing message.\n"},{"id":"344148","messageId":"CAPig+cR4kA+SHmOOOq20BJGzqQkqKvYrFEqPdDF6g6c=apjHtA@mail.gmail.com","threadId":"48197","inReplyTo":"xmqq7eph9wds.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v12 4/4] ls-remote: create '--sort' option","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2018-04-09T02:31:44Z","receivedAt":"2018-04-09T02:31:50Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Sun, Apr 8, 2018 at 6:16 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Harald Nordgren <haraldnordgren@gmail.com> writes:\n>> +--sort=<key>::\n>> +     Sort based on the key given. [...]\n>\n> This is a tangent but I suspect that the description of --sort in\n> git-for-each-ref documentation is wrong on the use of multiple\n> options, or I am misreading parse_opt_ref_sorting(), which I think\n> appends later keys to the end of the list, and compare_refs() which\n> I think yields results when an earlier key in the last decides two\n> are not equal and ignores the later keys.  The commit that added the\n> description was c0f6dc9b (\"git-for-each-ref.txt: minor\n> improvements\", 2008-06-05), and I think even back then the code in\n> builtin-for-each-ref.c appended later keys at the end, and it seems\n> nobody complained, so it is possible I am not reading the code right\n> before fully adjusting to timezone change ;-)\n\nI just re-read parse_opt_ref_sorting(), and I'm pretty sure that it is\n_prepending_ keys to the list, despite the confusingly named variable\n\"sorting_tail\", thus it agrees with the documentation that\n--sort=<key> specified last becomes primary sort key.\n\nFor me, at least, that behavior (last --sort= becomes primary key)\nfeels counterintuitive, but it's too late to change it now.\n"},{"id":"344153","messageId":"20180409035743.GA30063@sigill.intra.peff.net","threadId":"48197","inReplyTo":"xmqqy3hx70dw.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH 3/3] ref-filter: factor ref_array pushing into its own function","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-04-09T03:57:43Z","receivedAt":"2018-04-09T03:57:50Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Apr 09, 2018 at 08:18:35AM +0900, Junio C Hamano wrote:\n\n> Jeff King <peff@peff.net> writes:\n> \n> > In preparation for callers constructing their own ref_array\n> > structs, let's move our own internal push operation into its\n> > own function.\n> >\n> > While we're at it, we can replace REALLOC_ARRAY() with\n> > ALLOC_GROW(), which should give the growth operation\n> > amortized linear complexity (as opposed to growing by one,\n> > which is potentially quadratic, though in-place realloc\n> > growth often makes this faster in practice).\n> \n> Sorry, but I do not quite get the last part this paragraph.  Up to\n> but not including \", though in-place...\" I would understand as:\n> \n>      - With ALLOC_GROW(), we are explicit in that we are amortizing\n>        the allocation cost by growing in exponential batches.\n> \n>      - With REALLOC_ARRAY(), we are telling the underlying\n>        realloc(3) that it is OK to pretend that we grow by one, but\n>        if that permission is literally followed, it could end up\n>        quadratic.\n> \n>     So if you have really a bad realloc(3) implementation, switching\n>     to use ALLOC_GROW() is an improvement.\n\nYes, that's the gist of what I was saying. Though it is not even\nnecessarily \"a bad realloc\". At some point you may hit heap segmentation\nand need to copy (though I guess if that happens repeatedly then maybe\nyour realloc really _is_ bad ;) ).\n\n> But after that I am not sure what you are getting at.  Do you mean\n> \"In practice, a well-done realloc(3) does the amortizing internally\n> anyway, which makes it faster than the grow-by-one quadratic, so\n> this change may not make that much of a difference\"?  Or do you mean\n> \"In practice, a well-done realloc(3) internally amortizes better\n> than we do manually, so this change may hurt performance\"?\n\nThe first. I couldn't measure any speedup on glibc, which makes me think\nit's mostly doing in-place expansion.\n\n> In either case, I think this splitting into a helper is obviously a\n> good move, and using ALLOC_GROW() is conceptually cleaner, as we use\n> it everywhere and tend to avoid realloc(3) just to add one item.\n> \n> Other than that small confusion (not even a nit), three patches were\n> pleasant read.  Thanks.\n\nThanks. Please feel free to expand or clarify the commit message if that\nhelps.\n\n-Peff\n"},{"id":"344466","messageId":"CAHwyqnURebvfW4rGz9RAbe7B9p6ZDy0jUueDFrYE30dmjCtMVA@mail.gmail.com","threadId":"48197","inReplyTo":"20180409014226.2647-2-haraldnordgren@gmail.com","subject":"Re: [PATCH v14 2/4] ref-filter: make ref_array_item allocation more consistent","fromName":"Harald Nordgren","fromEmail":"haraldnordgren@gmail.com","sentAt":"2018-04-11T17:57:15Z","receivedAt":"2018-04-11T17:58:03Z","isPatch":true,"sender":{"key":"haraldnordgren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9569897?v=4"},"body":"There have been no new comments for the last few days. I know Jeff\nKing will be away for the next two weeks, but should we still move\nforward with this? The initial reactions to the idea seemed positive.\n\nBest regards\nHarald\n\nOn Mon, Apr 9, 2018 at 3:42 AM, Harald Nordgren\n<haraldnordgren@gmail.com> wrote:\n> From: Jeff King <peff@peff.net>\n>\n> We have a helper function to allocate ref_array_item\n> structs, but it only takes a subset of the possible fields\n> in the struct as initializers. We could have it accept an\n> argument for _every_ field, but that becomes a pain for the\n> fields which some callers don't want to set initially.\n>\n> Instead, let's be explicit that it takes only the minimum\n> required to create the ref, and that callers should then\n> fill in the rest themselves.\n>\n> Signed-off-by: Jeff King <peff@peff.net>\n> Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com>\n> ---\n>  ref-filter.c | 18 +++++++++++-------\n>  1 file changed, 11 insertions(+), 7 deletions(-)\n>\n> diff --git a/ref-filter.c b/ref-filter.c\n> index ade97a848..c1c3cc948 100644\n> --- a/ref-filter.c\n> +++ b/ref-filter.c\n> @@ -1824,15 +1824,18 @@ static const struct object_id *match_points_at(struct oid_array *points_at,\n>         return NULL;\n>  }\n>\n> -/* Allocate space for a new ref_array_item and copy the objectname and flag to it */\n> +/*\n> + * Allocate space for a new ref_array_item and copy the name and oid to it.\n> + *\n> + * Callers can then fill in other struct members at their leisure.\n> + */\n>  static struct ref_array_item *new_ref_array_item(const char *refname,\n> -                                                const struct object_id *oid,\n> -                                                int flag)\n> +                                                const struct object_id *oid)\n>  {\n>         struct ref_array_item *ref;\n> +\n>         FLEX_ALLOC_STR(ref, refname, refname);\n>         oidcpy(&ref->objectname, oid);\n> -       ref->flag = flag;\n>\n>         return ref;\n>  }\n> @@ -1927,12 +1930,13 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,\n>          * to do its job and the resulting list may yet to be pruned\n>          * by maxcount logic.\n>          */\n> -       ref = new_ref_array_item(refname, oid, flag);\n> +       ref = new_ref_array_item(refname, oid);\n>         ref->commit = commit;\n> +       ref->flag = flag;\n> +       ref->kind = kind;\n>\n>         REALLOC_ARRAY(ref_cbdata->array->items, ref_cbdata->array->nr + 1);\n>         ref_cbdata->array->items[ref_cbdata->array->nr++] = ref;\n> -       ref->kind = kind;\n>         return 0;\n>  }\n>\n> @@ -2169,7 +2173,7 @@ void pretty_print_ref(const char *name, const struct object_id *oid,\n>                       const struct ref_format *format)\n>  {\n>         struct ref_array_item *ref_item;\n> -       ref_item = new_ref_array_item(name, oid, 0);\n> +       ref_item = new_ref_array_item(name, oid);\n>         ref_item->kind = ref_kind_from_refname(name);\n>         show_ref_array_item(ref_item, format);\n>         free_array_item(ref_item);\n> --\n> 2.14.3 (Apple Git-98)\n>\n"},{"id":"344467","messageId":"CAGZ79kYeM=CqKSWTL2tdDXWueMGoki4zAUmFy4wbhtagN7gEAA@mail.gmail.com","threadId":"48197","inReplyTo":"CAHwyqnURebvfW4rGz9RAbe7B9p6ZDy0jUueDFrYE30dmjCtMVA@mail.gmail.com","subject":"Re: [PATCH v14 2/4] ref-filter: make ref_array_item allocation more consistent","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2018-04-11T18:07:57Z","receivedAt":"2018-04-11T18:08:03Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"Hi Harald,\n\nOn Wed, Apr 11, 2018 at 10:57 AM, Harald Nordgren\n<haraldnordgren@gmail.com> wrote:\n> There have been no new comments for the last few days. I know Jeff\n> King will be away for the next two weeks, but should we still move\n> forward with this? The initial reactions to the idea seemed positive.\n\nPlease see the \"What's cooking?\" email on the mailing list that is\nsent out periodically by Junio.\nthe last one is\nhttps://public-inbox.org/git/xmqqd0z865pk.fsf@gitster-ct.c.googlers.com/\nwhich says:\n\n> * jk/ref-array-push (2018-04-09) 3 commits\n> - ref-filter: factor ref_array pushing into its own function\n> - ref-filter: make ref_array_item allocation more consistent\n> - ref-filter: use \"struct object_id\" consistently\n> (this branch is used by hn/sort-ls-remote.)\n>\n> API clean-up aournd ref-filter code.\n>\n> Will merge to 'next'.\n\nIt will be merged to next and if no people speak up (due to bugs\nobserved or such)\nthen it will be merged to master eventually, later.\n\nI am not able to find the documentation for the workflow right now,\nthough it is partially covered in Documentation/SubmittingPatches.\n"},{"id":"344468","messageId":"20180411183033.GQ29680@zaya.teonanacatl.net","threadId":"48197","inReplyTo":"CAGZ79kYeM=CqKSWTL2tdDXWueMGoki4zAUmFy4wbhtagN7gEAA@mail.gmail.com","subject":"Re: [PATCH v14 2/4] ref-filter: make ref_array_item allocation more consistent","fromName":"Todd Zullinger","fromEmail":"tmz@pobox.com","sentAt":"2018-04-11T18:30:33Z","receivedAt":"2018-04-11T18:30:44Z","isPatch":true,"sender":{"key":"tmz@pobox.com","avatar":"https://avatars.githubusercontent.com/u/806319?v=4"},"body":"Hi Stefan,\n\nStefan Beller wrote:\n> Please see the \"What's cooking?\" email on the mailing list that is\n> sent out periodically by Junio.\n> the last one is\n> https://public-inbox.org/git/xmqqd0z865pk.fsf@gitster-ct.c.googlers.com/\n> which says:\n> \n>> * jk/ref-array-push (2018-04-09) 3 commits\n>> - ref-filter: factor ref_array pushing into its own function\n>> - ref-filter: make ref_array_item allocation more consistent\n>> - ref-filter: use \"struct object_id\" consistently\n>> (this branch is used by hn/sort-ls-remote.)\n>>\n>> API clean-up aournd ref-filter code.\n>>\n>> Will merge to 'next'.\n> \n> It will be merged to next and if no people speak up (due to bugs\n> observed or such)\n> then it will be merged to master eventually, later.\n> \n> I am not able to find the documentation for the workflow right now,\n> though it is partially covered in Documentation/SubmittingPatches.\n\nPerhaps Documentation/howto/maintain-git.txt is the\ndocumentation you're thinking of?\n\nhttps://kernel.org/pub/software/scm/git/docs/howto/maintain-git.html\n\nThere's also MaintNotes in the todo branch:\n\nhttps://raw.githubusercontent.com/git/git/todo/MaintNotes\n\n-- \nTodd\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nBe who you are and say what you feel because those who mind don't\nmatter and those who matter don't mind.\n    -- Dr Seuss, \"Oh the Places You'll Go\"\n\n"},{"id":"344479","messageId":"CAPig+cQzWAbEVBJ8O0yKYHQ02EaGTx9CeUyF67xozeT2-FL0EA@mail.gmail.com","threadId":"48197","inReplyTo":"CAGZ79kYeM=CqKSWTL2tdDXWueMGoki4zAUmFy4wbhtagN7gEAA@mail.gmail.com","subject":"Re: [PATCH v14 2/4] ref-filter: make ref_array_item allocation more consistent","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2018-04-11T18:56:21Z","receivedAt":"2018-04-11T20:01:36Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Wed, Apr 11, 2018 at 2:07 PM, Stefan Beller <sbeller@google.com> wrote:\n> On Wed, Apr 11, 2018 at 10:57 AM, Harald Nordgren\n> <haraldnordgren@gmail.com> wrote:\n>> There have been no new comments for the last few days. I know Jeff\n>> King will be away for the next two weeks, but should we still move\n>> forward with this? The initial reactions to the idea seemed positive.\n>\n> Please see the \"What's cooking?\" email on the mailing list that is\n> sent out periodically by Junio.\n>\n>> * jk/ref-array-push (2018-04-09) 3 commits\n>> - ref-filter: factor ref_array pushing into its own function\n>> - ref-filter: make ref_array_item allocation more consistent\n>> - ref-filter: use \"struct object_id\" consistently\n>> (this branch is used by hn/sort-ls-remote.)\n>>\n>> API clean-up aournd ref-filter code.\n>>\n>> Will merge to 'next'.\n>\n> It will be merged to next and if no people speak up (due to bugs\n> observed or such)\n\nI would guess, however, that Harald is wondering more specifically\nabout the \"--sort\" patch he added atop Peff's patches. Disposition for\n_that_ patch is not specified in the latest \"What's cooking\":\n\n    * hn/sort-ls-remote (2018-04-09) 1 commit\n     - ls-remote: create '--sort' option\n     (this branch uses jk/ref-array-push.)\n\n     \"git ls-remote\" learned an option to allow sorting its output based\n     on the refnames being shown.\n"},{"id":"344506","messageId":"xmqq37014973.fsf@gitster-ct.c.googlers.com","threadId":"48197","inReplyTo":"CAPig+cQzWAbEVBJ8O0yKYHQ02EaGTx9CeUyF67xozeT2-FL0EA@mail.gmail.com","subject":"Re: [PATCH v14 2/4] ref-filter: make ref_array_item allocation more consistent","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-04-11T23:25:36Z","receivedAt":"2018-04-11T23:25:43Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Eric Sunshine <sunshine@sunshineco.com> writes:\n\n> On Wed, Apr 11, 2018 at 2:07 PM, Stefan Beller <sbeller@google.com> wrote:\n>> On Wed, Apr 11, 2018 at 10:57 AM, Harald Nordgren\n>> <haraldnordgren@gmail.com> wrote:\n>>> There have been no new comments for the last few days. I know Jeff\n>>> King will be away for the next two weeks, but should we still move\n>>> forward with this? The initial reactions to the idea seemed positive.\n>> ...\n>> It will be merged to next and if no people speak up (due to bugs\n>> observed or such)\n>\n> I would guess, however, that Harald is wondering more specifically\n> about the \"--sort\" patch he added atop Peff's patches. Disposition for\n> _that_ patch is not specified in the latest \"What's cooking\":\n>\n>     * hn/sort-ls-remote (2018-04-09) 1 commit\n>      - ls-remote: create '--sort' option\n>      (this branch uses jk/ref-array-push.)\n>\n>      \"git ls-remote\" learned an option to allow sorting its output based\n>      on the refnames being shown.\n\nThanks all for summarizing.\n\nI think the preliminary clean-up patches by Peff are all\nindependently good and can be advanced, even without him being\naround.  I haven't formed a firm opinion on the doneness of the\nlatest round of the \"--sort\" thing.  I usually do not explicitly\nwrite \"I haven't formed an opinion\" in \"What's cooking\" report,\nso please read the lack of \"disposition\" as such.\n"},{"id":"347437","messageId":"b5555929-9f7c-1c4a-78e8-708ebdaaa9d2@web.de","threadId":"48197","inReplyTo":"20180409014226.2647-4-haraldnordgren@gmail.com","subject":"Re: [PATCH v14 4/4] ls-remote: create '--sort' option","fromName":"René Scharfe","fromEmail":"l.s.r@web.de","sentAt":"2018-05-12T08:45:23Z","receivedAt":"2018-05-12T08:45:35Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Am 09.04.2018 um 03:42 schrieb Harald Nordgren:\n> diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh\n> index 02106c922..83cd35c39 100755\n> --- a/t/t5512-ls-remote.sh\n> +++ b/t/t5512-ls-remote.sh\n\n> @@ -170,14 +206,18 @@ test_expect_success 'overrides work between mixed transfer/upload-pack hideRefs'\n>   \tgrep refs/tags/magic actual\n>   '\n>   \n> +git fetch origin\n>   test_expect_success 'ls-remote --symref' '\n> -\tcat >expect <<-\\EOF &&\n> +\tcat >expect <<-EOF &&\n>   \tref: refs/heads/master\tHEAD\n> -\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\tHEAD\n> -\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/heads/master\n> -\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/remotes/origin/HEAD\n> -\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/remotes/origin/master\n> -\t1bd44cb9d13204b0fe1958db0082f5028a16eb3a\trefs/tags/mark\n> +\t$(git rev-parse HEAD)\tHEAD\n> +\t$(git rev-parse refs/heads/master)\trefs/heads/master\n> +\t$(git rev-parse HEAD)\trefs/remotes/origin/HEAD\n> +\t$(git rev-parse refs/remotes/origin/master)\trefs/remotes/origin/master\n> +\t$(git rev-parse refs/tags/mark)\trefs/tags/mark\n> +\t$(git rev-parse refs/tags/mark1.1)\trefs/tags/mark1.1\n> +\t$(git rev-parse refs/tags/mark1.10)\trefs/tags/mark1.10\n> +\t$(git rev-parse refs/tags/mark1.2)\trefs/tags/mark1.2\n>   \tEOF\n>   \tgit ls-remote --symref >actual &&\n>   \ttest_cmp expect actual\n\nWhy is fetch called outside of the test?  Its output is shown among the\ntest messages, where it doesn't belong:\n\n    ok 23 - overrides work between mixed transfer/upload-pack hideRefs\n    From /home/lsr/src/git/t/trash directory.t5512-ls-remote/\n     * [new branch]      master     -> origin/master\n    ok 24 - ls-remote --symref\n\n-- >8 --\nSubject: [PATCH] t5512: run git fetch inside test\n\nDo the preparatory fetch inside the test of ls-remote --symref to avoid\ncluttering the test output and to be able to catch unexpected fetch\nfailures.\n\nSigned-off-by: Rene Scharfe <l.s.r@web.de>\n---\n t/t5512-ls-remote.sh | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh\nindex 83cd35c391..6a949484d0 100755\n--- a/t/t5512-ls-remote.sh\n+++ b/t/t5512-ls-remote.sh\n@@ -206,8 +206,8 @@ test_expect_success 'overrides work between mixed transfer/upload-pack hideRefs'\n \tgrep refs/tags/magic actual\n '\n \n-git fetch origin\n test_expect_success 'ls-remote --symref' '\n+\tgit fetch origin &&\n \tcat >expect <<-EOF &&\n \tref: refs/heads/master\tHEAD\n \t$(git rev-parse HEAD)\tHEAD\n-- \n2.17.0\n"},{"id":"347451","messageId":"20180512095523.GA2234@sigill.intra.peff.net","threadId":"48197","inReplyTo":"b5555929-9f7c-1c4a-78e8-708ebdaaa9d2@web.de","subject":"Re: [PATCH v14 4/4] ls-remote: create '--sort' option","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-05-12T09:55:23Z","receivedAt":"2018-05-12T09:55:28Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sat, May 12, 2018 at 10:45:23AM +0200, René Scharfe wrote:\n\n> Why is fetch called outside of the test?  Its output is shown among the\n> test messages, where it doesn't belong:\n> \n>     ok 23 - overrides work between mixed transfer/upload-pack hideRefs\n>     From /home/lsr/src/git/t/trash directory.t5512-ls-remote/\n>      * [new branch]      master     -> origin/master\n>     ok 24 - ls-remote --symref\n\nHeh, I just noticed this yesterday, too, but ran out of time before\nwriting up the patch.\n\n> -- >8 --\n> Subject: [PATCH] t5512: run git fetch inside test\n> \n> Do the preparatory fetch inside the test of ls-remote --symref to avoid\n> cluttering the test output and to be able to catch unexpected fetch\n> failures.\n\nYep, this looks obviously correct.\n\n-Peff\n"}]}