Skip to content

Commit 2f71366

Browse files
committed
Merge branch 'ds/add-with-sparse-index'
"git add" can work better with the sparse index. * ds/add-with-sparse-index: add: remove ensure_full_index() with --renormalize add: ignore outside the sparse-checkout in refresh() pathspec: stop calling ensure_full_index add: allow operating on a sparse-only index t1092: test merge conflicts outside cone
2 parents ae2d05d + 42f8ed6 commit 2f71366

File tree

3 files changed

+70
-14
lines changed

3 files changed

+70
-14
lines changed

builtin/add.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,6 @@ static int renormalize_tracked_files(const struct pathspec *pathspec, int flags)
144144
{
145145
int i, retval = 0;
146146

147-
/* TODO: audit for interaction with sparse-index. */
148-
ensure_full_index(&the_index);
149147
for (i = 0; i < active_nr; i++) {
150148
struct cache_entry *ce = active_cache[i];
151149

@@ -192,13 +190,21 @@ static int refresh(int verbose, const struct pathspec *pathspec)
192190
struct string_list only_match_skip_worktree = STRING_LIST_INIT_NODUP;
193191
int flags = REFRESH_IGNORE_SKIP_WORKTREE |
194192
(verbose ? REFRESH_IN_PORCELAIN : REFRESH_QUIET);
193+
struct pattern_list pl = { 0 };
194+
int sparse_checkout_enabled = !get_sparse_checkout_patterns(&pl);
195195

196196
seen = xcalloc(pathspec->nr, 1);
197197
refresh_index(&the_index, flags, pathspec, seen,
198198
_("Unstaged changes after refreshing the index:"));
199199
for (i = 0; i < pathspec->nr; i++) {
200200
if (!seen[i]) {
201-
if (matches_skip_worktree(pathspec, i, &skip_worktree_seen)) {
201+
const char *path = pathspec->items[i].original;
202+
int dtype = DT_REG;
203+
204+
if (matches_skip_worktree(pathspec, i, &skip_worktree_seen) ||
205+
(sparse_checkout_enabled &&
206+
!path_matches_pattern_list(path, strlen(path), NULL,
207+
&dtype, &pl, &the_index))) {
202208
string_list_append(&only_match_skip_worktree,
203209
pathspec->items[i].original);
204210
} else {
@@ -528,6 +534,9 @@ int cmd_add(int argc, const char **argv, const char *prefix)
528534
add_new_files = !take_worktree_changes && !refresh_only && !add_renormalize;
529535
require_pathspec = !(take_worktree_changes || (0 < addremove_explicit));
530536

537+
prepare_repo_settings(the_repository);
538+
the_repository->settings.command_requires_full_index = 0;
539+
531540
hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
532541

533542
/*

pathspec.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,6 @@ void add_pathspec_matches_against_index(const struct pathspec *pathspec,
3737
num_unmatched++;
3838
if (!num_unmatched)
3939
return;
40-
/* TODO: audit for interaction with sparse-index. */
41-
ensure_full_index(istate);
4240
for (i = 0; i < istate->cache_nr; i++) {
4341
const struct cache_entry *ce = istate->cache[i];
4442
if (sw_action == PS_IGNORE_SKIP_WORKTREE && ce_skip_worktree(ce))

t/t1092-sparse-checkout-compatibility.sh

Lines changed: 58 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,16 @@ test_expect_success 'setup' '
114114
git add . &&
115115
git commit -m "file to dir" &&
116116
117+
for side in left right
118+
do
119+
git checkout -b merge-$side base &&
120+
echo $side >>deep/deeper2/a &&
121+
echo $side >>folder1/a &&
122+
echo $side >>folder2/a &&
123+
git add . &&
124+
git commit -m "$side" || return 1
125+
done &&
126+
117127
git checkout -b deepest base &&
118128
echo "updated deepest" >deep/deeper1/deepest/a &&
119129
git commit -a -m "update deepest" &&
@@ -312,9 +322,6 @@ test_expect_success 'commit including unstaged changes' '
312322
test_expect_success 'status/add: outside sparse cone' '
313323
init_repos &&
314324
315-
# adding a "missing" file outside the cone should fail
316-
test_sparse_match test_must_fail git add folder1/a &&
317-
318325
# folder1 is at HEAD, but outside the sparse cone
319326
run_on_sparse mkdir folder1 &&
320327
cp initial-repo/folder1/a sparse-checkout/folder1/a &&
@@ -330,21 +337,23 @@ test_expect_success 'status/add: outside sparse cone' '
330337
331338
test_sparse_match git status --porcelain=v2 &&
332339
333-
# This "git add folder1/a" fails with a warning
334-
# in the sparse repos, differing from the full
335-
# repo. This is intentional.
340+
# Adding the path outside of the sparse-checkout cone should fail.
336341
test_sparse_match test_must_fail git add folder1/a &&
337342
test_sparse_match test_must_fail git add --refresh folder1/a &&
338-
test_all_match git status --porcelain=v2 &&
343+
344+
# NEEDSWORK: Adding a newly-tracked file outside the cone succeeds
345+
test_sparse_match git add folder1/new &&
339346
340347
test_all_match git add . &&
341348
test_all_match git status --porcelain=v2 &&
342349
test_all_match git commit -m folder1/new &&
350+
test_all_match git rev-parse HEAD^{tree} &&
343351
344352
run_on_all ../edit-contents folder1/newer &&
345353
test_all_match git add folder1/ &&
346354
test_all_match git status --porcelain=v2 &&
347-
test_all_match git commit -m folder1/newer
355+
test_all_match git commit -m folder1/newer &&
356+
test_all_match git rev-parse HEAD^{tree}
348357
'
349358

350359
test_expect_success 'checkout and reset --hard' '
@@ -482,6 +491,39 @@ test_expect_success 'merge' '
482491
test_all_match git rev-parse HEAD^{tree}
483492
'
484493

494+
# NEEDSWORK: This test is documenting current behavior, but that
495+
# behavior can be confusing to users so there is desire to change it.
496+
# Right now, users might be using this flow to work through conflicts,
497+
# so any solution should present advice to users who try this sequence
498+
# of commands to follow whatever new method we create.
499+
test_expect_success 'merge with conflict outside cone' '
500+
init_repos &&
501+
502+
test_all_match git checkout -b merge-tip merge-left &&
503+
test_all_match git status --porcelain=v2 &&
504+
test_all_match test_must_fail git merge -m merge merge-right &&
505+
test_all_match git status --porcelain=v2 &&
506+
507+
# Resolve the conflict in different ways:
508+
# 1. Revert to the base
509+
test_all_match git checkout base -- deep/deeper2/a &&
510+
test_all_match git status --porcelain=v2 &&
511+
512+
# 2. Add the file with conflict markers
513+
test_all_match git add folder1/a &&
514+
test_all_match git status --porcelain=v2 &&
515+
516+
# 3. Rename the file to another sparse filename and
517+
# accept conflict markers as resolved content.
518+
run_on_all mv folder2/a folder2/z &&
519+
test_all_match git add folder2 &&
520+
test_all_match git status --porcelain=v2 &&
521+
522+
test_all_match git merge --continue &&
523+
test_all_match git status --porcelain=v2 &&
524+
test_all_match git rev-parse HEAD^{tree}
525+
'
526+
485527
test_expect_success 'merge with outside renames' '
486528
init_repos &&
487529
@@ -598,7 +640,14 @@ test_expect_success 'sparse-index is not expanded' '
598640
git -C sparse-index reset --hard &&
599641
ensure_not_expanded checkout rename-out-to-out -- deep/deeper1 &&
600642
git -C sparse-index reset --hard &&
601-
ensure_not_expanded restore -s rename-out-to-out -- deep/deeper1
643+
ensure_not_expanded restore -s rename-out-to-out -- deep/deeper1 &&
644+
645+
echo >>sparse-index/README.md &&
646+
ensure_not_expanded add -A &&
647+
echo >>sparse-index/extra.txt &&
648+
ensure_not_expanded add extra.txt &&
649+
echo >>sparse-index/untracked.txt &&
650+
ensure_not_expanded add .
602651
'
603652

604653
# NEEDSWORK: a sparse-checkout behaves differently from a full checkout

0 commit comments

Comments
 (0)