Skip to content

Commit 35f9e3e

Browse files
jonathantanmygitster
authored andcommitted
fetch: in partial clone, check presence of targets
When fetching an object that is known as a promisor object to the local repository, the connectivity check in quickfetch() in builtin/fetch.c succeeds, causing object transfer to be bypassed. However, this should not happen if that object is merely promised and not actually present. Because this happens, when a user invokes "git fetch origin <sha-1>" on the command-line, the <sha-1> object may not actually be fetched even though the command returns an exit code of 0. This is a similar issue (but with a different cause) to the one fixed by a0c9016 ("upload-pack: send refs' objects despite "filter"", 2018-07-09). Therefore, update quickfetch() to also directly check for the presence of all objects to be fetched. Its documentation and name are also updated to better reflect what it does. Signed-off-by: Jonathan Tan <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 4937291 commit 35f9e3e

File tree

2 files changed

+30
-2
lines changed

2 files changed

+30
-2
lines changed

builtin/fetch.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -931,10 +931,11 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
931931
* everything we are going to fetch already exists and is connected
932932
* locally.
933933
*/
934-
static int quickfetch(struct ref *ref_map)
934+
static int check_exist_and_connected(struct ref *ref_map)
935935
{
936936
struct ref *rm = ref_map;
937937
struct check_connected_options opt = CHECK_CONNECTED_INIT;
938+
struct ref *r;
938939

939940
/*
940941
* If we are deepening a shallow clone we already have these
@@ -945,13 +946,23 @@ static int quickfetch(struct ref *ref_map)
945946
*/
946947
if (deepen)
947948
return -1;
949+
950+
/*
951+
* check_connected() allows objects to merely be promised, but
952+
* we need all direct targets to exist.
953+
*/
954+
for (r = rm; r; r = r->next) {
955+
if (!has_object_file(&r->old_oid))
956+
return -1;
957+
}
958+
948959
opt.quiet = 1;
949960
return check_connected(iterate_ref_map, &rm, &opt);
950961
}
951962

952963
static int fetch_refs(struct transport *transport, struct ref *ref_map)
953964
{
954-
int ret = quickfetch(ref_map);
965+
int ret = check_exist_and_connected(ref_map);
955966
if (ret)
956967
ret = transport_fetch_refs(transport, ref_map);
957968
if (!ret)

t/t5616-partial-clone.sh

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,23 @@ test_expect_success 'partial clone fetches blobs pointed to by refs even if norm
170170
git -C dst fsck
171171
'
172172

173+
test_expect_success 'fetch what is specified on CLI even if already promised' '
174+
rm -rf src dst.git &&
175+
git init src &&
176+
test_commit -C src foo &&
177+
test_config -C src uploadpack.allowfilter 1 &&
178+
test_config -C src uploadpack.allowanysha1inwant 1 &&
179+
180+
git hash-object --stdin <src/foo.t >blob &&
181+
182+
git clone --bare --filter=blob:none "file://$(pwd)/src" dst.git &&
183+
git -C dst.git rev-list --objects --quiet --missing=print HEAD >missing_before &&
184+
grep "?$(cat blob)" missing_before &&
185+
git -C dst.git fetch origin $(cat blob) &&
186+
git -C dst.git rev-list --objects --quiet --missing=print HEAD >missing_after &&
187+
! grep "?$(cat blob)" missing_after
188+
'
189+
173190
. "$TEST_DIRECTORY"/lib-httpd.sh
174191
start_httpd
175192

0 commit comments

Comments
 (0)