threads / patch / 64674

patch, 2 partsFix shallow clone with ref-in-want enabled

Subject: [PATCH 0/2] Fix shallow clone with ref-in-want enabled

## tl;dr

4 messages between Dec 24, 2025 and Jan 5, 2026. Diffs are folded; open one to read it.

replies: 3people: 2as markdown or json

Matthew Dodd· Dec 24, 2025, 00:35 UTC · lore
From: Mats-Dodd <mats.dodd12@gmail.com>

The ref-in-want feature (uploadpack.allowRefInWant) has been broken with shallow clones since it was introduced in 516e2b76bdc (upload-pack: implement ref-in-want, 2018-06-27). When enabled, shallow clones fail with:

    fatal: expected 'packfile', received 'shallow-info'

The server sends protocol v2 sections in the wrong order, violating the specification in Documentation/gitprotocol-v2.adoc and client expectations in fetch-pack.c.

This series:
1. Fixes the section ordering in upload-pack.c (swap two lines)
2. Adds a regression test for shallow clone + ref-in-want
Mats-Dodd (2):
  upload-pack: send shallow-info before wanted-refs in protocol v2
  t5703: add test for shallow fetch with ref-in-want
 t/t5703-upload-pack-ref-in-want.sh | 9 +++++++++
 upload-pack.c                      | 2 +-
 2 files changed, 10 insertions(+), 1 deletion(-)
base-commit: 9a2fb147f2c61d0cab52c883e7e26f5b7948e3ed
-- 
2.47.0
Matthew Dodd· Dec 24, 2025, 00:35 UTC · re: Matthew Dodd · lore

[PATCH 1/2] upload-pack: send shallow-info before wanted-refs in protocol v2

From: Mats-Dodd <mats.dodd12@gmail.com>

The protocol v2 specification (Documentation/gitprotocol-v2.adoc) defines the ordering of optional sections in the fetch response as:

    [acknowledgments delim-pkt] [shallow-info delim-pkt]
    [wanted-refs delim-pkt] [packfile-uris delim-pkt]
    packfile flush-pkt

However, since the ref-in-want feature was introduced in 516e2b76bdc (upload-pack: implement ref-in-want, 2018-06-27), the server sends wanted-refs before shallow-info. This violates the specification and breaks the client (fetch-pack.c), which expects shallow-info first.

When a client performs a shallow clone/fetch against a server with uploadpack.allowRefInWant=true, the client receives sections in the wrong order and fails with:

    fatal: expected 'packfile', received 'shallow-info'

Fix by swapping the order of send_shallow_info() and send_wanted_ref_info() to match both the protocol specification and client expectations.

Signed-off-by: Mats-Dodd <mats.dodd12@gmail.com>
---
 upload-pack.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
Show changes to upload-pack.c +1 −1
diff --git a/upload-pack.c b/upload-pack.c
index 1e87ae9559..029ca93e69 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -1830,8 +1830,8 @@ int upload_pack_v2(struct repository *r, struct packet_reader *request)
 				state = UPLOAD_DONE;
 			break;
 		case UPLOAD_SEND_PACK:
-			send_wanted_ref_info(&data);
 			send_shallow_info(&data);
