ls-remote: create '--count' option
diff mbox series

Message ID 20190918001134.20776-1-kamil@domanski.co
State New
Headers show
Series
  • ls-remote: create '--count' option
Related show

Commit Message

Kamil Domański Sept. 18, 2019, 12:11 a.m. UTC
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 <kamil@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(-)

Comments

Johannes Sixt Sept. 18, 2019, 6:28 a.m. UTC | #1
Am 18.09.19 um 02:11 schrieb Kamil Domański:
> 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 <kamil@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>...]]

It is understandable that the new option is important to _you_, but it
does not seem important enough that it must be the first in the list.
Please add it between --symref and <repository>

>  
>  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.

Is the meaning of this option perhaps:

    Stops after the specified count of refs have been listed.
    If `--sort=<key>` is specified as well, refs are counted
    after sorting; otherwise, it is unspecified which subset
    of is listed.

I do not know whether the "otherwise" part would be true (check it!),
but I am pretty certain that the "If" part must be true, otherwise the
option would be pointless.

The comment about the ordering of this paragraph at the very beginning
of the option list applies here, too, because the list is not sorted
alphabetically.

-- Hannes
Junio C Hamano Sept. 18, 2019, 5:28 p.m. UTC | #2
Johannes Sixt <j6t@kdbg.org> writes:

> Am 18.09.19 um 02:11 schrieb Kamil Domański:
>> 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 <kamil@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>...]]
>
> It is understandable that the new option is important to _you_, but it
> does not seem important enough that it must be the first in the list.
> Please add it between --symref and <repository>
>
>>  
>>  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.
>
> Is the meaning of this option perhaps:
>
>     Stops after the specified count of refs have been listed.
>     If `--sort=<key>` is specified as well, refs are counted
>     after sorting; otherwise, it is unspecified which subset
>     of is listed.
>
> I do not know whether the "otherwise" part would be true (check it!),
> but I am pretty certain that the "If" part must be true, otherwise the
> option would be pointless.
>
> The comment about the ordering of this paragraph at the very beginning
> of the option list applies here, too, because the list is not sorted
> alphabetically.

All sensible comments and suggestions.  I am not sure what's so hard
to pipe the output to "head -n 20" or something like that, though.
Kamil Domański Sept. 18, 2019, 9:44 p.m. UTC | #3
On 9/18/19 8:28 AM, Johannes Sixt wrote:
> Am 18.09.19 um 02:11 schrieb Kamil Domański:
>> 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 <kamil@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>...]]
> It is understandable that the new option is important to _you_, but it
> does not seem important enough that it must be the first in the list.
> Please add it between --symref and <repository>
The assumption is quite unnecessary. I merely tried to reflect the 
position of this parameter in the 'for-each-ref' command, on which I 
based the patch.
>>   
>>   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.
> Is the meaning of this option perhaps:
>
>      Stops after the specified count of refs have been listed.
>      If `--sort=<key>` is specified as well, refs are counted
>      after sorting; otherwise, it is unspecified which subset
>      of is listed.

Similarly, I merely copied the description used by 'for-each-ref'. I 
like your version as well, since it clarifies the relation to sorting. 
Should the description for 'for-each-ref' be changed as well then?

> I do not know whether the "otherwise" part would be true (check it!),
> but I am pretty certain that the "If" part must be true, otherwise the
> option would be pointless.

Yes, both in 'for-each-ref' as well as this patch, cutting off the 
results takes place after the whole set has been already sorted. As for 
the "otherwise" part, it appears that 'for-each-ref' defaults to sorting 
by 'refname' (through ref_default_sorting() ) if no alternative sorting 
is provided, while 'ls-remote' does no such defaulting. Do you figure it 
would be a good idea to add another patch which would introduce a 
similar default in 'ls-remote'?


Regards,

Kamil
Johannes Sixt Sept. 19, 2019, 6:40 p.m. UTC | #4
Am 18.09.19 um 23:44 schrieb Kamil Domański:
> On 9/18/19 8:28 AM, Johannes Sixt wrote:
>> Am 18.09.19 um 02:11 schrieb Kamil Domański:
>>>     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.
>> Is the meaning of this option perhaps:
>>
>>      Stops after the specified count of refs have been listed.
>>      If `--sort=<key>` is specified as well, refs are counted
>>      after sorting; otherwise, it is unspecified which subset
>>      of is listed.
> 
> Similarly, I merely copied the description used by 'for-each-ref'. I
> like your version as well, since it clarifies the relation to sorting.
> Should the description for 'for-each-ref' be changed as well then?

I am neutral. If you do it, then it should not happen in the same patch
as this change.

> ... it appears that 'for-each-ref' defaults to sorting
> by 'refname' (through ref_default_sorting() ) if no alternative sorting
> is provided, while 'ls-remote' does no such defaulting. Do you figure it
> would be a good idea to add another patch which would introduce a
> similar default in 'ls-remote'?

I don't think so. I would think that in the case of ls-remote it is
preferable to stream refs to the output as soon as they are received
from the remote. If refs must be sorted, it would have to wait until the
remote has sent all refs before it can do anything.

That said, Junio's question remains open: why is piping though head -n
not good enough?

-- Hannes

Patch
diff mbox series

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
 '