diff options
Diffstat (limited to 'builtin')
-rw-r--r-- | builtin/index-pack.c | 31 |
1 files changed, 30 insertions, 1 deletions
diff --git a/builtin/index-pack.c b/builtin/index-pack.c index 347a92c2f1..f811d1112a 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -817,6 +817,35 @@ static void record_outgoing_link(const struct object_id *oid) oidset_insert(&outgoing_links, oid); } +static void maybe_record_name_entry(const struct name_entry *entry) +{ + /* + * Checking only trees here results in a significantly faster packfile + * indexing, but the drawback is that if the packfile to be indexed + * references a local blob only directly (that is, never through a + * local tree), that local blob is in danger of being garbage + * collected. Such a situation may arise if we push local commits, + * including one with a change to a blob in the root tree, and then the + * server incorporates them into its main branch through a "rebase" or + * "squash" merge strategy, and then we fetch the new main branch from + * the server. + * + * This situation has not been observed yet - we have only noticed + * missing commits, not missing trees or blobs. (In fact, if it were + * believed that only missing commits are problematic, one could argue + * that we should also exclude trees during the outgoing link check; + * but it is safer to include them.) + * + * Due to the rarity of the situation (it has not been observed to + * happen in real life), and because the "penalty" in such a situation + * is merely to refetch the missing blob when it's needed (and this + * happens only once - when refetched, the blob goes into a promisor + * pack, so it won't be GC-ed, the tradeoff seems worth it. + */ + if (S_ISDIR(entry->mode)) + record_outgoing_link(&entry->oid); +} + static void do_record_outgoing_links(struct object *obj) { if (obj->type == OBJ_TREE) { @@ -831,7 +860,7 @@ static void do_record_outgoing_links(struct object *obj) */ return; while (tree_entry_gently(&desc, &entry)) - record_outgoing_link(&entry.oid); + maybe_record_name_entry(&entry); } else if (obj->type == OBJ_COMMIT) { struct commit *commit = (struct commit *) obj; struct commit_list *parents = commit->parents; |