+			send_wanted_ref_info(&data);
 
 			if (data.uri_protocols.nr) {
 				create_pack_file(&data, &data.uri_protocols);
-- 
2.47.0
Patrick Steinhardt· Jan 5, 2026, 13:00 UTC · re: Matthew Dodd · lore

Re: [PATCH 1/2] upload-pack: send shallow-info before wanted-refs in protocol v2

On Wed, Dec 24, 2025 at 01:35:03AM +0100, Matthew Dodd wrote:
Show 21 quoted lines
> From: Mats-Dodd <mats.dodd12@gmail.com>
> 
> The protocol v2 specification (Documentation/gitprotocol-v2.adoc) defines
> the ordering of optional sections in the fetch response as:
> 
>     [acknowledgments delim-pkt] [shallow-info delim-pkt]
>     [wanted-refs delim-pkt] [packfile-uris delim-pkt]
>     packfile flush-pkt
> 
> However, since the ref-in-want feature was introduced in 516e2b76bdc
> (upload-pack: implement ref-in-want, 2018-06-27), the server sends
> wanted-refs before shallow-info. This violates the specification and
> breaks the client (fetch-pack.c), which expects shallow-info first.
> 
> When a client performs a shallow clone/fetch against a server with
> uploadpack.allowRefInWant=true, the client receives sections in the
> wrong order and fails with:
> 
>     fatal: expected 'packfile', received 'shallow-info'
> 
> Fix by swapping the order of send_shallow_info() and
Nit: is there a word missing here? E.g. "Fix this by..."
Show 11 quoted lines
> diff --git a/upload-pack.c b/upload-pack.c
> index 1e87ae9559..029ca93e69 100644
> --- a/upload-pack.c
> +++ b/upload-pack.c
> @@ -1830,8 +1830,8 @@ int upload_pack_v2(struct repository *r, struct packet_reader *request)
>  				state = UPLOAD_DONE;
>  			break;
>  		case UPLOAD_SEND_PACK:
> -			send_wanted_ref_info(&data);
>  			send_shallow_info(&data);
> +			send_wanted_ref_info(&data);

Indeed. The accompanying code in "fetch-pack.c" expects information the other way round:

	if (process_section_header(&reader, "shallow-info", 1))
		receive_shallow_info(args, &reader, shallows, si);
	if (process_section_header(&reader, "wanted-refs", 1))
		receive_wanted_refs(&reader, sought, nr_sought);

The bug seems to exist since the inception of this feature. 516e2b76bd (upload-pack: implement ref-in-want, 2018-06-27) implements the server side in the current-broken way, and 733020517a (fetch-pack: implement ref-in-want, 2018-06-27) implements the client side in the correct way. So this combination has always been broken, and the fix looks obviously correct to me indeed.

One nit though: I don't really think it's necessary to split up this series into two patches. The new test can simply be added to this commit here.

Thanks!
Patrick
Matthew Dodd· Dec 24, 2025, 00:35 UTC · re: Matthew Dodd · lore

[PATCH 2/2] t5703: add test for shallow fetch with ref-in-want

From: Mats-Dodd <mats.dodd12@gmail.com>

Add a regression test for shallow clone operations when the server has uploadpack.allowRefInWant enabled. Before the previous commit, this operation would fail with:

    fatal: expected 'packfile', received 'shallow-info'

This was due to the server sending protocol v2 sections in the wrong order. The test ensures this scenario continues to work.

Signed-off-by: Mats-Dodd <mats.dodd12@gmail.com>
---
 t/t5703-upload-pack-ref-in-want.sh | 9 +++++++++
 1 file changed, 9 insertions(+)
Show changes to t/t5703-upload-pack-ref-in-want.sh +9 −0
diff --git a/t/t5703-upload-pack-ref-in-want.sh b/t/t5703-upload-pack-ref-in-want.sh
index 249137b467..21f4049eb4 100755
--- a/t/t5703-upload-pack-ref-in-want.sh
+++ b/t/t5703-upload-pack-ref-in-want.sh
@@ -256,6 +256,15 @@ test_expect_success 'fetching multiple refs' '
 	grep "want-ref refs/heads/baz" log
 '
 
+test_expect_success 'fetching with ref-in-want and shallow' '
+	rm -rf local &&
+	git -c protocol.version=2 clone --depth=1 "file://$REPO" local &&
+
+	git -C "$REPO" rev-parse main >expected &&
+	git -C local rev-parse refs/remotes/origin/main >actual &&
+	test_cmp expected actual
+'
+
 test_expect_success 'fetching ref and exact OID' '
 	test_when_finished "rm -f log" &&
 
-- 
2.47.0

← back to recent threads