diff --git a/Documentation/RelNotes/2.53.0.adoc b/Documentation/RelNotes/2.53.0.adoc index 7d9ca507f1730b..be8df254774caa 100644 --- a/Documentation/RelNotes/2.53.0.adoc +++ b/Documentation/RelNotes/2.53.0.adoc @@ -110,6 +110,10 @@ Performance, Internal Implementation, Development Support etc. * Further preparation to upstream symbolic link support on Windows. + * Remove implicit reliance on the_repository global in the APIs + around tree objects and make it explicit which repository to work + in. + Fixes since v2.52 ----------------- @@ -280,6 +284,12 @@ Fixes since v2.52 terminating newline, which has been corrected. (merge a8227ae8d5 kt/http-backend-errors later to maint). + * "git repack --geometric" did not work with promisor packs, which + has been corrected. + + * The logic that avoids reusing MIDX files with a wrong checksum was + broken, which has been corrected. + * Other code cleanup, docfix, build fix, etc. (merge 46207a54cc qj/doc-http-bad-want-response later to maint). (merge df90eccd93 kh/doc-commit-extra-references later to maint). @@ -311,3 +321,4 @@ Fixes since v2.52 (merge 3f051fc9c9 kh/doc-patch-id later to maint). (merge 555c8464e5 je/doc-reset later to maint). (merge 220f888d7e ps/t1410-cleanup later to maint). + (merge 5814b04c02 ps/config-doc-get-urlmatch-fix later to maint). diff --git a/Documentation/git-config.adoc b/Documentation/git-config.adoc index cc054fa7e16cab..ac3b536a155c6e 100644 --- a/Documentation/git-config.adoc +++ b/Documentation/git-config.adoc @@ -332,7 +332,7 @@ recommended to migrate to the new syntax. Replaced by `git config get --all --show-names --regexp `. --get-urlmatch :: - Replaced by `git config get --all --show-names --url= `. + Replaced by `git config get --url= `. --get-color []:: Replaced by `git config get --type=color [--default=] `. diff --git a/add-interactive.c b/add-interactive.c index 68fc09547dd02e..95ec5a89f8c3d3 100644 --- a/add-interactive.c +++ b/add-interactive.c @@ -840,7 +840,7 @@ static int run_revert(struct add_i_state *s, const struct pathspec *ps, if (is_initial) oidcpy(&oid, s->r->hash_algo->empty_tree); else { - tree = parse_tree_indirect(&oid); + tree = repo_parse_tree_indirect(s->r, &oid); if (!tree) { res = error(_("Could not parse HEAD^{tree}")); goto finish_revert; diff --git a/archive.c b/archive.c index 310672b479a19f..fcd474c682ffe5 100644 --- a/archive.c +++ b/archive.c @@ -519,7 +519,7 @@ static void parse_treeish_arg(const char **argv, if (ar_args->mtime_option) archive_time = approxidate(ar_args->mtime_option); - tree = parse_tree_indirect(&oid); + tree = repo_parse_tree_indirect(the_repository, &oid); if (!tree) die(_("not a tree object: %s"), oid_to_hex(&oid)); diff --git a/bloom.c b/bloom.c index 2d7b951e5bf245..77a6fddf720912 100644 --- a/bloom.c +++ b/bloom.c @@ -354,7 +354,7 @@ static void init_truncated_large_filter(struct bloom_filter *filter, static int has_entries_with_high_bit(struct repository *r, struct tree *t) { - if (parse_tree(t)) + if (repo_parse_tree(r, t)) return 1; if (!(t->object.flags & VISITED)) { diff --git a/builtin/am.c b/builtin/am.c index 277c2e7937dcc1..b66a33d8a8899c 100644 --- a/builtin/am.c +++ b/builtin/am.c @@ -1998,7 +1998,7 @@ static int fast_forward_to(struct tree *head, struct tree *remote, int reset) struct unpack_trees_options opts; struct tree_desc t[2]; - if (parse_tree(head) || parse_tree(remote)) + if (repo_parse_tree(the_repository, head) || repo_parse_tree(the_repository, remote)) return -1; repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR); @@ -2038,7 +2038,7 @@ static int merge_tree(struct tree *tree) struct unpack_trees_options opts; struct tree_desc t[1]; - if (parse_tree(tree)) + if (repo_parse_tree(the_repository, tree)) return -1; repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR); @@ -2071,11 +2071,11 @@ static int clean_index(const struct object_id *head, const struct object_id *rem struct tree *head_tree, *remote_tree, *index_tree; struct object_id index; - head_tree = parse_tree_indirect(head); + head_tree = repo_parse_tree_indirect(the_repository, head); if (!head_tree) return error(_("Could not parse object '%s'."), oid_to_hex(head)); - remote_tree = parse_tree_indirect(remote); + remote_tree = repo_parse_tree_indirect(the_repository, remote); if (!remote_tree) return error(_("Could not parse object '%s'."), oid_to_hex(remote)); @@ -2089,7 +2089,7 @@ static int clean_index(const struct object_id *head, const struct object_id *rem 0, NULL)) return -1; - index_tree = parse_tree_indirect(&index); + index_tree = repo_parse_tree_indirect(the_repository, &index); if (!index_tree) return error(_("Could not parse object '%s'."), oid_to_hex(&index)); diff --git a/builtin/checkout.c b/builtin/checkout.c index 261699e2f5fc97..0ba4f03f2ee064 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -724,7 +724,7 @@ static int reset_tree(struct tree *tree, const struct checkout_opts *o, init_checkout_metadata(&opts.meta, info->refname, info->commit ? &info->commit->object.oid : null_oid(the_hash_algo), NULL); - if (parse_tree(tree) < 0) + if (repo_parse_tree(the_repository, tree) < 0) return 128; init_tree_desc(&tree_desc, &tree->object.oid, tree->buffer, tree->size); switch (unpack_trees(1, &tree_desc, &opts)) { @@ -803,7 +803,8 @@ static int merge_working_tree(const struct checkout_opts *opts, if (opts->new_orphan_branch && opts->orphan_from_empty_tree) { if (new_branch_info->commit) BUG("'switch --orphan' should never accept a commit as starting point"); - new_tree = parse_tree_indirect(the_hash_algo->empty_tree); + new_tree = repo_parse_tree_indirect(the_repository, + the_hash_algo->empty_tree); if (!new_tree) BUG("unable to read empty tree"); } else { @@ -841,14 +842,15 @@ static int merge_working_tree(const struct checkout_opts *opts, old_commit_oid = old_branch_info->commit ? &old_branch_info->commit->object.oid : the_hash_algo->empty_tree; - tree = parse_tree_indirect(old_commit_oid); + tree = repo_parse_tree_indirect(the_repository, + old_commit_oid); if (!tree) die(_("unable to parse commit %s"), oid_to_hex(old_commit_oid)); init_tree_desc(&trees[0], &tree->object.oid, tree->buffer, tree->size); - if (parse_tree(new_tree) < 0) + if (repo_parse_tree(the_repository, new_tree) < 0) die(NULL); tree = new_tree; init_tree_desc(&trees[1], &tree->object.oid, @@ -1278,7 +1280,7 @@ static void setup_new_branch_info_and_source_tree( new_branch_info->commit = lookup_commit_reference_gently(the_repository, rev, 1); if (!new_branch_info->commit) { /* not a commit */ - *source_tree = parse_tree_indirect(rev); + *source_tree = repo_parse_tree_indirect(the_repository, rev); if (!*source_tree) die(_("unable to read tree (%s)"), oid_to_hex(rev)); } else { diff --git a/builtin/clone.c b/builtin/clone.c index b19b302b065467..b40cee596804f5 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -680,10 +680,10 @@ static int checkout(int submodule_progress, int filter_submodules, opts.dst_index = the_repository->index; init_checkout_metadata(&opts.meta, head, &oid, NULL); - tree = parse_tree_indirect(&oid); + tree = repo_parse_tree_indirect(the_repository, &oid); if (!tree) die(_("unable to parse commit %s"), oid_to_hex(&oid)); - if (parse_tree(tree) < 0) + if (repo_parse_tree(the_repository, tree) < 0) exit(128); init_tree_desc(&t, &tree->object.oid, tree->buffer, tree->size); if (unpack_trees(1, &t, &opts) < 0) diff --git a/builtin/commit.c b/builtin/commit.c index 0243f17d53c97c..8e901fe8db7942 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -327,10 +327,11 @@ static void create_base_index(const struct commit *current_head) opts.dst_index = the_repository->index; opts.fn = oneway_merge; - tree = parse_tree_indirect(¤t_head->object.oid); + tree = repo_parse_tree_indirect(the_repository, + ¤t_head->object.oid); if (!tree) die(_("failed to unpack HEAD tree object")); - if (parse_tree(tree) < 0) + if (repo_parse_tree(the_repository, tree) < 0) exit(128); init_tree_desc(&t, &tree->object.oid, tree->buffer, tree->size); if (unpack_trees(1, &t, &opts)) diff --git a/builtin/diff-tree.c b/builtin/diff-tree.c index 49dd4d00ebf1bc..740d9a791c9c1d 100644 --- a/builtin/diff-tree.c +++ b/builtin/diff-tree.c @@ -52,7 +52,7 @@ static int stdin_diff_trees(struct tree *tree1, const char *p) if (!isspace(*p++) || parse_oid_hex(p, &oid, &p) || *p) return error("Need exactly two trees, separated by a space"); tree2 = lookup_tree(the_repository, &oid); - if (!tree2 || parse_tree(tree2)) + if (!tree2 || repo_parse_tree(the_repository, tree2)) return -1; printf("%s %s\n", oid_to_hex(&tree1->object.oid), oid_to_hex(&tree2->object.oid)); diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c index ec6940fc7c4b9c..113e4a960dc7dd 100644 --- a/builtin/ls-tree.c +++ b/builtin/ls-tree.c @@ -421,7 +421,7 @@ int cmd_ls_tree(int argc, for (i = 0; i < options.pathspec.nr; i++) options.pathspec.items[i].nowildcard_len = options.pathspec.items[i].len; options.pathspec.has_wildcard = 0; - tree = parse_tree_indirect(&oid); + tree = repo_parse_tree_indirect(the_repository, &oid); if (!tree) die("not a tree object"); /* diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c index 1c063d9a41a695..a6e6d5b555f7db 100644 --- a/builtin/merge-tree.c +++ b/builtin/merge-tree.c @@ -447,17 +447,20 @@ static int real_merge(struct merge_tree_options *o, if (repo_get_oid_treeish(the_repository, merge_base, &base_oid)) die(_("could not parse as tree '%s'"), merge_base); - base_tree = parse_tree_indirect(&base_oid); + base_tree = repo_parse_tree_indirect(the_repository, + &base_oid); if (!base_tree) die(_("unable to read tree (%s)"), oid_to_hex(&base_oid)); if (repo_get_oid_treeish(the_repository, branch1, &head_oid)) die(_("could not parse as tree '%s'"), branch1); - parent1_tree = parse_tree_indirect(&head_oid); + parent1_tree = repo_parse_tree_indirect(the_repository, + &head_oid); if (!parent1_tree) die(_("unable to read tree (%s)"), oid_to_hex(&head_oid)); if (repo_get_oid_treeish(the_repository, branch2, &merge_oid)) die(_("could not parse as tree '%s'"), branch2); - parent2_tree = parse_tree_indirect(&merge_oid); + parent2_tree = repo_parse_tree_indirect(the_repository, + &merge_oid); if (!parent2_tree) die(_("unable to read tree (%s)"), oid_to_hex(&merge_oid)); diff --git a/builtin/merge.c b/builtin/merge.c index c421a11b0b69df..50001b4c59f083 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -756,19 +756,19 @@ static int read_tree_trivial(struct object_id *common, struct object_id *head, opts.trivial_merges_only = 1; opts.merge = 1; opts.preserve_ignored = 0; /* FIXME: !overwrite_ignore */ - trees[nr_trees] = parse_tree_indirect(common); + trees[nr_trees] = repo_parse_tree_indirect(the_repository, common); if (!trees[nr_trees++]) return -1; - trees[nr_trees] = parse_tree_indirect(head); + trees[nr_trees] = repo_parse_tree_indirect(the_repository, head); if (!trees[nr_trees++]) return -1; - trees[nr_trees] = parse_tree_indirect(one); + trees[nr_trees] = repo_parse_tree_indirect(the_repository, one); if (!trees[nr_trees++]) return -1; opts.fn = threeway_merge; cache_tree_free(&the_repository->index->cache_tree); for (i = 0; i < nr_trees; i++) { - parse_tree(trees[i]); + repo_parse_tree(the_repository, trees[i]); init_tree_desc(t+i, &trees[i]->object.oid, trees[i]->buffer, trees[i]->size); } diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index 6ee31d48c94748..5846b6a293a27b 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -3863,8 +3863,11 @@ static void read_packs_list_from_stdin(struct rev_info *revs) repo_for_each_pack(the_repository, p) { const char *pack_name = pack_basename(p); - if ((item = string_list_lookup(&include_packs, pack_name))) + if ((item = string_list_lookup(&include_packs, pack_name))) { + if (exclude_promisor_objects && p->pack_promisor) + die(_("packfile %s is a promisor but --exclude-promisor-objects was given"), p->pack_name); item->util = p; + } if ((item = string_list_lookup(&exclude_packs, pack_name))) item->util = p; } @@ -3942,6 +3945,7 @@ static void read_stdin_packs(enum stdin_packs_mode mode, int rev_list_unpacked) revs.tree_objects = 1; revs.tag_objects = 1; revs.ignore_missing_links = 1; + revs.exclude_promisor_objects = exclude_promisor_objects; /* avoids adding objects in excluded packs */ ignore_packed_keep_in_core = 1; @@ -5098,9 +5102,13 @@ int cmd_pack_objects(int argc, exclude_promisor_objects_best_effort, "--exclude-promisor-objects-best-effort"); if (exclude_promisor_objects) { - use_internal_rev_list = 1; fetch_if_missing = 0; - strvec_push(&rp, "--exclude-promisor-objects"); + + /* --stdin-packs handles promisor objects separately. */ + if (!stdin_packs) { + use_internal_rev_list = 1; + strvec_push(&rp, "--exclude-promisor-objects"); + } } else if (exclude_promisor_objects_best_effort) { use_internal_rev_list = 1; fetch_if_missing = 0; diff --git a/builtin/read-tree.c b/builtin/read-tree.c index 34f7a59f38ee22..460b21e40ac914 100644 --- a/builtin/read-tree.c +++ b/builtin/read-tree.c @@ -32,7 +32,7 @@ static int list_tree(struct object_id *oid) if (nr_trees >= MAX_UNPACK_TREES) die("I cannot read more than %d trees", MAX_UNPACK_TREES); - tree = parse_tree_indirect(oid); + tree = repo_parse_tree_indirect(the_repository, oid); if (!tree) return -1; trees[nr_trees++] = tree; @@ -268,7 +268,7 @@ int cmd_read_tree(int argc, cache_tree_free(&the_repository->index->cache_tree); for (i = 0; i < nr_trees; i++) { struct tree *tree = trees[i]; - if (parse_tree(tree) < 0) + if (repo_parse_tree(the_repository, tree) < 0) return 128; init_tree_desc(t+i, &tree->object.oid, tree->buffer, tree->size); } diff --git a/builtin/repack.c b/builtin/repack.c index d9012141f699c9..f6bb04bef7264e 100644 --- a/builtin/repack.c +++ b/builtin/repack.c @@ -332,6 +332,9 @@ int cmd_repack(int argc, !(pack_everything & PACK_CRUFT)) strvec_push(&cmd.args, "--pack-loose-unreachable"); } else if (geometry.split_factor) { + pack_geometry_repack_promisors(repo, &po_args, &geometry, + &names, packtmp); + if (midx_must_contain_cruft) strvec_push(&cmd.args, "--stdin-packs"); else diff --git a/builtin/reset.c b/builtin/reset.c index ed35802af15c94..c48d9845f8425e 100644 --- a/builtin/reset.c +++ b/builtin/reset.c @@ -118,7 +118,7 @@ static int reset_index(const char *ref, const struct object_id *oid, int reset_t goto out; if (reset_type == MIXED || reset_type == HARD) { - tree = parse_tree_indirect(oid); + tree = repo_parse_tree_indirect(the_repository, oid); if (!tree) { error(_("unable to read tree (%s)"), oid_to_hex(oid)); goto out; @@ -417,7 +417,7 @@ int cmd_reset(int argc, struct tree *tree; if (repo_get_oid_treeish(the_repository, rev, &oid)) die(_("Failed to resolve '%s' as a valid tree."), rev); - tree = parse_tree_indirect(&oid); + tree = repo_parse_tree_indirect(the_repository, &oid); if (!tree) die(_("Could not parse object '%s'."), rev); oidcpy(&oid, &tree->object.oid); diff --git a/builtin/stash.c b/builtin/stash.c index 948eba06fbccb3..193e3ea47a17c8 100644 --- a/builtin/stash.c +++ b/builtin/stash.c @@ -347,8 +347,8 @@ static int reset_tree(struct object_id *i_tree, int update, int reset) memset(&opts, 0, sizeof(opts)); - tree = parse_tree_indirect(i_tree); - if (parse_tree(tree)) + tree = repo_parse_tree_indirect(the_repository, i_tree); + if (repo_parse_tree(the_repository, tree)) return -1; init_tree_desc(t, &tree->object.oid, tree->buffer, tree->size); @@ -940,8 +940,8 @@ static void diff_include_untracked(const struct stash_info *info, struct diff_op struct unpack_trees_options unpack_tree_opt = { 0 }; for (size_t i = 0; i < ARRAY_SIZE(oid); i++) { - tree[i] = parse_tree_indirect(oid[i]); - if (parse_tree(tree[i]) < 0) + tree[i] = repo_parse_tree_indirect(the_repository, oid[i]); + if (repo_parse_tree(the_repository, tree[i]) < 0) die(_("failed to parse tree")); init_tree_desc(&tree_desc[i], &tree[i]->object.oid, tree[i]->buffer, tree[i]->size); diff --git a/cache-tree.c b/cache-tree.c index 2d8947b5187840..16c3a36b48267b 100644 --- a/cache-tree.c +++ b/cache-tree.c @@ -813,7 +813,7 @@ static void prime_cache_tree_rec(struct repository *r, struct cache_tree_sub *sub; struct tree *subtree = lookup_tree(r, &entry.oid); - if (parse_tree(subtree) < 0) + if (repo_parse_tree(the_repository, subtree) < 0) exit(128); sub = cache_tree_sub(it, entry.path); sub->cache_tree = cache_tree(); diff --git a/contrib/coccinelle/the_repository.cocci b/contrib/coccinelle/the_repository.cocci index ea7fe1c8db78f3..f1129f79859cee 100644 --- a/contrib/coccinelle/the_repository.cocci +++ b/contrib/coccinelle/the_repository.cocci @@ -2,121 +2,16 @@ @@ @@ ( -// cache.h -- get_oid -+ repo_get_oid +// TODO: remove the rules below and the macros from tree.h after the +// next Git release. +- parse_tree ++ repo_parse_tree | -- get_oid_commit -+ repo_get_oid_commit +- parse_tree_gently ++ repo_parse_tree_gently | -- get_oid_committish -+ repo_get_oid_committish -| -- get_oid_tree -+ repo_get_oid_tree -| -- get_oid_treeish -+ repo_get_oid_treeish -| -- get_oid_blob -+ repo_get_oid_blob -| -- get_oid_mb -+ repo_get_oid_mb -| -- find_unique_abbrev -+ repo_find_unique_abbrev -| -- find_unique_abbrev_r -+ repo_find_unique_abbrev_r -| -- for_each_abbrev -+ repo_for_each_abbrev -| -- interpret_branch_name -+ repo_interpret_branch_name -| -- peel_to_type -+ repo_peel_to_type -// commit-reach.h -| -- get_merge_bases -+ repo_get_merge_bases -| -- get_merge_bases_many -+ repo_get_merge_bases_many -| -- get_merge_bases_many_dirty -+ repo_get_merge_bases_many_dirty -| -- in_merge_bases -+ repo_in_merge_bases -| -- in_merge_bases_many -+ repo_in_merge_bases_many -// commit.h -| -- parse_commit_internal -+ repo_parse_commit_internal -| -- parse_commit -+ repo_parse_commit -| -- get_commit_buffer -+ repo_get_commit_buffer -| -- unuse_commit_buffer -+ repo_unuse_commit_buffer -| -- logmsg_reencode -+ repo_logmsg_reencode -| -- get_commit_tree -+ repo_get_commit_tree -// diff.h -| -- diff_setup -+ repo_diff_setup -// odb.h -| -- read_object_file -+ repo_read_object_file -| -- has_object_file -+ repo_has_object_file -| -- has_object_file_with_flags -+ repo_has_object_file_with_flags -// pretty.h -| -- format_commit_message -+ repo_format_commit_message -// packfile.h -| -- approximate_object_count -+ repo_approximate_object_count -// promisor-remote.h -| -- promisor_remote_reinit -+ repo_promisor_remote_reinit -| -- promisor_remote_find -+ repo_promisor_remote_find -| -- has_promisor_remote -+ repo_has_promisor_remote -// refs.h -| -- dwim_ref -+ repo_dwim_ref -// rerere.h -| -- rerere -+ repo_rerere -// revision.h -| -- init_revisions -+ repo_init_revisions +- parse_tree_indirect ++ repo_parse_tree_indirect ) ( + the_repository, diff --git a/delta-islands.c b/delta-islands.c index 7cfebc4162b0e0..f4d2468790ce4f 100644 --- a/delta-islands.c +++ b/delta-islands.c @@ -283,7 +283,7 @@ void resolve_tree_islands(struct repository *r, root_marks = kh_value(island_marks, pos); tree = lookup_tree(r, &ent->idx.oid); - if (!tree || parse_tree(tree) < 0) + if (!tree || repo_parse_tree(r, tree) < 0) die(_("bad tree object %s"), oid_to_hex(&ent->idx.oid)); init_tree_desc(&desc, &tree->object.oid, tree->buffer, tree->size); diff --git a/diff-lib.c b/diff-lib.c index 5307390ff3db7b..506000761d4db5 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -552,7 +552,7 @@ static int diff_cache(struct rev_info *revs, struct tree_desc t; struct unpack_trees_options opts; - tree = parse_tree_indirect(tree_oid); + tree = repo_parse_tree_indirect(the_repository, tree_oid); if (!tree) return error("bad tree object %s", tree_name ? tree_name : oid_to_hex(tree_oid)); diff --git a/environment.c b/environment.c index b65b85a01f18cf..8ffbf92d507917 100644 --- a/environment.c +++ b/environment.c @@ -80,30 +80,6 @@ int core_sparse_checkout_cone; int sparse_expect_files_outside_of_patterns; int precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */ unsigned long pack_size_limit_cfg; -int max_allowed_tree_depth = -#ifdef _MSC_VER - /* - * When traversing into too-deep trees, Visual C-compiled Git seems to - * run into some internal stack overflow detection in the - * `RtlpAllocateHeap()` function that is called from within - * `git_inflate_init()`'s call tree. The following value seems to be - * low enough to avoid that by letting Git exit with an error before - * the stack overflow can occur. - */ - 512; -#elif defined(GIT_WINDOWS_NATIVE) && defined(__clang__) && defined(__aarch64__) - /* - * Similar to Visual C, it seems that on Windows/ARM64 the clang-based - * builds have a smaller stack space available. When running out of - * that stack space, a `STATUS_STACK_OVERFLOW` is produced. When the - * Git command was run from an MSYS2 Bash, this unfortunately results - * in an exit code 127. Let's prevent that by lowering the maximal - * tree depth; This value seems to be low enough. - */ - 1280; -#else - 2048; -#endif #ifndef PROTECT_HFS_DEFAULT #define PROTECT_HFS_DEFAULT 0 @@ -569,11 +545,6 @@ int git_default_core_config(const char *var, const char *value, return 0; } - if (!strcmp(var, "core.maxtreedepth")) { - max_allowed_tree_depth = git_config_int(var, value, ctx->kvi); - return 0; - } - /* Add other config variables here and to Documentation/config.adoc. */ return platform_core_config(var, value, ctx, cb); } diff --git a/environment.h b/environment.h index e61f843fdbb637..27f657af046a51 100644 --- a/environment.h +++ b/environment.h @@ -158,7 +158,6 @@ extern char *git_attributes_file; extern int zlib_compression_level; extern int pack_compression_level; extern unsigned long pack_size_limit_cfg; -extern int max_allowed_tree_depth; extern int precomposed_unicode; extern int protect_hfs; diff --git a/fsck.c b/fsck.c index 813d927d57d4b0..3afec0d0d3828c 100644 --- a/fsck.c +++ b/fsck.c @@ -360,7 +360,7 @@ static int fsck_walk_tree(struct tree *tree, void *data, struct fsck_options *op int res = 0; const char *name; - if (parse_tree(tree)) + if (repo_parse_tree(the_repository, tree)) return -1; name = fsck_get_object_name(options, &tree->object.oid); diff --git a/git-compat-util.h b/git-compat-util.h index b0673d1a450db5..bebcf9f698cd39 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -578,6 +578,30 @@ static inline bool strip_suffix(const char *str, const char *suffix, #define DEFAULT_PACKED_GIT_LIMIT \ ((1024L * 1024L) * (size_t)(sizeof(void*) >= 8 ? (32 * 1024L * 1024L) : 256)) +#ifdef _MSC_VER + /* + * When traversing into too-deep trees, Visual C-compiled Git seems to + * run into some internal stack overflow detection in the + * `RtlpAllocateHeap()` function that is called from within + * `git_inflate_init()`'s call tree. The following value seems to be + * low enough to avoid that by letting Git exit with an error before + * the stack overflow can occur. + */ +#define DEFAULT_MAX_ALLOWED_TREE_DEPTH 512 +#elif defined(GIT_WINDOWS_NATIVE) && defined(__clang__) && defined(__aarch64__) + /* + * Similar to Visual C, it seems that on Windows/ARM64 the clang-based + * builds have a smaller stack space available. When running out of + * that stack space, a `STATUS_STACK_OVERFLOW` is produced. When the + * Git command was run from an MSYS2 Bash, this unfortunately results + * in an exit code 127. Let's prevent that by lowering the maximal + * tree depth; This value seems to be low enough. + */ +#define DEFAULT_MAX_ALLOWED_TREE_DEPTH 1280 +#else +#define DEFAULT_MAX_ALLOWED_TREE_DEPTH 2048 +#endif + int git_open_cloexec(const char *name, int flags); #define git_open(name) git_open_cloexec(name, O_RDONLY) diff --git a/http-push.c b/http-push.c index 60a9b756209071..cc0f80934615ba 100644 --- a/http-push.c +++ b/http-push.c @@ -1311,7 +1311,7 @@ static struct object_list **process_tree(struct tree *tree, if (obj->flags & (UNINTERESTING | SEEN)) return p; - if (parse_tree(tree) < 0) + if (repo_parse_tree(the_repository, tree) < 0) die("bad tree object %s", oid_to_hex(&obj->oid)); obj->flags |= SEEN; diff --git a/list-objects.c b/list-objects.c index 42c17d9573910b..91b23e22f71aac 100644 --- a/list-objects.c +++ b/list-objects.c @@ -167,10 +167,10 @@ static void process_tree(struct traversal_context *ctx, !revs->include_check_obj(&tree->object, revs->include_check_data)) return; - if (ctx->depth > max_allowed_tree_depth) + if (ctx->depth > revs->repo->settings.max_allowed_tree_depth) die("exceeded maximum allowed tree depth"); - failed_parse = parse_tree_gently(tree, 1); + failed_parse = repo_parse_tree_gently(the_repository, tree, 1); if (failed_parse) { if (revs->ignore_missing_links) return; diff --git a/merge-ort.c b/merge-ort.c index 2b837a58c3a6f8..e80e4f735a60f0 100644 --- a/merge-ort.c +++ b/merge-ort.c @@ -1732,9 +1732,9 @@ static int collect_merge_info(struct merge_options *opt, info.data = opt; info.show_all_errors = 1; - if (parse_tree(merge_base) < 0 || - parse_tree(side1) < 0 || - parse_tree(side2) < 0) + if (repo_parse_tree(the_repository, merge_base) < 0 || + repo_parse_tree(the_repository, side1) < 0 || + repo_parse_tree(the_repository, side2) < 0) return -1; init_tree_desc(t + 0, &merge_base->object.oid, merge_base->buffer, merge_base->size); @@ -4619,10 +4619,10 @@ static int checkout(struct merge_options *opt, unpack_opts.verbose_update = (opt->verbosity > 2); unpack_opts.fn = twoway_merge; unpack_opts.preserve_ignored = 0; /* FIXME: !opts->overwrite_ignore */ - if (parse_tree(prev) < 0) + if (repo_parse_tree(the_repository, prev) < 0) return -1; init_tree_desc(&trees[0], &prev->object.oid, prev->buffer, prev->size); - if (parse_tree(next) < 0) + if (repo_parse_tree(the_repository, next) < 0) return -1; init_tree_desc(&trees[1], &next->object.oid, next->buffer, next->size); @@ -5280,7 +5280,8 @@ static void merge_ort_nonrecursive_internal(struct merge_options *opt, if (result->clean >= 0) { if (!opt->mergeability_only) { - result->tree = parse_tree_indirect(&working_tree_oid); + result->tree = repo_parse_tree_indirect(the_repository, + &working_tree_oid); if (!result->tree) die(_("unable to read tree (%s)"), oid_to_hex(&working_tree_oid)); diff --git a/merge.c b/merge.c index 5ecaf508e4cb98..0f5e823e63ed5f 100644 --- a/merge.c +++ b/merge.c @@ -68,18 +68,18 @@ int checkout_fast_forward(struct repository *r, memset(&trees, 0, sizeof(trees)); memset(&t, 0, sizeof(t)); - trees[nr_trees] = parse_tree_indirect(head); + trees[nr_trees] = repo_parse_tree_indirect(the_repository, head); if (!trees[nr_trees++]) { rollback_lock_file(&lock_file); return -1; } - trees[nr_trees] = parse_tree_indirect(remote); + trees[nr_trees] = repo_parse_tree_indirect(the_repository, remote); if (!trees[nr_trees++]) { rollback_lock_file(&lock_file); return -1; } for (i = 0; i < nr_trees; i++) { - if (parse_tree(trees[i]) < 0) { + if (repo_parse_tree(the_repository, trees[i]) < 0) { rollback_lock_file(&lock_file); return -1; } diff --git a/midx-write.c b/midx-write.c index 87b97c70872271..6485cb67068553 100644 --- a/midx-write.c +++ b/midx-write.c @@ -1011,6 +1011,20 @@ static bool midx_needs_update(struct multi_pack_index *midx, struct write_midx_c struct strbuf buf = STRBUF_INIT; bool needed = true; + /* + * Ensure that we have a valid checksum before consulting the + * exisiting MIDX in order to determine if we can avoid an + * update. + * + * This is necessary because the given MIDX is loaded directly + * from the object store (because we still compare our proposed + * update to any on-disk MIDX regardless of whether or not we + * have assigned "ctx.m") and is thus not guaranteed to have a + * valid checksum. + */ + if (!midx_checksum_valid(midx)) + goto out; + /* * Ignore incremental updates for now. The assumption is that any * incremental update would be either empty (in which case we will bail diff --git a/pack-bitmap-write.c b/pack-bitmap-write.c index bf73ce5710abcc..625fa92b2f4101 100644 --- a/pack-bitmap-write.c +++ b/pack-bitmap-write.c @@ -474,7 +474,7 @@ static int fill_bitmap_tree(struct bitmap_writer *writer, return 0; bitmap_set(bitmap, pos); - if (parse_tree(tree) < 0) + if (repo_parse_tree(writer->repo, tree) < 0) die("unable to load tree object %s", oid_to_hex(&tree->object.oid)); init_tree_desc(&desc, &tree->object.oid, tree->buffer, tree->size); diff --git a/path-walk.c b/path-walk.c index f1ceed99e94ca9..364e4cfa19b2e4 100644 --- a/path-walk.c +++ b/path-walk.c @@ -137,7 +137,7 @@ static int add_tree_entries(struct path_walk_context *ctx, error(_("failed to walk children of tree %s: not found"), oid_to_hex(oid)); return -1; - } else if (parse_tree_gently(tree, 1)) { + } else if (repo_parse_tree_gently(ctx->repo, tree, 1)) { error("bad tree object %s", oid_to_hex(oid)); return -1; } diff --git a/read-cache.c b/read-cache.c index 990d4ead0d8ae4..e9c1b23e48437a 100644 --- a/read-cache.c +++ b/read-cache.c @@ -3807,7 +3807,7 @@ void overlay_tree_on_index(struct index_state *istate, if (repo_get_oid(the_repository, tree_name, &oid)) die("tree-ish %s not found.", tree_name); - tree = parse_tree_indirect(&oid); + tree = repo_parse_tree_indirect(the_repository, &oid); if (!tree) die("bad tree-ish %s", tree_name); diff --git a/repack-geometry.c b/repack-geometry.c index b3e32cd07ec119..7cebd0cb45f0ea 100644 --- a/repack-geometry.c +++ b/repack-geometry.c @@ -66,45 +66,54 @@ void pack_geometry_init(struct pack_geometry *geometry, if (p->is_cruft) continue; - ALLOC_GROW(geometry->pack, - geometry->pack_nr + 1, - geometry->pack_alloc); - - geometry->pack[geometry->pack_nr] = p; - geometry->pack_nr++; + if (p->pack_promisor) { + ALLOC_GROW(geometry->promisor_pack, + geometry->promisor_pack_nr + 1, + geometry->promisor_pack_alloc); + + geometry->promisor_pack[geometry->promisor_pack_nr] = p; + geometry->promisor_pack_nr++; + } else { + ALLOC_GROW(geometry->pack, + geometry->pack_nr + 1, + geometry->pack_alloc); + + geometry->pack[geometry->pack_nr] = p; + geometry->pack_nr++; + } } QSORT(geometry->pack, geometry->pack_nr, pack_geometry_cmp); + QSORT(geometry->promisor_pack, geometry->promisor_pack_nr, pack_geometry_cmp); strbuf_release(&buf); } -void pack_geometry_split(struct pack_geometry *geometry) +static uint32_t compute_pack_geometry_split(struct packed_git **pack, size_t pack_nr, + int split_factor) { uint32_t i; uint32_t split; off_t total_size = 0; - if (!geometry->pack_nr) { - geometry->split = geometry->pack_nr; - return; - } + if (!pack_nr) + return 0; /* * First, count the number of packs (in descending order of size) which * already form a geometric progression. */ - for (i = geometry->pack_nr - 1; i > 0; i--) { - struct packed_git *ours = geometry->pack[i]; - struct packed_git *prev = geometry->pack[i - 1]; + for (i = pack_nr - 1; i > 0; i--) { + struct packed_git *ours = pack[i]; + struct packed_git *prev = pack[i - 1]; - if (unsigned_mult_overflows(geometry->split_factor, + if (unsigned_mult_overflows(split_factor, pack_geometry_weight(prev))) die(_("pack %s too large to consider in geometric " "progression"), prev->pack_name); if (pack_geometry_weight(ours) < - geometry->split_factor * pack_geometry_weight(prev)) + split_factor * pack_geometry_weight(prev)) break; } @@ -130,21 +139,19 @@ void pack_geometry_split(struct pack_geometry *geometry) * the geometric progression. */ for (i = 0; i < split; i++) { - struct packed_git *p = geometry->pack[i]; + struct packed_git *p = pack[i]; if (unsigned_add_overflows(total_size, pack_geometry_weight(p))) die(_("pack %s too large to roll up"), p->pack_name); total_size += pack_geometry_weight(p); } - for (i = split; i < geometry->pack_nr; i++) { - struct packed_git *ours = geometry->pack[i]; + for (i = split; i < pack_nr; i++) { + struct packed_git *ours = pack[i]; - if (unsigned_mult_overflows(geometry->split_factor, - total_size)) + if (unsigned_mult_overflows(split_factor, total_size)) die(_("pack %s too large to roll up"), ours->pack_name); - if (pack_geometry_weight(ours) < - geometry->split_factor * total_size) { + if (pack_geometry_weight(ours) < split_factor * total_size) { if (unsigned_add_overflows(total_size, pack_geometry_weight(ours))) die(_("pack %s too large to roll up"), @@ -156,7 +163,16 @@ void pack_geometry_split(struct pack_geometry *geometry) break; } - geometry->split = split; + return split; +} + +void pack_geometry_split(struct pack_geometry *geometry) +{ + geometry->split = compute_pack_geometry_split(geometry->pack, geometry->pack_nr, + geometry->split_factor); + geometry->promisor_split = compute_pack_geometry_split(geometry->promisor_pack, + geometry->promisor_pack_nr, + geometry->split_factor); } struct packed_git *pack_geometry_preferred_pack(struct pack_geometry *geometry) @@ -194,17 +210,18 @@ struct packed_git *pack_geometry_preferred_pack(struct pack_geometry *geometry) return NULL; } -void pack_geometry_remove_redundant(struct pack_geometry *geometry, - struct string_list *names, - struct existing_packs *existing, - const char *packdir) +static void remove_redundant_packs(struct packed_git **pack, + uint32_t pack_nr, + struct string_list *names, + struct existing_packs *existing, + const char *packdir) { const struct git_hash_algo *algop = existing->repo->hash_algo; struct strbuf buf = STRBUF_INIT; uint32_t i; - for (i = 0; i < geometry->split; i++) { - struct packed_git *p = geometry->pack[i]; + for (i = 0; i < pack_nr; i++) { + struct packed_git *p = pack[i]; if (string_list_has_string(names, hash_to_hex_algop(p->hash, algop))) continue; @@ -223,10 +240,22 @@ void pack_geometry_remove_redundant(struct pack_geometry *geometry, strbuf_release(&buf); } +void pack_geometry_remove_redundant(struct pack_geometry *geometry, + struct string_list *names, + struct existing_packs *existing, + const char *packdir) +{ + remove_redundant_packs(geometry->pack, geometry->split, + names, existing, packdir); + remove_redundant_packs(geometry->promisor_pack, geometry->promisor_split, + names, existing, packdir); +} + void pack_geometry_release(struct pack_geometry *geometry) { if (!geometry) return; free(geometry->pack); + free(geometry->promisor_pack); } diff --git a/repack-promisor.c b/repack-promisor.c index ee6e0669f65602..73af57bce31376 100644 --- a/repack-promisor.c +++ b/repack-promisor.c @@ -34,39 +34,17 @@ static int write_oid(const struct object_id *oid, return 0; } -void repack_promisor_objects(struct repository *repo, - const struct pack_objects_args *args, - struct string_list *names, const char *packtmp) +static void finish_repacking_promisor_objects(struct repository *repo, + struct child_process *cmd, + struct string_list *names, + const char *packtmp) { - struct write_oid_context ctx; - struct child_process cmd = CHILD_PROCESS_INIT; - FILE *out; struct strbuf line = STRBUF_INIT; + FILE *out; - prepare_pack_objects(&cmd, args, packtmp); - cmd.in = -1; - - /* - * NEEDSWORK: Giving pack-objects only the OIDs without any ordering - * hints may result in suboptimal deltas in the resulting pack. See if - * the OIDs can be sent with fake paths such that pack-objects can use a - * {type -> existing pack order} ordering when computing deltas instead - * of a {type -> size} ordering, which may produce better deltas. - */ - ctx.cmd = &cmd; - ctx.algop = repo->hash_algo; - for_each_packed_object(repo, write_oid, &ctx, - FOR_EACH_OBJECT_PROMISOR_ONLY); - - if (cmd.in == -1) { - /* No packed objects; cmd was never started */ - child_process_clear(&cmd); - return; - } - - close(cmd.in); + close(cmd->in); - out = xfdopen(cmd.out, "r"); + out = xfdopen(cmd->out, "r"); while (strbuf_getline_lf(&line, out) != EOF) { struct string_list_item *item; char *promisor_name; @@ -96,7 +74,66 @@ void repack_promisor_objects(struct repository *repo, } fclose(out); - if (finish_command(&cmd)) + if (finish_command(cmd)) die(_("could not finish pack-objects to repack promisor objects")); strbuf_release(&line); } + +void repack_promisor_objects(struct repository *repo, + const struct pack_objects_args *args, + struct string_list *names, const char *packtmp) +{ + struct write_oid_context ctx; + struct child_process cmd = CHILD_PROCESS_INIT; + + prepare_pack_objects(&cmd, args, packtmp); + cmd.in = -1; + + /* + * NEEDSWORK: Giving pack-objects only the OIDs without any ordering + * hints may result in suboptimal deltas in the resulting pack. See if + * the OIDs can be sent with fake paths such that pack-objects can use a + * {type -> existing pack order} ordering when computing deltas instead + * of a {type -> size} ordering, which may produce better deltas. + */ + ctx.cmd = &cmd; + ctx.algop = repo->hash_algo; + for_each_packed_object(repo, write_oid, &ctx, + FOR_EACH_OBJECT_PROMISOR_ONLY); + + if (cmd.in == -1) { + /* No packed objects; cmd was never started */ + child_process_clear(&cmd); + return; + } + + finish_repacking_promisor_objects(repo, &cmd, names, packtmp); +} + +void pack_geometry_repack_promisors(struct repository *repo, + const struct pack_objects_args *args, + const struct pack_geometry *geometry, + struct string_list *names, + const char *packtmp) +{ + struct child_process cmd = CHILD_PROCESS_INIT; + FILE *in; + + if (!geometry->promisor_split) + return; + + prepare_pack_objects(&cmd, args, packtmp); + strvec_push(&cmd.args, "--stdin-packs"); + cmd.in = -1; + if (start_command(&cmd)) + die(_("could not start pack-objects to repack promisor packs")); + + in = xfdopen(cmd.in, "w"); + for (size_t i = 0; i < geometry->promisor_split; i++) + fprintf(in, "%s\n", pack_basename(geometry->promisor_pack[i])); + for (size_t i = geometry->promisor_split; i < geometry->promisor_pack_nr; i++) + fprintf(in, "^%s\n", pack_basename(geometry->promisor_pack[i])); + fclose(in); + + finish_repacking_promisor_objects(repo, &cmd, names, packtmp); +} diff --git a/repack.h b/repack.h index 3a688a12eeb7aa..bc9f2e1a5de984 100644 --- a/repack.h +++ b/repack.h @@ -103,9 +103,19 @@ struct pack_geometry { uint32_t pack_nr, pack_alloc; uint32_t split; + struct packed_git **promisor_pack; + uint32_t promisor_pack_nr, promisor_pack_alloc; + uint32_t promisor_split; + int split_factor; }; +void pack_geometry_repack_promisors(struct repository *repo, + const struct pack_objects_args *args, + const struct pack_geometry *geometry, + struct string_list *names, + const char *packtmp); + void pack_geometry_init(struct pack_geometry *geometry, struct existing_packs *existing, const struct pack_objects_args *args); diff --git a/repo-settings.c b/repo-settings.c index 195c24e9c07606..208e09ff17fcee 100644 --- a/repo-settings.c +++ b/repo-settings.c @@ -100,6 +100,9 @@ void prepare_repo_settings(struct repository *r) */ if (!repo_config_get_int(r, "index.version", &value)) r->settings.index_version = value; + repo_cfg_int(r, "core.maxtreedepth", + &r->settings.max_allowed_tree_depth, + DEFAULT_MAX_ALLOWED_TREE_DEPTH); if (!repo_config_get_string_tmp(r, "core.untrackedcache", &strval)) { int v = git_parse_maybe_bool(strval); diff --git a/repo-settings.h b/repo-settings.h index d4778855614497..cad9c3f0cc15f3 100644 --- a/repo-settings.h +++ b/repo-settings.h @@ -67,6 +67,8 @@ struct repo_settings { size_t packed_git_limit; unsigned long big_file_threshold; + int max_allowed_tree_depth; + char *hooks_path; }; #define REPO_SETTINGS_INIT { \ @@ -78,6 +80,7 @@ struct repo_settings { .delta_base_cache_limit = DEFAULT_DELTA_BASE_CACHE_LIMIT, \ .packed_git_window_size = DEFAULT_PACKED_GIT_WINDOW_SIZE, \ .packed_git_limit = DEFAULT_PACKED_GIT_LIMIT, \ + .max_allowed_tree_depth = DEFAULT_MAX_ALLOWED_TREE_DEPTH, \ } void prepare_repo_settings(struct repository *r); diff --git a/reset.c b/reset.c index bb590271811ec2..46e30e639458c5 100644 --- a/reset.c +++ b/reset.c @@ -163,7 +163,7 @@ int reset_head(struct repository *r, const struct reset_head_opts *opts) goto leave_reset_head; } - tree = parse_tree_indirect(oid); + tree = repo_parse_tree_indirect(the_repository, oid); if (!tree) { ret = error(_("unable to read tree (%s)"), oid_to_hex(oid)); goto leave_reset_head; diff --git a/revision.c b/revision.c index b65a76377062cd..9b131670f79b96 100644 --- a/revision.c +++ b/revision.c @@ -72,7 +72,7 @@ static void mark_tree_contents_uninteresting(struct repository *r, struct tree_desc desc; struct name_entry entry; - if (parse_tree_gently(tree, 1) < 0) + if (repo_parse_tree_gently(the_repository, tree, 1) < 0) return; init_tree_desc(&desc, &tree->object.oid, tree->buffer, tree->size); @@ -179,7 +179,7 @@ static void add_children_by_path(struct repository *r, if (!tree) return; - if (parse_tree_gently(tree, 1) < 0) + if (repo_parse_tree_gently(the_repository, tree, 1) < 0) return; init_tree_desc(&desc, &tree->object.oid, tree->buffer, tree->size); diff --git a/sequencer.c b/sequencer.c index 5476d39ba9b097..1f492f8460e237 100644 --- a/sequencer.c +++ b/sequencer.c @@ -767,7 +767,7 @@ static int do_recursive_merge(struct repository *r, o.buffer_output = 2; o.show_rename_progress = 1; - head_tree = parse_tree_indirect(head); + head_tree = repo_parse_tree_indirect(the_repository, head); if (!head_tree) return error(_("unable to read tree (%s)"), oid_to_hex(head)); next_tree = next ? repo_get_commit_tree(r, next) : empty_tree(r); @@ -4044,7 +4044,7 @@ static int do_reset(struct repository *r, goto cleanup; } - tree = parse_tree_indirect(&oid); + tree = repo_parse_tree_indirect(the_repository, &oid); if (!tree) return error(_("unable to read tree (%s)"), oid_to_hex(&oid)); prime_cache_tree(r, r->index, tree); diff --git a/t/helper/test-cache-tree.c b/t/helper/test-cache-tree.c index 3ae45cec3be639..ff61d0ca7e2fe3 100644 --- a/t/helper/test-cache-tree.c +++ b/t/helper/test-cache-tree.c @@ -41,7 +41,7 @@ int cmd__cache_tree(int argc, const char **argv) die(_("unable to read index file")); oidcpy(&oid, &the_repository->index->cache_tree->oid); - tree = parse_tree_indirect(&oid); + tree = repo_parse_tree_indirect(the_repository, &oid); if (!tree) die(_("not a tree object: %s"), oid_to_hex(&oid)); diff --git a/t/helper/test-match-trees.c b/t/helper/test-match-trees.c index e0e2048320d583..2ed064b9716ac8 100644 --- a/t/helper/test-match-trees.c +++ b/t/helper/test-match-trees.c @@ -19,10 +19,10 @@ int cmd__match_trees(int ac UNUSED, const char **av) die("cannot parse %s as an object name", av[1]); if (repo_get_oid(the_repository, av[2], &hash2)) die("cannot parse %s as an object name", av[2]); - one = parse_tree_indirect(&hash1); + one = repo_parse_tree_indirect(the_repository, &hash1); if (!one) die("not a tree-ish %s", av[1]); - two = parse_tree_indirect(&hash2); + two = repo_parse_tree_indirect(the_repository, &hash2); if (!two) die("not a tree-ish %s", av[2]); diff --git a/t/t5319-multi-pack-index.sh b/t/t5319-multi-pack-index.sh index 794f8b5ab4e136..faae98c7e76a20 100755 --- a/t/t5319-multi-pack-index.sh +++ b/t/t5319-multi-pack-index.sh @@ -415,8 +415,6 @@ test_expect_success 'up-to-date multi-pack-index is retained' ' ) ' -test_done - test_expect_success 'verify multi-pack-index success' ' git multi-pack-index verify --object-dir=$objdir ' diff --git a/t/t5331-pack-objects-stdin.sh b/t/t5331-pack-objects-stdin.sh index 4a8df5a389d29f..cd949025b982a4 100755 --- a/t/t5331-pack-objects-stdin.sh +++ b/t/t5331-pack-objects-stdin.sh @@ -319,6 +319,45 @@ test_expect_success '--stdin-packs=follow walks into unknown packs' ' ) ' +test_expect_success '--stdin-packs with promisors' ' + test_when_finished "rm -fr repo" && + git init repo && + ( + cd repo && + git config set maintenance.auto false && + git remote add promisor garbage && + git config set remote.promisor.promisor true && + + for c in A B C D + do + echo "$c" >file && + git add file && + git commit --message "$c" && + git tag "$c" || return 1 + done && + + A="$(echo A | git pack-objects --revs $packdir/pack)" && + B="$(echo A..B | git pack-objects --revs $packdir/pack --filter=blob:none)" && + C="$(echo B..C | git pack-objects --revs $packdir/pack)" && + D="$(echo C..D | git pack-objects --revs $packdir/pack)" && + touch $packdir/pack-$B.promisor && + + test_must_fail git pack-objects --stdin-packs --exclude-promisor-objects pack- 2>err <<-EOF && + pack-$B.pack + EOF + test_grep "is a promisor but --exclude-promisor-objects was given" err && + + PACK=$(git pack-objects --stdin-packs=follow --exclude-promisor-objects $packdir/pack <<-EOF + pack-$D.pack + EOF + ) && + objects_in_packs $C $D >expect && + objects_in_packs $PACK >actual && + test_cmp expect actual && + rm -f $packdir/pack-$PACK.* + ) +' + stdin_packs__follow_with_only () { rm -fr stdin_packs__follow_with_only && git init stdin_packs__follow_with_only && diff --git a/t/t7703-repack-geometric.sh b/t/t7703-repack-geometric.sh index 98806cdb6fe9b7..04d5d8fc33e9e5 100755 --- a/t/t7703-repack-geometric.sh +++ b/t/t7703-repack-geometric.sh @@ -480,4 +480,65 @@ test_expect_success '--geometric -l disables writing bitmaps with non-local pack test_path_is_file member/.git/objects/pack/multi-pack-index-*.bitmap ' +write_packfile () { + NR="$1" + PREFIX="$2" + + printf "blob\ndata <objects-expect && + + ls .git/objects/pack/*.pack >packs-before && + test_line_count = 8 packs-before && + git repack --geometric=2 -d && + ls .git/objects/pack/*.pack >packs-after && + test_line_count = 5 packs-after && + test_grep ! "$NORMAL_A" packs-after && + test_grep ! "$NORMAL_B" packs-after && + test_grep "$NORMAL_C" packs-after && + test_grep ! "$PROMISOR_A" packs-after && + test_grep ! "$PROMISOR_B" packs-after && + test_grep ! "$PROMISOR_C" packs-after && + test_grep "$PROMISOR_D" packs-after && + test_grep "$PROMISOR_E" packs-after && + + ls .git/objects/pack/*.promisor >promisors && + test_line_count = 3 promisors && + + git cat-file --batch-all-objects --batch-check="%(objectname)" >objects-actual && + test_cmp objects-expect objects-actual + ) +' + test_done diff --git a/tree-diff.c b/tree-diff.c index 5988148b602536..631ea868124256 100644 --- a/tree-diff.c +++ b/tree-diff.c @@ -439,7 +439,7 @@ static void ll_diff_tree_paths( void *ttree, **tptree; int i; - if (depth > max_allowed_tree_depth) + if (depth > opt->repo->settings.max_allowed_tree_depth) die("exceeded maximum allowed tree depth"); FAST_ARRAY_ALLOC(tp, nparent); diff --git a/tree-walk.c b/tree-walk.c index e449a1320e55a6..7e1b956f278164 100644 --- a/tree-walk.c +++ b/tree-walk.c @@ -12,6 +12,7 @@ #include "pathspec.h" #include "json-writer.h" #include "environment.h" +#include "read-cache-ll.h" static int decode_tree_entry(struct tree_desc *desc, const char *buf, unsigned long size, struct strbuf *err) { @@ -441,8 +442,9 @@ int traverse_trees(struct index_state *istate, struct strbuf base = STRBUF_INIT; int interesting = 1; char *traverse_path; + struct repository *r = istate ? istate->repo : the_repository; - if (traverse_trees_cur_depth > max_allowed_tree_depth) + if (traverse_trees_cur_depth > r->settings.max_allowed_tree_depth) return error("exceeded maximum allowed tree depth"); traverse_trees_count++; diff --git a/tree.c b/tree.c index 1ef743d90f4bad..d703ab97c8303a 100644 --- a/tree.c +++ b/tree.c @@ -1,5 +1,3 @@ -#define USE_THE_REPOSITORY_VARIABLE - #include "git-compat-util.h" #include "hex.h" #include "tree.h" @@ -25,10 +23,10 @@ int read_tree_at(struct repository *r, int len, oldlen = base->len; enum interesting retval = entry_not_interesting; - if (depth > max_allowed_tree_depth) + if (depth > r->settings.max_allowed_tree_depth) return error("exceeded maximum allowed tree depth"); - if (parse_tree(tree)) + if (repo_parse_tree(r, tree)) return -1; init_tree_desc(&desc, &tree->object.oid, tree->buffer, tree->size); @@ -185,7 +183,8 @@ int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size) return 0; } -int parse_tree_gently(struct tree *item, int quiet_on_missing) +int repo_parse_tree_gently(struct repository *r, struct tree *item, + int quiet_on_missing) { enum object_type type; void *buffer; @@ -193,8 +192,7 @@ int parse_tree_gently(struct tree *item, int quiet_on_missing) if (item->object.parsed) return 0; - buffer = odb_read_object(the_repository->objects, &item->object.oid, - &type, &size); + buffer = odb_read_object(r->objects, &item->object.oid, &type, &size); if (!buffer) return quiet_on_missing ? -1 : error("Could not read %s", @@ -214,9 +212,9 @@ void free_tree_buffer(struct tree *tree) tree->object.parsed = 0; } -struct tree *parse_tree_indirect(const struct object_id *oid) +struct tree *repo_parse_tree_indirect(struct repository *r, + const struct object_id *oid) { - struct repository *r = the_repository; struct object *obj = parse_object(r, oid); return (struct tree *)repo_peel_to_type(r, NULL, 0, obj, OBJ_TREE); } diff --git a/tree.h b/tree.h index cc6ddf51b3273c..677382eed86c59 100644 --- a/tree.h +++ b/tree.h @@ -19,15 +19,20 @@ struct tree *lookup_tree(struct repository *r, const struct object_id *oid); int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size); -int parse_tree_gently(struct tree *tree, int quiet_on_missing); -static inline int parse_tree(struct tree *tree) +#define parse_tree_gently(t, q) repo_parse_tree_gently(the_repository, t, q) +int repo_parse_tree_gently(struct repository *r, struct tree *item, + int quiet_on_missing); +#define parse_tree(t) repo_parse_tree(the_repository, t) +static inline int repo_parse_tree(struct repository *r, struct tree *item) { - return parse_tree_gently(tree, 0); + return repo_parse_tree_gently(r, item, 0); } void free_tree_buffer(struct tree *tree); /* Parses and returns the tree in the given ent, chasing tags and commits. */ -struct tree *parse_tree_indirect(const struct object_id *oid); +#define parse_tree_indirect(o) repo_parse_tree_indirect(the_repository, o) +struct tree *repo_parse_tree_indirect(struct repository *r, + const struct object_id *oid); /* * Functions for comparing pathnames diff --git a/walker.c b/walker.c index 2891563b03620b..91332539d3a286 100644 --- a/walker.c +++ b/walker.c @@ -45,7 +45,7 @@ static int process_tree(struct walker *walker, struct tree *tree) struct tree_desc desc; struct name_entry entry; - if (parse_tree(tree)) + if (repo_parse_tree(the_repository, tree)) return -1; init_tree_desc(&desc, &tree->object.oid, tree->buffer, tree->size);