Create a '--count' option for ls-remote, based on the one from
for-each-ref. This allows e.g. to return only the first result
from a sorted list of refs.

Signed-off-by: Kamil Domański <ka...@domanski.co>
---
 Documentation/git-ls-remote.txt | 11 ++++++++---
 builtin/ls-remote.c             | 16 ++++++++++++----
 t/t5512-ls-remote.sh            |  9 +++++++++
 3 files changed, 29 insertions(+), 7 deletions(-)

diff --git a/Documentation/git-ls-remote.txt b/Documentation/git-ls-remote.txt
index 0b057cbb10..5adc1d676e 100644
--- a/Documentation/git-ls-remote.txt
+++ b/Documentation/git-ls-remote.txt
@@ -9,9 +9,9 @@ git-ls-remote - List references in a remote repository
 SYNOPSIS
 --------
 [verse]
-'git ls-remote' [--heads] [--tags] [--refs] [--upload-pack=<exec>]
-             [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]
-             [--symref] [<repository> [<refs>...]]
+'git ls-remote' [--count=<count>] [--heads] [--tags] [--refs]
+             [--upload-pack=<exec>] [-q | --quiet] [--exit-code] [--get-url]
+             [--sort=<key>] [--symref] [<repository> [<refs>...]]
 
 DESCRIPTION
 -----------
@@ -21,6 +21,11 @@ commit IDs.
 
 OPTIONS
 -------
+--count=<count>::
+       By default the command shows all refs that match
+       `<pattern>`.  This option makes it stop after showing
+       that many refs.
+
 -h::
 --heads::
 -t::
diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c
index 6ef519514b..482b8c5b3c 100644
--- a/builtin/ls-remote.c
+++ b/builtin/ls-remote.c
@@ -8,7 +8,7 @@
 static const char * const ls_remote_usage[] = {
        N_("git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
           "                     [-q | --quiet] [--exit-code] [--get-url]\n"
-          "                     [--symref] [<repository> [<refs>...]]"),
+          "                     [--symref] [--count=<n>] [<repository> 
[<refs>...]]"),
        NULL
 };
 
@@ -43,6 +43,7 @@ int cmd_ls_remote(int argc, const char **argv, const char 
*prefix)
        int quiet = 0;
        int status = 0;
        int show_symref_target = 0;
+       int maxcount = 0;
        const char *uploadpack = NULL;
        const char **pattern = NULL;
        struct argv_array ref_prefixes = ARGV_ARRAY_INIT;
@@ -55,7 +56,7 @@ int cmd_ls_remote(int argc, const char **argv, const char 
*prefix)
        struct ref_array ref_array;
        static struct ref_sorting *sorting = NULL, **sorting_tail = &sorting;
 
-       struct option options[] = {
+       struct option opts[] = {
                OPT__QUIET(&quiet, N_("do not print remote URL")),
                OPT_STRING(0, "upload-pack", &uploadpack, N_("exec"),
                           N_("path of git-upload-pack on the remote host")),
@@ -73,14 +74,19 @@ int cmd_ls_remote(int argc, const char **argv, const char 
*prefix)
                              2, PARSE_OPT_NOCOMPLETE),
                OPT_BOOL(0, "symref", &show_symref_target,
                         N_("show underlying ref in addition to the object 
pointed by it")),
+               OPT_INTEGER( 0 , "count", &maxcount, N_("show only <n> matched 
refs")),
                OPT_STRING_LIST('o', "server-option", &server_options, 
N_("server-specific"), N_("option to transmit")),
                OPT_END()
        };
 
        memset(&ref_array, 0, sizeof(ref_array));
 
-       argc = parse_options(argc, argv, prefix, options, ls_remote_usage,
+       argc = parse_options(argc, argv, prefix, opts, ls_remote_usage,
                             PARSE_OPT_STOP_AT_NON_OPTION);
+       if (maxcount < 0) {
+               error("invalid --count argument: `%d'", maxcount);
+               usage_with_options(ls_remote_usage, opts);
+       }
        dest = argv[0];
 
        if (argc > 1) {
@@ -138,7 +144,9 @@ int cmd_ls_remote(int argc, const char **argv, const char 
*prefix)
        if (sorting)
                ref_array_sort(sorting, &ref_array);
 
-       for (i = 0; i < ref_array.nr; i++) {
+       if (!maxcount || ref_array.nr < maxcount)
+               maxcount = ref_array.nr;
+       for (i = 0; i < maxcount; i++) {
                const struct ref_array_item *ref = ref_array.items[i];
                if (show_symref_target && ref->symref)
                        printf("ref: %s\t%s\n", ref->symref, ref->refname);
diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh
index 43e1d8d4d2..5c27a126bd 100755
--- a/t/t5512-ls-remote.sh
+++ b/t/t5512-ls-remote.sh
@@ -75,6 +75,15 @@ test_expect_success 'ls-remote --sort="-refname" --tags 
self' '
        test_cmp expect actual
 '
 
+test_expect_success 'ls-remote --count=2 --sort="refname" --tags self' '
+       cat >expect <<-EOF &&
+       $(git rev-parse mark)   refs/tags/mark
+       $(git rev-parse mark1.1)        refs/tags/mark1.1
+       EOF
+       git ls-remote --count=2 --sort="refname" --tags self >actual &&
+       test_cmp expect actual
+'
+
 test_expect_success 'dies when no remote specified and no default remotes 
found' '
        test_must_fail git ls-remote
 '
-- 
2.23.0

Reply via email to