Skip to content

Commit 9479a31

Browse files
derrickstoleegitster
authored andcommitted
advice: warn when sparse index expands
Typically, forcing a sparse index to expand to a full index means that Git could not determine the status of a file outside of the sparse-checkout and needed to expand sparse trees into the full list of sparse blobs. This operation can be very slow when the sparse-checkout is much smaller than the full tree at HEAD. When users are in this state, there is usually a modified or untracked file outside of the sparse-checkout mentioned by the output of 'git status'. There are a number of reasons why this is insufficient: 1. Users may not have a full understanding of which files are inside or outside of their sparse-checkout. This is more common in monorepos that manage the sparse-checkout using custom tools that map build dependencies into sparse-checkout definitions. 2. In some cases, an empty directory could exist outside the sparse-checkout and these empty directories are not reported by 'git status' and friends. 3. If the user has '.gitignore' or 'exclude' files, then 'git status' will squelch the warnings and not demonstrate any problems. In order to help users who are in this state, add a new advice message to indicate that a sparse index is expanded to a full index. This message should be written at most once per process, so add a static global 'give_advice_on_expansion' to sparse-index.c. Further, there is a case in 'git sparse-checkout set' that uses the sparse index as an in-memory data structure (even when writing a full index) so we need to disable the message in that kind of case. The t1092-sparse-checkout-compatibility.sh test script compares the behavior of several Git commands across full and sparse repositories, including sparse repositories with and without a sparse index. We need to disable the advice in the sparse-index repo to avoid differences in stderr. By leaving the advice on in the sparse-checkout repo (without the sparse index), we can test the behavior of disabling the advice in convert_to_sparse(). (Indeed, these tests are how that necessity was discovered.) Add a test that reenables the advice and demonstrates that the message is output. The advice message is defined outside of expand_index() to avoid super- wide lines. It is also defined as a macro to avoid compile issues with -Werror=format-security. Signed-off-by: Derrick Stolee <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 3c2a3fd commit 9479a31

File tree

5 files changed

+49
-1
lines changed

5 files changed

+49
-1
lines changed

Documentation/config/advice.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,10 @@ advice.*::
109109
skippedCherryPicks::
110110
Shown when linkgit:git-rebase[1] skips a commit that has already
111111
been cherry-picked onto the upstream branch.
112+
sparseIndexExpanded::
113+
Shown when a sparse index is expanded to a full index, which is likely
114+
due to an unexpected set of files existing outside of the
115+
sparse-checkout.
112116
statusAheadBehind::
113117
Shown when linkgit:git-status[1] computes the ahead/behind
114118
counts for a local ref compared to its remote tracking ref,

advice.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ static struct {
7474
[ADVICE_SEQUENCER_IN_USE] = { "sequencerInUse" },
7575
[ADVICE_SET_UPSTREAM_FAILURE] = { "setUpstreamFailure" },
7676
[ADVICE_SKIPPED_CHERRY_PICKS] = { "skippedCherryPicks" },
77+
[ADVICE_SPARSE_INDEX_EXPANDED] = { "sparseIndexExpanded" },
7778
[ADVICE_STATUS_AHEAD_BEHIND_WARNING] = { "statusAheadBehindWarning" },
7879
[ADVICE_STATUS_HINTS] = { "statusHints" },
7980
[ADVICE_STATUS_U_OPTION] = { "statusUoption" },

advice.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ enum advice_type {
4242
ADVICE_SEQUENCER_IN_USE,
4343
ADVICE_SET_UPSTREAM_FAILURE,
4444
ADVICE_SKIPPED_CHERRY_PICKS,
45+
ADVICE_SPARSE_INDEX_EXPANDED,
4546
ADVICE_STATUS_AHEAD_BEHIND_WARNING,
4647
ADVICE_STATUS_HINTS,
4748
ADVICE_STATUS_U_OPTION,

sparse-index.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,22 @@
1212
#include "config.h"
1313
#include "dir.h"
1414
#include "fsmonitor-ll.h"
15+
#include "advice.h"
16+
17+
/**
18+
* This global is used by expand_index() to determine if we should give the
19+
* advice for advice.sparseIndexExpanded when expanding a sparse index to a full
20+
* one. However, this is sometimes done on purpose, such as in the sparse-checkout
21+
* builtin, even when index.sparse=false. This may be disabled in
22+
* convert_to_sparse().
23+
*/
24+
static int give_advice_on_expansion = 1;
25+
#define ADVICE_MSG \
26+
"The sparse index is expanding to a full index, a slow operation.\n" \
27+
"Your working directory likely has contents that are outside of\n" \
28+
"your sparse-checkout patterns. Use 'git sparse-checkout list' to\n" \
29+
"see your sparse-checkout definition and compare it to your working\n" \
30+
"directory contents. Running 'git clean' may assist in this cleanup."
1531

1632
struct modify_index_context {
1733
struct index_state *write;
@@ -183,6 +199,12 @@ int convert_to_sparse(struct index_state *istate, int flags)
183199
!is_sparse_index_allowed(istate, flags))
184200
return 0;
185201

202+
/*
203+
* If we are purposefully collapsing a full index, then don't give
204+
* advice when it is expanded later.
205+
*/
206+
give_advice_on_expansion = 0;
207+
186208
/*
187209
* NEEDSWORK: If we have unmerged entries, then stay full.
188210
* Unmerged entries prevent the cache-tree extension from working.
@@ -328,6 +350,12 @@ void expand_index(struct index_state *istate, struct pattern_list *pl)
328350
pl = NULL;
329351
}
330352

353+
if (!pl && give_advice_on_expansion) {
354+
give_advice_on_expansion = 0;
355+
advise_if_enabled(ADVICE_SPARSE_INDEX_EXPANDED,
356+
_(ADVICE_MSG));
357+
}
358+
331359
/*
332360
* A NULL pattern set indicates we are expanding a full index, so
333361
* we use a special region name that indicates the full expansion.

t/t1092-sparse-checkout-compatibility.sh

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,10 @@ init_repos () {
159159
git -C sparse-checkout sparse-checkout set deep &&
160160
git -C sparse-index sparse-checkout init --cone --sparse-index &&
161161
test_cmp_config -C sparse-index true index.sparse &&
162-
git -C sparse-index sparse-checkout set deep
162+
git -C sparse-index sparse-checkout set deep &&
163+
164+
# Disable this message to keep stderr the same.
165+
git -C sparse-index config advice.sparseIndexExpanded false
163166
}
164167

165168
init_repos_as_submodules () {
@@ -2331,4 +2334,15 @@ test_expect_success 'sparse-index is not expanded: check-attr' '
23312334
ensure_not_expanded check-attr -a --cached -- folder1/a
23322335
'
23332336

2337+
test_expect_success 'advice.sparseIndexExpanded' '
2338+
init_repos &&
2339+
2340+
git -C sparse-index config --unset advice.sparseIndexExpanded &&
2341+
git -C sparse-index sparse-checkout set deep/deeper1 &&
2342+
mkdir -p sparse-index/deep/deeper2/deepest &&
2343+
touch sparse-index/deep/deeper2/deepest/bogus &&
2344+
git -C sparse-index status 2>err &&
2345+
grep "The sparse index is expanding to a full index" err
2346+
'
2347+
23342348
test_done

0 commit comments

Comments
 (0)