git add: make -p/-i aware of sparse index

It is slow to expand a sparse index in-memory due to parsing of trees.
We aim to minimize that performance cost when possible. 'git add -p'
uses 'git apply' child processes to modify the index, but still there
are some expansions that occur.

It turns out that control flows out of cmd_add() in the interactive
cases before the lines that confirm that the builtin is integrated with
the sparse index.

Moving that integration point earlier in cmd_add() allows 'git add -i'
and 'git add -p' to operate without expanding a sparse index to a full
one.

Add test cases that confirm that these interactive add options work with
the sparse index.

Signed-off-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
maint
Derrick Stolee 2025-05-16 14:55:28 +00:00 committed by Junio C Hamano
parent 952de281fe
commit 02ed8555f6
2 changed files with 64 additions and 3 deletions

View File

@ -391,6 +391,10 @@ int cmd_add(int argc,

argc = parse_options(argc, argv, prefix, builtin_add_options,
builtin_add_usage, PARSE_OPT_KEEP_ARGV0);

prepare_repo_settings(repo);
repo->settings.command_requires_full_index = 0;

if (patch_interactive)
add_interactive = 1;
if (add_interactive) {
@ -427,9 +431,6 @@ int cmd_add(int argc,
add_new_files = !take_worktree_changes && !refresh_only && !add_renormalize;
require_pathspec = !(take_worktree_changes || (0 < addremove_explicit));

prepare_repo_settings(repo);
repo->settings.command_requires_full_index = 0;

repo_hold_locked_index(repo, &lock_file, LOCK_DIE_ON_ERROR);

/*

View File

@ -384,6 +384,38 @@ test_expect_success 'add, commit, checkout' '
test_all_match git checkout -
'

test_expect_success 'git add -p' '
init_repos &&

write_script edit-contents <<-\EOF &&
echo text >>$1
EOF

# Does not expand when edits are within sparse checkout.
run_on_all ../edit-contents deep/a &&
run_on_all ../edit-contents deep/deeper1/a &&

test_write_lines y n >in &&
run_on_all git add -p <in &&
test_all_match git status --porcelain=v2 &&
test_all_match git reset &&

test_write_lines u 1 "" q >in &&
run_on_all git add -i <in &&
test_all_match git status --porcelain=v2 &&
test_all_match git reset --hard &&

run_on_sparse mkdir -p folder1 &&
run_on_all ../edit-contents folder1/a &&
test_write_lines y n y >in &&
run_on_all git add -p <in &&
test_sparse_match git status --porcelain=v2 &&
test_sparse_match git reset &&
test_write_lines u 2 3 "" q >in &&
run_on_all git add -i <in &&
test_sparse_match git status --porcelain=v2
'

test_expect_success 'deep changes during checkout' '
init_repos &&

@ -2400,6 +2432,34 @@ test_expect_success 'sparse-index is not expanded: git apply' '
ensure_expanded apply --cached ../patch-outside
'

test_expect_success 'sparse-index is not expanded: git add -p' '
init_repos &&

# Does not expand when edits are within sparse checkout.
echo "new content" >sparse-index/deep/a &&
echo "new content" >sparse-index/deep/deeper1/a &&
test_write_lines y n >in &&
ensure_not_expanded add -p <in &&
git -C sparse-index reset &&
ensure_not_expanded add -i <in &&

# -p does expand when edits are outside sparse checkout.
mkdir -p sparse-index/folder1 &&
echo "new content" >sparse-index/folder1/a &&
test_write_lines y n y >in &&
ensure_expanded add -p <in &&

# Fully reset the index.
git -C sparse-index reset --hard &&
git -C sparse-index sparse-checkout reapply &&

# -i does expand when edits are outside sparse checkout.
mkdir -p sparse-index/folder1 &&
echo "new content" >sparse-index/folder1/a &&
test_write_lines u 2 3 "" q >in &&
ensure_expanded add -i <in
'

test_expect_success 'advice.sparseIndexExpanded' '
init_repos &&