Skip to content

Commit 6b02c0f

Browse files
committed
Merge branch 'cw/fix-reachable-in-repo-with-promisor' into seen
* cw/fix-reachable-in-repo-with-promisor: fetch-pack.c: do not declare local commits as "have" in partial repos packfile: split promisor objects oidset into two
2 parents 365fc4b + 9d57a5f commit 6b02c0f

File tree

4 files changed

+64
-13
lines changed

4 files changed

+64
-13
lines changed

fetch-pack.c

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1297,12 +1297,23 @@ static void add_common(struct strbuf *req_buf, struct oidset *common)
12971297

12981298
static int add_haves(struct fetch_negotiator *negotiator,
12991299
struct strbuf *req_buf,
1300-
int *haves_to_send)
1300+
int *haves_to_send,
1301+
int from_promisor)
13011302
{
13021303
int haves_added = 0;
13031304
const struct object_id *oid;
13041305

13051306
while ((oid = negotiator->next(negotiator))) {
1307+
/*
1308+
* In partial repos, do not declare local objects as "have"
1309+
* so that they can be fetched into a promisor pack. Certain
1310+
* operations mark parent commits of promisor objects as
1311+
* UNINTERESTING and are subsequently garbage collected so
1312+
* this ensures local commits are still available in promisor
1313+
* packs after a fetch + gc.
1314+
*/
1315+
if (from_promisor && !is_in_promisor_pack(oid, 0))
1316+
continue;
13061317
packet_buf_write(req_buf, "have %s\n", oid_to_hex(oid));
13071318
if (++haves_added >= *haves_to_send)
13081319
break;
@@ -1405,7 +1416,7 @@ static int send_fetch_request(struct fetch_negotiator *negotiator, int fd_out,
14051416
/* Add all of the common commits we've found in previous rounds */
14061417
add_common(&req_buf, common);
14071418

1408-
haves_added = add_haves(negotiator, &req_buf, haves_to_send);
1419+
haves_added = add_haves(negotiator, &req_buf, haves_to_send, args->from_promisor);
14091420
*in_vain += haves_added;
14101421
trace2_data_intmax("negotiation_v2", the_repository, "haves_added", haves_added);
14111422
trace2_data_intmax("negotiation_v2", the_repository, "in_vain", *in_vain);
@@ -2178,7 +2189,7 @@ void negotiate_using_fetch(const struct oid_array *negotiation_tips,
21782189

21792190
packet_buf_write(&req_buf, "wait-for-done");
21802191

2181-
haves_added = add_haves(&negotiator, &req_buf, &haves_to_send);
2192+
haves_added = add_haves(&negotiator, &req_buf, &haves_to_send, 0);
21822193
in_vain += haves_added;
21832194
if (!haves_added || (seen_ack && in_vain >= MAX_IN_VAIN))
21842195
last_iteration = 1;

packfile.c

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2270,12 +2270,17 @@ int for_each_packed_object(each_packed_object_fn cb, void *data,
22702270
return r ? r : pack_errors;
22712271
}
22722272

2273+
struct promisor_objects {
2274+
struct oidset promisor_pack_objects;
2275+
struct oidset promisor_pack_referenced_objects;
2276+
};
2277+
22732278
static int add_promisor_object(const struct object_id *oid,
22742279
struct packed_git *pack UNUSED,
22752280
uint32_t pos UNUSED,
22762281
void *set_)
22772282
{
2278-
struct oidset *set = set_;
2283+
struct promisor_objects *set = set_;
22792284
struct object *obj;
22802285
int we_parsed_object;
22812286

@@ -2290,7 +2295,7 @@ static int add_promisor_object(const struct object_id *oid,
22902295
if (!obj)
22912296
return 1;
22922297

2293-
oidset_insert(set, oid);
2298+
oidset_insert(&set->promisor_pack_objects, oid);
22942299

22952300
/*
22962301
* If this is a tree, commit, or tag, the objects it refers
@@ -2308,26 +2313,26 @@ static int add_promisor_object(const struct object_id *oid,
23082313
*/
23092314
return 0;
23102315
while (tree_entry_gently(&desc, &entry))
2311-
oidset_insert(set, &entry.oid);
2316+
oidset_insert(&set->promisor_pack_referenced_objects, &entry.oid);
23122317
if (we_parsed_object)
23132318
free_tree_buffer(tree);
23142319
} else if (obj->type == OBJ_COMMIT) {
23152320
struct commit *commit = (struct commit *) obj;
23162321
struct commit_list *parents = commit->parents;
23172322

2318-
oidset_insert(set, get_commit_tree_oid(commit));
2323+
oidset_insert(&set->promisor_pack_referenced_objects, get_commit_tree_oid(commit));
23192324
for (; parents; parents = parents->next)
2320-
oidset_insert(set, &parents->item->object.oid);
2325+
oidset_insert(&set->promisor_pack_referenced_objects, &parents->item->object.oid);
23212326
} else if (obj->type == OBJ_TAG) {
23222327
struct tag *tag = (struct tag *) obj;
2323-
oidset_insert(set, get_tagged_oid(tag));
2328+
oidset_insert(&set->promisor_pack_referenced_objects, get_tagged_oid(tag));
23242329
}
23252330
return 0;
23262331
}
23272332

2328-
int is_promisor_object(const struct object_id *oid)
2333+
int is_in_promisor_pack(const struct object_id *oid, int referenced)
23292334
{
2330-
static struct oidset promisor_objects;
2335+
static struct promisor_objects promisor_objects;
23312336
static int promisor_objects_prepared;
23322337

23332338
if (!promisor_objects_prepared) {
@@ -2339,5 +2344,6 @@ int is_promisor_object(const struct object_id *oid)
23392344
}
23402345
promisor_objects_prepared = 1;
23412346
}
2342-
return oidset_contains(&promisor_objects, oid);
2347+
return oidset_contains(&promisor_objects.promisor_pack_objects, oid) ||
2348+
(referenced && oidset_contains(&promisor_objects.promisor_pack_referenced_objects, oid));
23432349
}

packfile.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,11 +195,16 @@ int has_object_kept_pack(const struct object_id *oid, unsigned flags);
195195

196196
int has_pack_index(const unsigned char *sha1);
197197

198+
int is_in_promisor_pack(const struct object_id *oid, int referenced);
199+
198200
/*
199201
* Return 1 if an object in a promisor packfile is or refers to the given
200202
* object, 0 otherwise.
201203
*/
202-
int is_promisor_object(const struct object_id *oid);
204+
static inline int is_promisor_object(const struct object_id *oid)
205+
{
206+
return is_in_promisor_pack(oid, 1);
207+
}
203208

204209
/*
205210
* Expose a function for fuzz testing.

t/t5616-partial-clone.sh

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -716,6 +716,35 @@ test_expect_success 'lazy-fetch in submodule succeeds' '
716716
git -C client restore --recurse-submodules --source=HEAD^ :/
717717
'
718718

719+
test_expect_success 'fetching from promisor remote fetches previously local commits' '
720+
# Setup
721+
git init full &&
722+
git -C full config uploadpack.allowfilter 1 &&
723+
git -C full config uploadpack.allowanysha1inwant 1 &&
724+
touch full/foo &&
725+
git -C full add foo &&
726+
git -C full commit -m "commit 1" &&
727+
git -C full checkout --detach &&
728+
729+
# Partial clone and push commit to remote
730+
git clone "file://$(pwd)/full" --filter=blob:none partial &&
731+
echo "hello" > partial/foo &&
732+
git -C partial commit -a -m "commit 2" &&
733+
git -C partial push &&
734+
735+
# gc in partial repo
736+
git -C partial gc --prune=now &&
737+
738+
# Create another commit in normal repo
739+
git -C full checkout main &&
740+
echo " world" >> full/foo &&
741+
git -C full commit -a -m "commit 3" &&
742+
743+
# Pull from remote in partial repo, and run gc again
744+
git -C partial pull &&
745+
git -C partial gc --prune=now
746+
'
747+
719748
. "$TEST_DIRECTORY"/lib-httpd.sh
720749
start_httpd
721750

0 commit comments

Comments
 (0)