Merge branch 'tn/stash-avoid-sparse-index-expansion' into jch
The 'git stash push' command has been optimized to avoid unnecessary sparse index expansion when pathspecs are wholly inside the sparse-checkout cone. Also, a potential out-of-bounds read in the sparse-index expansion check helper pathspec_needs_expanded_index() has been fixed by consistently using the parsed, prefixed path. * tn/stash-avoid-sparse-index-expansion: stash: avoid sparse-index expansion for in-cone paths pathspec: use match for sparse-index expansion checksjch
commit
bf5a557747
|
|
@ -1702,8 +1702,8 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q
|
|||
if (!include_untracked && ps->nr) {
|
||||
char *ps_matched = xcalloc(ps->nr, 1);
|
||||
|
||||
/* TODO: audit for interaction with sparse-index. */
|
||||
ensure_full_index(the_repository->index);
|
||||
if (pathspec_needs_expanded_index(the_repository->index, ps))
|
||||
ensure_full_index(the_repository->index);
|
||||
for (size_t i = 0; i < the_repository->index->cache_nr; i++)
|
||||
ce_path_match(the_repository->index, the_repository->index->cache[i], ps,
|
||||
ps_matched);
|
||||
|
|
|
|||
12
pathspec.c
12
pathspec.c
|
|
@ -847,9 +847,9 @@ int pathspec_needs_expanded_index(struct index_state *istate,
|
|||
* - not-in-cone/bar*: may need expanded index
|
||||
* - **.c: may need expanded index
|
||||
*/
|
||||
if (strspn(item.original + item.nowildcard_len, "*") ==
|
||||
if (strspn(item.match + item.nowildcard_len, "*") ==
|
||||
(unsigned int)(item.len - item.nowildcard_len) &&
|
||||
path_in_cone_mode_sparse_checkout(item.original, istate))
|
||||
path_in_cone_mode_sparse_checkout(item.match, istate))
|
||||
continue;
|
||||
|
||||
for (pos = 0; pos < istate->cache_nr; pos++) {
|
||||
|
|
@ -865,7 +865,7 @@ int pathspec_needs_expanded_index(struct index_state *istate,
|
|||
*/
|
||||
if ((unsigned int)item.nowildcard_len >
|
||||
ce_namelen(ce) &&
|
||||
!strncmp(item.original, ce->name,
|
||||
!strncmp(item.match, ce->name,
|
||||
ce_namelen(ce))) {
|
||||
res = 1;
|
||||
break;
|
||||
|
|
@ -876,13 +876,13 @@ int pathspec_needs_expanded_index(struct index_state *istate,
|
|||
* directory and the pathspec does not match the whole
|
||||
* directory, need to expand the index.
|
||||
*/
|
||||
if (!strncmp(item.original, ce->name, item.nowildcard_len) &&
|
||||
wildmatch(item.original, ce->name, 0)) {
|
||||
if (!strncmp(item.match, ce->name, item.nowildcard_len) &&
|
||||
wildmatch(item.match, ce->name, 0)) {
|
||||
res = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (!path_in_cone_mode_sparse_checkout(item.original, istate) &&
|
||||
} else if (!path_in_cone_mode_sparse_checkout(item.match, istate) &&
|
||||
!matches_skip_worktree(pathspec, i, &skip_worktree_seen))
|
||||
res = 1;
|
||||
|
||||
|
|
|
|||
|
|
@ -108,6 +108,7 @@ test_perf_on_all () {
|
|||
|
||||
test_perf_on_all git status
|
||||
test_perf_on_all 'git stash && git stash pop'
|
||||
test_perf_on_all "git stash push -- $SPARSE_CONE/a && git stash pop"
|
||||
test_perf_on_all 'echo >>new && git stash -u && git stash pop'
|
||||
test_perf_on_all git add -A
|
||||
test_perf_on_all git add .
|
||||
|
|
|
|||
|
|
@ -1598,6 +1598,61 @@ test_expect_success 'sparse-index is not expanded: stash' '
|
|||
ensure_not_expanded stash pop
|
||||
'
|
||||
|
||||
test_expect_success 'sparse-index is not expanded: stash in-cone pathspec' '
|
||||
init_repos &&
|
||||
|
||||
echo unrelated >>sparse-index/deep/e &&
|
||||
echo literal >>sparse-index/deep/a &&
|
||||
ensure_not_expanded stash push -- deep/a &&
|
||||
test_grep ! literal sparse-index/deep/a &&
|
||||
test_grep unrelated sparse-index/deep/e &&
|
||||
ensure_not_expanded stash pop &&
|
||||
test_grep literal sparse-index/deep/a &&
|
||||
|
||||
echo prefixed >>sparse-index/deep/a &&
|
||||
ensure_not_expanded -C deep stash push -- a &&
|
||||
test_grep ! prefixed sparse-index/deep/a &&
|
||||
test_grep unrelated sparse-index/deep/e &&
|
||||
ensure_not_expanded stash pop &&
|
||||
test_grep prefixed sparse-index/deep/a &&
|
||||
|
||||
echo wildcard >>sparse-index/deep/a &&
|
||||
ensure_not_expanded stash push -- "deep/a*" &&
|
||||
test_grep ! wildcard sparse-index/deep/a &&
|
||||
test_grep unrelated sparse-index/deep/e &&
|
||||
ensure_not_expanded stash pop &&
|
||||
test_grep wildcard sparse-index/deep/a &&
|
||||
|
||||
echo pathspec-file >>sparse-index/deep/a &&
|
||||
echo deep/a >pathspec-file &&
|
||||
ensure_not_expanded stash push --pathspec-from-file=../pathspec-file &&
|
||||
test_grep ! pathspec-file sparse-index/deep/a &&
|
||||
test_grep unrelated sparse-index/deep/e &&
|
||||
ensure_not_expanded stash pop &&
|
||||
test_grep pathspec-file sparse-index/deep/a &&
|
||||
|
||||
echo multiple-a >>sparse-index/deep/a &&
|
||||
echo multiple-e >>sparse-index/deep/e &&
|
||||
ensure_not_expanded stash push -- deep/a deep/e &&
|
||||
test_grep ! multiple-a sparse-index/deep/a &&
|
||||
test_grep ! multiple-e sparse-index/deep/e &&
|
||||
ensure_not_expanded stash pop &&
|
||||
test_grep multiple-a sparse-index/deep/a &&
|
||||
test_grep multiple-e sparse-index/deep/e &&
|
||||
|
||||
echo staged >>sparse-index/deep/a &&
|
||||
git -C sparse-index add deep/a &&
|
||||
ensure_not_expanded stash push --staged -- deep/a &&
|
||||
test_grep ! staged sparse-index/deep/a &&
|
||||
test_grep unrelated sparse-index/deep/e &&
|
||||
ensure_not_expanded stash pop --index &&
|
||||
test_grep staged sparse-index/deep/a &&
|
||||
test_must_fail git -C sparse-index diff --cached --quiet -- deep/a &&
|
||||
|
||||
ensure_not_expanded ! stash push -- deep/does-not-exist &&
|
||||
test_grep "did not match any file" sparse-index-error
|
||||
'
|
||||
|
||||
test_expect_success 'describe tested on all' '
|
||||
init_repos &&
|
||||
|
||||
|
|
@ -2119,6 +2174,13 @@ test_expect_success 'sparse index is not expanded: rm' '
|
|||
ensure_not_expanded rm -r deep
|
||||
'
|
||||
|
||||
test_expect_success 'sparse index is not expanded: prefixed wildcard pathspec' '
|
||||
init_repos &&
|
||||
|
||||
ensure_not_expanded -C deep rm --dry-run -- "a*" &&
|
||||
ensure_not_expanded -C deep reset base -- "a*"
|
||||
'
|
||||
|
||||
test_expect_success 'grep with and --cached' '
|
||||
init_repos &&
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue