diff options
Diffstat (limited to 'cache-tree.c')
-rw-r--r-- | cache-tree.c | 54 |
1 files changed, 47 insertions, 7 deletions
diff --git a/cache-tree.c b/cache-tree.c index 79d168192d..6752f69d51 100644 --- a/cache-tree.c +++ b/cache-tree.c @@ -432,15 +432,15 @@ static int update_one(struct cache_tree *it, if (repair) { struct object_id oid; hash_object_file(the_hash_algo, buffer.buf, buffer.len, - tree_type, &oid); + OBJ_TREE, &oid); if (has_object_file_with_flags(&oid, OBJECT_INFO_SKIP_FETCH_OBJECT)) oidcpy(&it->oid, &oid); else to_invalidate = 1; } else if (dryrun) { hash_object_file(the_hash_algo, buffer.buf, buffer.len, - tree_type, &it->oid); - } else if (write_object_file_flags(buffer.buf, buffer.len, tree_type, + OBJ_TREE, &it->oid); + } else if (write_object_file_flags(buffer.buf, buffer.len, OBJ_TREE, &it->oid, flags & WRITE_TREE_SILENT ? HASH_SILENT : 0)) { strbuf_release(&buffer); @@ -741,15 +741,26 @@ out: return ret; } +static void prime_cache_tree_sparse_dir(struct cache_tree *it, + struct tree *tree) +{ + + oidcpy(&it->oid, &tree->object.oid); + it->entry_count = 1; +} + static void prime_cache_tree_rec(struct repository *r, struct cache_tree *it, - struct tree *tree) + struct tree *tree, + struct strbuf *tree_path) { struct tree_desc desc; struct name_entry entry; int cnt; + int base_path_len = tree_path->len; oidcpy(&it->oid, &tree->object.oid); + init_tree_desc(&desc, tree->buffer, tree->size); cnt = 0; while (tree_entry(&desc, &entry)) { @@ -758,14 +769,40 @@ static void prime_cache_tree_rec(struct repository *r, else { struct cache_tree_sub *sub; struct tree *subtree = lookup_tree(r, &entry.oid); + if (!subtree->object.parsed) parse_tree(subtree); sub = cache_tree_sub(it, entry.path); sub->cache_tree = cache_tree(); - prime_cache_tree_rec(r, sub->cache_tree, subtree); + + /* + * Recursively-constructed subtree path is only needed when working + * in a sparse index (where it's used to determine whether the + * subtree is a sparse directory in the index). + */ + if (r->index->sparse_index) { + strbuf_setlen(tree_path, base_path_len); + strbuf_grow(tree_path, base_path_len + entry.pathlen + 1); + strbuf_add(tree_path, entry.path, entry.pathlen); + strbuf_addch(tree_path, '/'); + } + + /* + * If a sparse index is in use, the directory being processed may be + * sparse. To confirm that, we can check whether an entry with that + * exact name exists in the index. If it does, the created subtree + * should be sparse. Otherwise, cache tree expansion should continue + * as normal. + */ + if (r->index->sparse_index && + index_entry_exists(r->index, tree_path->buf, tree_path->len)) + prime_cache_tree_sparse_dir(sub->cache_tree, subtree); + else + prime_cache_tree_rec(r, sub->cache_tree, subtree, tree_path); cnt += sub->cache_tree->entry_count; } } + it->entry_count = cnt; } @@ -773,11 +810,14 @@ void prime_cache_tree(struct repository *r, struct index_state *istate, struct tree *tree) { + struct strbuf tree_path = STRBUF_INIT; + trace2_region_enter("cache-tree", "prime_cache_tree", the_repository); cache_tree_free(&istate->cache_tree); istate->cache_tree = cache_tree(); - prime_cache_tree_rec(r, istate->cache_tree, tree); + prime_cache_tree_rec(r, istate->cache_tree, tree, &tree_path); + strbuf_release(&tree_path); istate->cache_changed |= CACHE_TREE_CHANGED; trace2_region_leave("cache-tree", "prime_cache_tree", the_repository); } @@ -908,7 +948,7 @@ static int verify_one(struct repository *r, strbuf_addf(&tree_buf, "%o %.*s%c", mode, entlen, name, '\0'); strbuf_add(&tree_buf, oid->hash, r->hash_algo->rawsz); } - hash_object_file(r->hash_algo, tree_buf.buf, tree_buf.len, tree_type, + hash_object_file(r->hash_algo, tree_buf.buf, tree_buf.len, OBJ_TREE, &new_oid); if (!oideq(&new_oid, &it->oid)) BUG("cache-tree for path %.*s does not match. " |