* [PATCH] ls-remote: add --show-object-format
@ 2026-11-05 10:45 Adrian Ratiu
2026-11-05 14:13 ` Patrick Steinhardt
0 siblings, 1 reply; 3+ messages in thread
From: Adrian Ratiu @ 2026-11-05 10:45 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, brian m . carlson, Axel Rasmussen, Emily Shaffer,
Josh Steadmon, Adrian Ratiu
While working on JJ sha256 remote support (it uses Git for networking),
I noticed there is no way to get the object format of a repo without
cloning it. [1]
Git clone learns the remote format during the protocol handshake, but
it is not shown anywhere else. For example, when creating an empty repo
and running "git fetch":
1. If the remote has references, fetch can fail with a mismatch error
and "git ls-remote" shows the format indirectly through the length
of the object IDs. Not ideal, but the it can be figured out eventually.
2. If the remote is empty, "git ls-remote" prints nothing and fetch
succeeds, so the new local repo can silently get the wrong format,
which only shows up later, on the first push.
To fill this gap, add a ls-remote --show-object-format option which
prints the object format learned from the remote on a line of its own,
before the references.
[1]: https://github.com/jj-vcs/jj/issues/3813
Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com>
---
Documentation/git-ls-remote.adoc | 10 ++++++-
builtin/ls-remote.c | 8 +++++-
t/t5512-ls-remote.sh | 46 ++++++++++++++++++++++++++++++++
3 files changed, 62 insertions(+), 2 deletions(-)
diff --git a/Documentation/git-ls-remote.adoc b/Documentation/git-ls-remote.adoc
index d71c4ab3e2..1abf7b60b7 100644
--- a/Documentation/git-ls-remote.adoc
+++ b/Documentation/git-ls-remote.adoc
@@ -11,7 +11,8 @@ SYNOPSIS
[verse]
'git ls-remote' [--branches] [--tags] [--refs] [--upload-pack=<exec>]
[-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]
- [--symref] [<repository> [<patterns>...]]
+ [--symref] [--show-object-format]
+ [<repository> [<patterns>...]]
DESCRIPTION
-----------
@@ -64,6 +65,13 @@ OPTIONS
upload-pack only shows the symref HEAD, so it will be the only
one shown by ls-remote.
+--show-object-format::
+ Show the object format (hash algorithm, e.g. `sha1` or `sha256`) used
+ by the remote repository before printing the references, on a line of
+ its own. This also works for a remote repo without any refs, which is
+ useful to find out which object format to use for a local repository,
+ before pushing or fetching the new remote.
+
--sort=<key>::
Sort based on the key given. Prefix `-` to sort in descending order
of the value. Supports "version:refname" or "v:refname" (tag names
diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c
index fe77829557..6d961f9961 100644
--- a/builtin/ls-remote.c
+++ b/builtin/ls-remote.c
@@ -12,7 +12,8 @@
static const char * const ls_remote_usage[] = {
N_("git ls-remote [--branches] [--tags] [--refs] [--upload-pack=<exec>]\n"
" [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n"
- " [--symref] [<repository> [<patterns>...]]"),
+ " [--symref] [--show-object-format]\n"
+ " [<repository> [<patterns>...]]"),
NULL
};
@@ -49,6 +50,7 @@ int cmd_ls_remote(int argc,
int quiet = 0;
int status = 0;
int show_symref_target = 0;
+ int show_object_format = 0;
const char *uploadpack = NULL;
struct strvec pattern = STRVEC_INIT;
struct transport_ls_refs_options transport_options =
@@ -89,6 +91,8 @@ int cmd_ls_remote(int argc,
2, PARSE_OPT_NOCOMPLETE),
OPT_BOOL(0, "symref", &show_symref_target,
N_("show underlying ref in addition to the object pointed by it")),
+ OPT_BOOL(0, "show-object-format", &show_object_format,
+ N_("show the object format used by the remote repository")),
OPT_STRING_LIST('o', "server-option", &server_options, N_("server-specific"), N_("option to transmit")),
OPT_END()
};
@@ -150,6 +154,8 @@ int cmd_ls_remote(int argc,
if (!dest && !quiet)
fprintf(stderr, "From %s\n", remote->url.v[0]);
+ if (show_object_format)
+ printf("%s\n", transport_get_hash_algo(transport)->name);
for ( ; ref; ref = ref->next) {
struct ref_array_item *item;
if (!check_ref_type(ref, flags))
diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh
index 2e1d4f7586..7e82154fe4 100755
--- a/t/t5512-ls-remote.sh
+++ b/t/t5512-ls-remote.sh
@@ -332,6 +332,52 @@ test_expect_success 'indicate no refs in v0 standards-compliant empty remote' '
test_expect_code 2 git ls-remote --exit-code --upload-pack=./cat-input .
'
+# Run "ls-remote --show-object-format" with the given arguments over
+# protocol v0 and v2, and compare its output with "expect".
+test_show_object_format () {
+ for version in 0 2
+ do
+ git -c protocol.version=$version \
+ ls-remote --show-object-format "$@" >actual &&
+ test_cmp expect actual || return 1
+ done
+}
+
+test_expect_success 'ls-remote --show-object-format with empty sha1 remote' '
+ git init --bare --object-format=sha1 empty-sha1.git &&
+ echo sha1 >expect &&
+ test_show_object_format empty-sha1.git
+'
+
+test_expect_success 'ls-remote --show-object-format with empty sha256 remote' '
+ git init --bare --object-format=sha256 empty-sha256.git &&
+ echo sha256 >expect &&
+ test_show_object_format empty-sha256.git
+'
+
+test_expect_success 'ls-remote --show-object-format with sha1 remote' '
+ git init --object-format=sha1 repo-sha1 &&
+ test_commit -C repo-sha1 one &&
+ oid=$(git -C repo-sha1 rev-parse HEAD) &&
+ printf "sha1\n%s\tHEAD\n" "$oid" >expect &&
+ test_show_object_format repo-sha1 HEAD
+'
+
+test_expect_success 'ls-remote --show-object-format with sha256 remote' '
+ git init --object-format=sha256 repo-sha256 &&
+ test_commit -C repo-sha256 one &&
+ oid=$(git -C repo-sha256 rev-parse HEAD) &&
+ printf "sha256\n%s\tHEAD\n" "$oid" >expect &&
+ test_show_object_format repo-sha256 HEAD
+'
+
+test_expect_success 'ls-remote --show-object-format outside repository' '
+ nongit git init --bare --object-format=sha256 empty-nongit.git &&
+ echo sha256 >expect &&
+ nongit git ls-remote --show-object-format empty-nongit.git >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'ls-remote works outside repository' '
# It is important for this repo to be inside the nongit
# area, as we want a repo name that does not include
--
2.56.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH] ls-remote: add --show-object-format
2026-11-05 10:45 [PATCH] ls-remote: add --show-object-format Adrian Ratiu
@ 2026-11-05 14:13 ` Patrick Steinhardt
2026-11-05 16:35 ` Adrian Ratiu
0 siblings, 1 reply; 3+ messages in thread
From: Patrick Steinhardt @ 2026-11-05 14:13 UTC (permalink / raw)
To: Adrian Ratiu
Cc: git, Junio C Hamano, brian m . carlson, Axel Rasmussen,
Emily Shaffer, Josh Steadmon
On Thu, Nov 05, 2026 at 12:45:41PM +0200, Adrian Ratiu wrote:
> While working on JJ sha256 remote support (it uses Git for networking),
> I noticed there is no way to get the object format of a repo without
> cloning it. [1]
>
> Git clone learns the remote format during the protocol handshake, but
> it is not shown anywhere else. For example, when creating an empty repo
> and running "git fetch":
>
> 1. If the remote has references, fetch can fail with a mismatch error
> and "git ls-remote" shows the format indirectly through the length
> of the object IDs. Not ideal, but the it can be figured out eventually.
s/the it/then it/
Also, this is a somewhat imperfect way to detect the hash algorithm as
it assumes that we don't ever add a third hash that has the same length
as either of the existing ones. So it works now, but it may not work in
the future anymore.
> 2. If the remote is empty, "git ls-remote" prints nothing and fetch
> succeeds, so the new local repo can silently get the wrong format,
> which only shows up later, on the first push.
>
> To fill this gap, add a ls-remote --show-object-format option which
> prints the object format learned from the remote on a line of its own,
> before the references.
Seems sensible.
> diff --git a/Documentation/git-ls-remote.adoc b/Documentation/git-ls-remote.adoc
> index d71c4ab3e2..1abf7b60b7 100644
> --- a/Documentation/git-ls-remote.adoc
> +++ b/Documentation/git-ls-remote.adoc
> @@ -64,6 +65,13 @@ OPTIONS
> upload-pack only shows the symref HEAD, so it will be the only
> one shown by ls-remote.
>
> +--show-object-format::
> + Show the object format (hash algorithm, e.g. `sha1` or `sha256`) used
> + by the remote repository before printing the references, on a line of
> + its own. This also works for a remote repo without any refs, which is
> + useful to find out which object format to use for a local repository,
A bit curious that you first say "repo" and then "repository". I'd just
drop "repo".
> diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c
> index fe77829557..6d961f9961 100644
> --- a/builtin/ls-remote.c
> +++ b/builtin/ls-remote.c
> @@ -150,6 +154,8 @@ int cmd_ls_remote(int argc,
>
> if (!dest && !quiet)
> fprintf(stderr, "From %s\n", remote->url.v[0]);
> + if (show_object_format)
> + printf("%s\n", transport_get_hash_algo(transport)->name);
Should we maybe make this a tiny bit more extensible by not printing the
object format without any kind of prefix? We could for example instead
print "object-format: %s", which would allow us to add more fields in
the future without the need to make parsers be order-dependent.
Also, one more question I had is whether we know that the hash algo will
always be populated here. I would assume so, as we have this logic a
couple lines further up:
ref = transport_get_remote_refs(transport, &transport_options);
if (ref) {
int hash_algo = hash_algo_by_ptr(transport_get_hash_algo(transport));
repo_set_hash_algo(the_repository, hash_algo);
}
But in theory, this logic would also work alright if the hash was NULL.
> diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh
> index 2e1d4f7586..7e82154fe4 100755
> --- a/t/t5512-ls-remote.sh
> +++ b/t/t5512-ls-remote.sh
> @@ -332,6 +332,52 @@ test_expect_success 'indicate no refs in v0 standards-compliant empty remote' '
> test_expect_code 2 git ls-remote --exit-code --upload-pack=./cat-input .
> '
>
> +# Run "ls-remote --show-object-format" with the given arguments over
> +# protocol v0 and v2, and compare its output with "expect".
> +test_show_object_format () {
> + for version in 0 2
> + do
> + git -c protocol.version=$version \
> + ls-remote --show-object-format "$@" >actual &&
> + test_cmp expect actual || return 1
It's a bit weird that we expect the caller to already have written
`expect`. A better interface would be to have them call the expected
object format as another parameter.
> + done
> +}
> +
> +test_expect_success 'ls-remote --show-object-format with empty sha1 remote' '
> + git init --bare --object-format=sha1 empty-sha1.git &&
> + echo sha1 >expect &&
> + test_show_object_format empty-sha1.git
> +'
> +
> +test_expect_success 'ls-remote --show-object-format with empty sha256 remote' '
> + git init --bare --object-format=sha256 empty-sha256.git &&
> + echo sha256 >expect &&
> + test_show_object_format empty-sha256.git
> +'
We could easily deduplicate these tests by looping around `for hash in
sha1 sha256`.
Thanks!
Patrick
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] ls-remote: add --show-object-format
2026-11-05 14:13 ` Patrick Steinhardt
@ 2026-11-05 16:35 ` Adrian Ratiu
0 siblings, 0 replies; 3+ messages in thread
From: Adrian Ratiu @ 2026-11-05 16:35 UTC (permalink / raw)
To: Patrick Steinhardt
Cc: git, Junio C Hamano, brian m . carlson, Axel Rasmussen,
Emily Shaffer, Josh Steadmon
Hi Patrick and thank you for the awesome review, as always.
I'll let this sit for about 1 week to also give others a chance to
review, then send v2 addresing all your feedback.
On Thu, 05 Nov 2026, Patrick Steinhardt <ps@pks.im> wrote:
<snip>
>> diff --git a/Documentation/git-ls-remote.adoc b/Documentation/git-ls-remote.adoc
>> index d71c4ab3e2..1abf7b60b7 100644
>> --- a/Documentation/git-ls-remote.adoc
>> +++ b/Documentation/git-ls-remote.adoc
>> @@ -64,6 +65,13 @@ OPTIONS
>> upload-pack only shows the symref HEAD, so it will be the only
>> one shown by ls-remote.
>>
>> +--show-object-format::
>> + Show the object format (hash algorithm, e.g. `sha1` or `sha256`) used
>> + by the remote repository before printing the references, on a line of
>> + its own. This also works for a remote repo without any refs, which is
>> + useful to find out which object format to use for a local repository,
>
> A bit curious that you first say "repo" and then "repository". I'd just
> drop "repo".
Initially I wrote repository twice then the lines didn't fit, so I cut
repository -> repo to make them fit. :)
English is also not my first nor second languege, so I tend to keep
rewriting multiple times before sending. It's still not "good" on the
Nth read, tbh.
I'll try to improve this further to avoid redundancies, for e.g. I just
realized I wrote "--show-objoct-format" then immediately I repeated "Show
the object format on the next line". =)
>
>> diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c
>> index fe77829557..6d961f9961 100644
>> --- a/builtin/ls-remote.c
>> +++ b/builtin/ls-remote.c
>> @@ -150,6 +154,8 @@ int cmd_ls_remote(int argc,
>>
>> if (!dest && !quiet)
>> fprintf(stderr, "From %s\n", remote->url.v[0]);
>> + if (show_object_format)
>> + printf("%s\n", transport_get_hash_algo(transport)->name);
>
> Should we maybe make this a tiny bit more extensible by not printing the
> object format without any kind of prefix? We could for example instead
> print "object-format: %s", which would allow us to add more fields in
> the future without the need to make parsers be order-dependent.
Yes, this is a great idea, will do in v2.
(I just need to know the sha1 vs sha256 information, the format can be
anything at all, no strong preference on my side).
>
> Also, one more question I had is whether we know that the hash algo will
> always be populated here. I would assume so, as we have this logic a
> couple lines further up:
>
> ref = transport_get_remote_refs(transport, &transport_options);
> if (ref) {
> int hash_algo = hash_algo_by_ptr(transport_get_hash_algo(transport));
> repo_set_hash_algo(the_repository, hash_algo);
> }
>
> But in theory, this logic would also work alright if the hash was
> NULL.
Yes, the hash format will always be populated by the time we call
transport_get_hash_algo() here.
>> diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh
>> index 2e1d4f7586..7e82154fe4 100755
>> --- a/t/t5512-ls-remote.sh
>> +++ b/t/t5512-ls-remote.sh
>> @@ -332,6 +332,52 @@ test_expect_success 'indicate no refs in v0 standards-compliant empty remote' '
>> test_expect_code 2 git ls-remote --exit-code --upload-pack=./cat-input .
>> '
>>
>> +# Run "ls-remote --show-object-format" with the given arguments over
>> +# protocol v0 and v2, and compare its output with "expect".
>> +test_show_object_format () {
>> + for version in 0 2
>> + do
>> + git -c protocol.version=$version \
>> + ls-remote --show-object-format "$@" >actual &&
>> + test_cmp expect actual || return 1
>
> It's a bit weird that we expect the caller to already have written
> `expect`. A better interface would be to have them call the expected
> object format as another parameter.
Ack, will do in v2.
>> + done
>> +}
>> +
>> +test_expect_success 'ls-remote --show-object-format with empty sha1 remote' '
>> + git init --bare --object-format=sha1 empty-sha1.git &&
>> + echo sha1 >expect &&
>> + test_show_object_format empty-sha1.git
>> +'
>> +
>> +test_expect_success 'ls-remote --show-object-format with empty sha256 remote' '
>> + git init --bare --object-format=sha256 empty-sha256.git &&
>> + echo sha256 >expect &&
>> + test_show_object_format empty-sha256.git
>> +'
>
> We could easily deduplicate these tests by looping around `for hash in
> sha1 sha256`.
Ack, will do in v2.
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-11-05 16:36 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-05 10:45 [PATCH] ls-remote: add --show-object-format Adrian Ratiu
2026-11-05 14:13 ` Patrick Steinhardt
2026-11-05 16:35 ` Adrian Ratiu
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox