From 5489d58942012e1a3ed8400f69aecfb628bccfba Mon Sep 17 00:00:00 2001 From: Derrick Stolee Date: Mon, 30 Sep 2024 16:33:58 -0400 Subject: [PATCH 1/6] sparse-index: add ensure_full_index_with_reason() It is sometimes difficult to support users who are hitting issues with sparse index expansion because it is unclear why the index needs to expand from logs alone. It is too invasive to set up a debugging scenario on the user's machine, so let's improve the logging. Create a new ensure_full_index_with_reason() method that takes a formatting string and parameters. If the index is not fully expanded, then apply the formatting logic to create the logged string and log it before calling ensure_full_index(). This should assist with discovering why an index is expanded from trace2 logs alone. Signed-off-by: Derrick Stolee --- sparse-index.c | 18 ++++++++++++++++++ sparse-index.h | 8 ++++++++ 2 files changed, 26 insertions(+) diff --git a/sparse-index.c b/sparse-index.c index fe369df3e53f76..8c30c51cf2caa6 100644 --- a/sparse-index.c +++ b/sparse-index.c @@ -456,6 +456,24 @@ void ensure_full_index(struct index_state *istate) expand_index(istate, NULL); } +void ensure_full_index_with_reason(struct index_state *istate, + const char *fmt, ...) +{ + va_list ap; + struct strbuf why = STRBUF_INIT; + if (!istate) + BUG("ensure_full_index_with_reason() must get an index!"); + if (istate->sparse_index == INDEX_EXPANDED) + return; + + va_start(ap, fmt); + strbuf_vaddf(&why, fmt, ap); + trace2_data_string("sparse-index", istate->repo, "expansion-reason", why.buf); + va_end(ap); + strbuf_release(&why); + ensure_full_index(istate); +} + void ensure_correct_sparsity(struct index_state *istate) { /* diff --git a/sparse-index.h b/sparse-index.h index a16f3e67d75913..b8d51b091196a0 100644 --- a/sparse-index.h +++ b/sparse-index.h @@ -39,4 +39,12 @@ void expand_index(struct index_state *istate, struct pattern_list *pl); void ensure_full_index(struct index_state *istate); +/** + * If there is a clear reason why the sparse index is being expanded, then + * trace the information for why the expansion is occurring. + */ +void ensure_full_index_with_reason(struct index_state *istate, + const char *fmt, + ...); + #endif From bee6d26b83d01692e9fa98fff894813b2eefd283 Mon Sep 17 00:00:00 2001 From: Derrick Stolee Date: Mon, 30 Sep 2024 16:57:43 -0400 Subject: [PATCH 2/6] treewide: add reasons for expanding index These locations that previously called ensure_full_index() are now updated to call the ..._with_reason() varation using fixed strings that should be enough to identify the reason for the expansion. This will help users use tracing to determine why the index is expanding in their scenarios. Signed-off-by: Derrick Stolee --- builtin/checkout-index.c | 3 ++- builtin/ls-files.c | 2 +- builtin/read-tree.c | 3 ++- builtin/reset.c | 3 ++- builtin/rm.c | 3 ++- builtin/sparse-checkout.c | 6 ++++-- read-cache.c | 6 +++--- repository.c | 2 +- sequencer.c | 4 ++-- sparse-index.c | 6 ++++-- t/t1092-sparse-checkout-compatibility.sh | 8 ++++++++ unpack-trees.c | 4 ++-- 12 files changed, 33 insertions(+), 17 deletions(-) diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c index 29e744d11be410..4550ce12044fce 100644 --- a/builtin/checkout-index.c +++ b/builtin/checkout-index.c @@ -154,7 +154,8 @@ static int checkout_all(const char *prefix, int prefix_length) * first entry inside the expanded sparse directory). */ if (ignore_skip_worktree) { - ensure_full_index(the_repository->index); + ensure_full_index_with_reason(the_repository->index, + "checkout-index"); ce = the_repository->index->cache[i]; } } diff --git a/builtin/ls-files.c b/builtin/ls-files.c index 6eeb5cba783d8d..c955267011bda7 100644 --- a/builtin/ls-files.c +++ b/builtin/ls-files.c @@ -410,7 +410,7 @@ static void show_files(struct repository *repo, struct dir_struct *dir) return; if (!show_sparse_dirs) - ensure_full_index(repo->index); + ensure_full_index_with_reason(repo->index, "ls-files"); for (i = 0; i < repo->index->cache_nr; i++) { const struct cache_entry *ce = repo->index->cache[i]; diff --git a/builtin/read-tree.c b/builtin/read-tree.c index a8cf8504b8a368..c2994bc2af18c2 100644 --- a/builtin/read-tree.c +++ b/builtin/read-tree.c @@ -224,7 +224,8 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix) setup_work_tree(); if (opts.skip_sparse_checkout) - ensure_full_index(the_repository->index); + ensure_full_index_with_reason(the_repository->index, + "read-tree"); if (opts.merge) { switch (stage - 1) { diff --git a/builtin/reset.c b/builtin/reset.c index 6e11fc88c0b512..2c1dbb0ec80254 100644 --- a/builtin/reset.c +++ b/builtin/reset.c @@ -259,7 +259,8 @@ static int read_from_tree(const struct pathspec *pathspec, opt.add_remove = diff_addremove; if (pathspec->nr && pathspec_needs_expanded_index(the_repository->index, pathspec)) - ensure_full_index(the_repository->index); + ensure_full_index_with_reason(the_repository->index, + "reset pathspec"); if (do_diff_cache(tree_oid, &opt)) return 1; diff --git a/builtin/rm.c b/builtin/rm.c index ac048e4a47f9ae..36027328b4faae 100644 --- a/builtin/rm.c +++ b/builtin/rm.c @@ -307,7 +307,8 @@ int cmd_rm(int argc, const char **argv, const char *prefix) seen = xcalloc(pathspec.nr, 1); if (pathspec_needs_expanded_index(the_repository->index, &pathspec)) - ensure_full_index(the_repository->index); + ensure_full_index_with_reason(the_repository->index, + "rm pathspec"); for (i = 0; i < the_repository->index->cache_nr; i++) { const struct cache_entry *ce = the_repository->index->cache[i]; diff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c index 623a5b0c4d7379..5d4f5f742c20cd 100644 --- a/builtin/sparse-checkout.c +++ b/builtin/sparse-checkout.c @@ -204,7 +204,8 @@ static void clean_tracked_sparse_directories(struct repository *r) strbuf_release(&path); if (was_full) - ensure_full_index(r->index); + ensure_full_index_with_reason(r->index, + "sparse-checkout:was full"); } static int update_working_directory(struct pattern_list *pl) @@ -435,7 +436,8 @@ static int update_modes(int *cone_mode, int *sparse_index) the_repository->index->updated_workdir = 1; if (!*sparse_index) - ensure_full_index(the_repository->index); + ensure_full_index_with_reason(the_repository->index, + "sparse-checkout:disabling sparse index"); } return 0; diff --git a/read-cache.c b/read-cache.c index c54114e0b56957..51b89df7ab644d 100644 --- a/read-cache.c +++ b/read-cache.c @@ -2373,7 +2373,7 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist) */ prepare_repo_settings(istate->repo); if (istate->repo->settings.command_requires_full_index) - ensure_full_index(istate); + ensure_full_index_with_reason(istate, "incompatible builtin"); else ensure_correct_sparsity(istate); @@ -3242,7 +3242,7 @@ static int do_write_locked_index(struct index_state *istate, "%s", get_lock_file_path(lock)); if (was_full) - ensure_full_index(istate); + ensure_full_index_with_reason(istate, "re-expanding after write"); if (ret) return ret; @@ -3346,7 +3346,7 @@ static int write_shared_index(struct index_state *istate, the_repository, "%s", get_tempfile_path(*temp)); if (was_full) - ensure_full_index(istate); + ensure_full_index_with_reason(istate, "re-expanding after write"); if (ret) return ret; diff --git a/repository.c b/repository.c index 4d7f6d5f25c50b..a9a826ee83b45d 100644 --- a/repository.c +++ b/repository.c @@ -393,7 +393,7 @@ int repo_read_index(struct repository *repo) prepare_repo_settings(repo); if (repo->settings.command_requires_full_index) - ensure_full_index(repo->index); + ensure_full_index_with_reason(repo->index, "incompatible builtin"); /* * If sparse checkouts are in use, check whether paths with the diff --git a/sequencer.c b/sequencer.c index a3fff8665c83d9..86f283787688e9 100644 --- a/sequencer.c +++ b/sequencer.c @@ -795,7 +795,7 @@ static int do_recursive_merge(struct repository *r, merge_switch_to_result(&o, head_tree, &result, 1, show_output); clean = result.clean; } else { - ensure_full_index(r->index); + ensure_full_index_with_reason(r->index, "non-ort merge strategy"); clean = merge_trees(&o, head_tree, next_tree, base_tree); if (is_rebase_i(opts) && clean <= 0) fputs(o.obuf.buf, stdout); @@ -2567,7 +2567,7 @@ static int read_and_refresh_cache(struct repository *r, * expand the sparse index. */ if (opts->strategy && strcmp(opts->strategy, "ort")) - ensure_full_index(r->index); + ensure_full_index_with_reason(r->index, "non-ort merge strategy"); return 0; } diff --git a/sparse-index.c b/sparse-index.c index 8c30c51cf2caa6..3e7cb7cdbe430d 100644 --- a/sparse-index.c +++ b/sparse-index.c @@ -483,7 +483,8 @@ void ensure_correct_sparsity(struct index_state *istate) if (is_sparse_index_allowed(istate, 0)) convert_to_sparse(istate, 0); else - ensure_full_index(istate); + ensure_full_index_with_reason(istate, + "sparse index not allowed"); } struct path_found_data { @@ -686,7 +687,8 @@ void clear_skip_worktree_from_present_files(struct index_state *istate) return; if (clear_skip_worktree_from_present_files_sparse(istate)) { - ensure_full_index(istate); + ensure_full_index_with_reason(istate, + "failed to clear skip-worktree while sparse"); clear_skip_worktree_from_present_files_full(istate); } } diff --git a/t/t1092-sparse-checkout-compatibility.sh b/t/t1092-sparse-checkout-compatibility.sh index 1954bf6332d691..5a6e2661e26ad9 100755 --- a/t/t1092-sparse-checkout-compatibility.sh +++ b/t/t1092-sparse-checkout-compatibility.sh @@ -2448,4 +2448,12 @@ test_expect_success 'advice.sparseIndexExpanded' ' grep "The sparse index is expanding to a full index" err ' +test_expect_success 'ensure_full_index_with_reason' ' + init_repos && + + GIT_TRACE2_EVENT="$(pwd)/ls-files-trace" \ + git -C sparse-index ls-files --no-sparse HEAD && + test_trace2_data "sparse-index" "expansion-reason" "ls-files" settings.command_requires_full_index) { - ensure_full_index(o->src_index); + ensure_full_index_with_reason(o->src_index, "incompatible builtin"); if (o->dst_index) - ensure_full_index(o->dst_index); + ensure_full_index_with_reason(o->dst_index, "incompatible builtin"); } if (o->reset == UNPACK_RESET_OVERWRITE_UNTRACKED && From 7f061d8e36a99ccbf3d9f37e7e98d8a6cfaf7b97 Mon Sep 17 00:00:00 2001 From: Derrick Stolee Date: Mon, 30 Sep 2024 16:59:07 -0400 Subject: [PATCH 3/6] treewide: custom reasons for expanding index These cases that call ensure_full_index() are likely to be due to a data shape issue on a user's machine, so take the extra time to format a message that can be placed in their trace2 output and hopefully identify the problem that is leading to this slow behavior. Signed-off-by: Derrick Stolee --- builtin/update-index.c | 4 +++- merge-ort.c | 3 ++- read-cache.c | 4 +++- sparse-index.c | 4 +++- t/t1092-sparse-checkout-compatibility.sh | 10 +++++++++- unpack-trees.c | 6 ++++-- 6 files changed, 24 insertions(+), 7 deletions(-) diff --git a/builtin/update-index.c b/builtin/update-index.c index 9e1eb6b0aead95..859df54197a2bc 100644 --- a/builtin/update-index.c +++ b/builtin/update-index.c @@ -712,7 +712,9 @@ static int do_reupdate(const char **paths, * to process each path individually */ if (S_ISSPARSEDIR(ce->ce_mode)) { - ensure_full_index(the_repository->index); + const char *fmt = "update-index:modified sparse dir '%s'"; + ensure_full_index_with_reason(the_repository->index, + fmt, ce->name); goto redo; } diff --git a/merge-ort.c b/merge-ort.c index e9d01ac7f7ad34..b4499b7a645fef 100644 --- a/merge-ort.c +++ b/merge-ort.c @@ -4532,7 +4532,8 @@ static int record_conflicted_index_entries(struct merge_options *opt) */ strmap_for_each_entry(&opt->priv->conflicted, &iter, e) { if (!path_in_sparse_checkout(e->key, index)) { - ensure_full_index(index); + const char *fmt = "merge-ort: path outside sparse checkout (%s)"; + ensure_full_index_with_reason(index, fmt, e->key); break; } } diff --git a/read-cache.c b/read-cache.c index 51b89df7ab644d..feecfa527c26cb 100644 --- a/read-cache.c +++ b/read-cache.c @@ -553,7 +553,9 @@ static int index_name_stage_pos(struct index_state *istate, if (S_ISSPARSEDIR(ce->ce_mode) && ce_namelen(ce) < namelen && !strncmp(name, ce->name, ce_namelen(ce))) { - ensure_full_index(istate); + const char *fmt = "searching for '%s' and found parent dir '%s'"; + ensure_full_index_with_reason(istate, fmt, + name, ce->name); return index_name_stage_pos(istate, name, namelen, stage, search_mode); } } diff --git a/sparse-index.c b/sparse-index.c index 3e7cb7cdbe430d..ef0db8487b1ae0 100644 --- a/sparse-index.c +++ b/sparse-index.c @@ -751,7 +751,9 @@ void expand_to_path(struct index_state *istate, * in the index, perhaps it exists within this * sparse-directory. Expand accordingly. */ - ensure_full_index(istate); + const char *fmt = "found index entry for '%s'"; + ensure_full_index_with_reason(istate, fmt, + path_mutable.buf); break; } diff --git a/t/t1092-sparse-checkout-compatibility.sh b/t/t1092-sparse-checkout-compatibility.sh index 5a6e2661e26ad9..e6f04ed4a69183 100755 --- a/t/t1092-sparse-checkout-compatibility.sh +++ b/t/t1092-sparse-checkout-compatibility.sh @@ -2453,7 +2453,15 @@ test_expect_success 'ensure_full_index_with_reason' ' GIT_TRACE2_EVENT="$(pwd)/ls-files-trace" \ git -C sparse-index ls-files --no-sparse HEAD && - test_trace2_data "sparse-index" "expansion-reason" "ls-files" sparse-index/folder2/a && + GIT_TRACE2_EVENT="$(pwd)/status-trace" \ + git -C sparse-index status && + test_trace2_data "sparse-index" "skip-worktree sparsedir" "folder2/" = 0) - ensure_full_index(istate); + index_name_pos(istate, ce_prefix.buf, ce_prefix.len) >= 0) { + const char *fmt = "could not find '%s' in index"; + ensure_full_index_with_reason(istate, fmt, ce_prefix.buf); + } strbuf_release(&ce_prefix); } From 53e266813c5f430cba4953ec7c299217f7ca1435 Mon Sep 17 00:00:00 2001 From: Derrick Stolee Date: Mon, 30 Sep 2024 17:05:06 -0400 Subject: [PATCH 4/6] sparse-index: add macro for unaudited expansions For safety, areas of code that iterate over the cache entries in the index were guarded with ensure_full_index() and labeled with a comment. Replace these with a macro that calls ensure_full_index_with_reason() using the line number of the caller to help identify the situation that is causing the index expansion. Signed-off-by: Derrick Stolee --- builtin/commit.c | 4 ++-- builtin/difftool.c | 2 +- builtin/fsck.c | 2 +- builtin/merge-index.c | 4 ++-- builtin/stash.c | 2 +- builtin/submodule--helper.c | 2 +- entry.c | 2 +- merge-recursive.c | 2 +- read-cache.c | 4 ++-- resolve-undo.c | 2 +- revision.c | 2 +- sparse-index.h | 6 ++++++ 12 files changed, 20 insertions(+), 14 deletions(-) diff --git a/builtin/commit.c b/builtin/commit.c index 6ec1f3bdd78186..c19053e4118f29 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -381,7 +381,7 @@ static int list_paths(struct string_list *list, const char *with_tree, } /* TODO: audit for interaction with sparse-index. */ - ensure_full_index(the_repository->index); + ensure_full_index_unaudited(the_repository->index); for (i = 0; i < the_repository->index->cache_nr; i++) { const struct cache_entry *ce = the_repository->index->cache[i]; struct string_list_item *item; @@ -1119,7 +1119,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix, int i, ita_nr = 0; /* TODO: audit for interaction with sparse-index. */ - ensure_full_index(the_repository->index); + ensure_full_index_unaudited(the_repository->index); for (i = 0; i < the_repository->index->cache_nr; i++) if (ce_intent_to_add(the_repository->index->cache[i])) ita_nr++; diff --git a/builtin/difftool.c b/builtin/difftool.c index 5cca20276a06c2..fd7ef528bc1a32 100644 --- a/builtin/difftool.c +++ b/builtin/difftool.c @@ -586,7 +586,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix, ret = run_command(&cmd); /* TODO: audit for interaction with sparse-index. */ - ensure_full_index(&wtindex); + ensure_full_index_unaudited(&wtindex); /* * If the diff includes working copy files and those diff --git a/builtin/fsck.c b/builtin/fsck.c index d13a226c2ed86b..f4206821de4ec3 100644 --- a/builtin/fsck.c +++ b/builtin/fsck.c @@ -815,7 +815,7 @@ static void fsck_index(struct index_state *istate, const char *index_path, unsigned int i; /* TODO: audit for interaction with sparse-index. */ - ensure_full_index(istate); + ensure_full_index_unaudited(istate); for (i = 0; i < istate->cache_nr; i++) { unsigned int mode; struct blob *blob; diff --git a/builtin/merge-index.c b/builtin/merge-index.c index 0fabe3f6bb2092..e73e02c8d5eefa 100644 --- a/builtin/merge-index.c +++ b/builtin/merge-index.c @@ -64,7 +64,7 @@ static void merge_all(void) { int i; /* TODO: audit for interaction with sparse-index. */ - ensure_full_index(the_repository->index); + ensure_full_index_unaudited(the_repository->index); for (i = 0; i < the_repository->index->cache_nr; i++) { const struct cache_entry *ce = the_repository->index->cache[i]; if (!ce_stage(ce)) @@ -88,7 +88,7 @@ int cmd_merge_index(int argc, const char **argv, const char *prefix UNUSED) repo_read_index(the_repository); /* TODO: audit for interaction with sparse-index. */ - ensure_full_index(the_repository->index); + ensure_full_index_unaudited(the_repository->index); i = 1; if (!strcmp(argv[i], "-o")) { diff --git a/builtin/stash.c b/builtin/stash.c index 80ccfc7a085d1a..ab703f96ad5d3c 100644 --- a/builtin/stash.c +++ b/builtin/stash.c @@ -1549,7 +1549,7 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q char *ps_matched = xcalloc(ps->nr, 1); /* TODO: audit for interaction with sparse-index. */ - ensure_full_index(the_repository->index); + ensure_full_index_unaudited(the_repository->index); for (i = 0; i < the_repository->index->cache_nr; i++) ce_path_match(the_repository->index, the_repository->index->cache[i], ps, ps_matched); diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c index f1218a19957aa5..91e68918cb5fbb 100644 --- a/builtin/submodule--helper.c +++ b/builtin/submodule--helper.c @@ -3321,7 +3321,7 @@ static void die_on_index_match(const char *path, int force) char *ps_matched = xcalloc(ps.nr, 1); /* TODO: audit for interaction with sparse-index. */ - ensure_full_index(the_repository->index); + ensure_full_index_unaudited(the_repository->index); /* * Since there is only one pathspec, we just need to diff --git a/entry.c b/entry.c index 2f92fdb2fe069e..a60c28971f72f7 100644 --- a/entry.c +++ b/entry.c @@ -451,7 +451,7 @@ static void mark_colliding_entries(const struct checkout *state, ce->ce_flags |= CE_MATCHED; /* TODO: audit for interaction with sparse-index. */ - ensure_full_index(state->istate); + ensure_full_index_unaudited(state->istate); for (i = 0; i < state->istate->cache_nr; i++) { struct cache_entry *dup = state->istate->cache[i]; diff --git a/merge-recursive.c b/merge-recursive.c index 0a00568064340f..ce61669f0eae76 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -539,7 +539,7 @@ static struct string_list *get_unmerged(struct index_state *istate) string_list_init_dup(unmerged); /* TODO: audit for interaction with sparse-index. */ - ensure_full_index(istate); + ensure_full_index_unaudited(istate); for (i = 0; i < istate->cache_nr; i++) { struct string_list_item *item; struct stage_data *e; diff --git a/read-cache.c b/read-cache.c index feecfa527c26cb..59d67ce30fd8e0 100644 --- a/read-cache.c +++ b/read-cache.c @@ -2587,7 +2587,7 @@ int repo_index_has_changes(struct repository *repo, return opt.flags.has_changes != 0; } else { /* TODO: audit for interaction with sparse-index. */ - ensure_full_index(istate); + ensure_full_index_unaudited(istate); for (i = 0; sb && i < istate->cache_nr; i++) { if (i) strbuf_addch(sb, ' '); @@ -3898,7 +3898,7 @@ void overlay_tree_on_index(struct index_state *istate, /* Hoist the unmerged entries up to stage #3 to make room */ /* TODO: audit for interaction with sparse-index. */ - ensure_full_index(istate); + ensure_full_index_unaudited(istate); for (i = 0; i < istate->cache_nr; i++) { struct cache_entry *ce = istate->cache[i]; if (!ce_stage(ce)) diff --git a/resolve-undo.c b/resolve-undo.c index 8c9911affbe409..cefe67cc3df467 100644 --- a/resolve-undo.c +++ b/resolve-undo.c @@ -160,7 +160,7 @@ void unmerge_index(struct index_state *istate, const struct pathspec *pathspec, return; /* TODO: audit for interaction with sparse-index. */ - ensure_full_index(istate); + ensure_full_index_unaudited(istate); for_each_string_list_item(item, istate->resolve_undo) { const char *path = item->string; diff --git a/revision.c b/revision.c index 5fecd7e0d75c03..89a02fd3956c2a 100644 --- a/revision.c +++ b/revision.c @@ -1828,7 +1828,7 @@ static void do_add_index_objects_to_pending(struct rev_info *revs, int i; /* TODO: audit for interaction with sparse-index. */ - ensure_full_index(istate); + ensure_full_index_unaudited(istate); for (i = 0; i < istate->cache_nr; i++) { struct cache_entry *ce = istate->cache[i]; struct blob *blob; diff --git a/sparse-index.h b/sparse-index.h index b8d51b091196a0..41b6f93681b578 100644 --- a/sparse-index.h +++ b/sparse-index.h @@ -1,6 +1,8 @@ #ifndef SPARSE_INDEX_H__ #define SPARSE_INDEX_H__ +#include "strbuf.h" + struct index_state; #define SPARSE_INDEX_MEMORY_ONLY (1 << 0) int is_sparse_index_allowed(struct index_state *istate, int flags); @@ -47,4 +49,8 @@ void ensure_full_index_with_reason(struct index_state *istate, const char *fmt, ...); +#define ensure_full_index_unaudited(i) \ + ensure_full_index_with_reason((i), \ + "unaudited call (%s.%d)", __FILE__, __LINE__); + #endif From dc7b1e08d1c35986d21b97dbe420f02afd5bdc3f Mon Sep 17 00:00:00 2001 From: Derrick Stolee Date: Mon, 30 Sep 2024 17:07:14 -0400 Subject: [PATCH 5/6] Docs: update sparse index plan with logging The recent changes update the callers of ensure_full_index() to call variants that will log extra information. This should assist developers assisting users who are hitting the sparse index expansion message. Signed-off-by: Derrick Stolee --- Documentation/technical/sparse-index.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Documentation/technical/sparse-index.txt b/Documentation/technical/sparse-index.txt index 3b24c1a219f811..c466dbddc930a9 100644 --- a/Documentation/technical/sparse-index.txt +++ b/Documentation/technical/sparse-index.txt @@ -206,3 +206,10 @@ Here are some commands that might be useful to update: * `git am` * `git clean` * `git stash` + +In order to help identify the cases where remaining index expansion is +occurring in user machines, calls to `ensure_full_index()` have been +replaced with `ensure_full_index_with_reason()` or with +`ensure_full_index_unaudited()`. These versions add tracing that should +help identify the reason for the index expansion without needing full +access to someone's repository. From e75130841defc703371f4e5a46c5b3ee24ad111a Mon Sep 17 00:00:00 2001 From: Derrick Stolee Date: Mon, 30 Sep 2024 17:14:58 -0400 Subject: [PATCH 6/6] sparse-index: log failure to clear skip-worktree The clear_skip_worktree_from_present_files_sparse() method attempts to clear the skip worktree bit from cache entries in the index depending on when they exist in the workdir. When this comes across a sparse directory that actually exists in the workdir, then this method fails and signals that the index needs expansion. The index expansion already logs a reason, but this reason is separate from the path that caused this failure. Add logging to demonstrate this situation for full clarity. Signed-off-by: Derrick Stolee --- sparse-index.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sparse-index.c b/sparse-index.c index ef0db8487b1ae0..1fd70155a368e2 100644 --- a/sparse-index.c +++ b/sparse-index.c @@ -632,6 +632,8 @@ static int clear_skip_worktree_from_present_files_sparse(struct index_state *ist if (path_found(ce->name, &data)) { if (S_ISSPARSEDIR(ce->ce_mode)) { to_restart = 1; + trace2_data_string("sparse-index", istate->repo, + "skip-worktree sparsedir", ce->name); break; } ce->ce_flags &= ~CE_SKIP_WORKTREE;