@matheusbsbs / matheus-bagliano / commits / abcb7eeb31
Fork 0

fetch: only populate existing_refs if needed

In "fetch", get_ref_map() iterates over all refs to populate "existing_refs" in order to populate peer_ref->old_oid in the returned refmap, even if the refmap has no peer_ref set - which is the case when only literal hashes (i.e. no refs by name) are fetched. Iterating over refs causes the targets of those refs to be checked for existence. Avoiding this is especially important when we use "git fetch" to perform lazy fetches in a partial clone because a target of such a ref may need to be itself lazy-fetched (and otherwise causing an infinite loop). Therefore, avoid populating "existing_refs" until necessary. With this patch, because Git lazy-fetches objects by literal hashes (to be done in a subsequent commit), it will then be able to guarantee avoiding reading targets of refs. Signed-off-by: Jonathan Tan <jonathantanmy@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jonathan Tan committed Aug 17, 2020 at 21:01 UTC abcb7eeb31d0267ada469646be993ad25e127d0d
1 file changed +9 -4
builtin/fetch.c
+9 -4
@@ -445,6 +445,7 @@ static struct ref *get_ref_map(struct remote *remote,
445 struct ref *orefs = NULL, **oref_tail = &orefs;
446
447 struct hashmap existing_refs;
448 + int existing_refs_populated = 0;
449
450 if (rs->nr) {
451 struct refspec *fetch_refspec;
@@ -538,15 +539,18 @@ static struct ref *get_ref_map(struct remote *remote,
539
540 ref_map = ref_remove_duplicates(ref_map);
541
541 - refname_hash_init(&existing_refs);
542 - for_each_ref(add_one_refname, &existing_refs);
543 -
542 for (rm = ref_map; rm; rm = rm->next) {
543 if (rm->peer_ref) {
544 const char *refname = rm->peer_ref->name;
545 struct refname_hash_entry *peer_item;
546 unsigned int hash = strhash(refname);
547
548 + if (!existing_refs_populated) {
549 + refname_hash_init(&existing_refs);
550 + for_each_ref(add_one_refname, &existing_refs);
551 + existing_refs_populated = 1;
552 + }
553 +
554 peer_item = hashmap_get_entry_from_hash(&existing_refs,
555 hash, refname,
556 struct refname_hash_entry, ent);
@@ -556,7 +560,8 @@ static struct ref *get_ref_map(struct remote *remote,
560 }
561 }
562 }
559 - hashmap_free_entries(&existing_refs, struct refname_hash_entry, ent);
563 + if (existing_refs_populated)
564 + hashmap_free_entries(&existing_refs, struct refname_hash_entry, ent);
565
566 return ref_map;
567 }