read-cache: disable renames in add_files_to_cache

add_files_to_cache() refreshes the index from worktree changes and does
not need rename detection. When unmerged entries and a deleted stage-0
path are present together, rename detection can pair them and rewrite an
unmerged diff pair to point at the deleted path.

That later makes "git commit -a" and "git add -u" try to stat the
deleted path and die with "unable to stat". Disable rename detection in
this callback-driven staging path and add a regression test covering the
crash.

Signed-off-by: Nick Golden <blindmansion@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Nick Golden
2026-04-01 15:00:33 -04:00
committed by Junio C Hamano
parent 67ad42147a
commit c0ce43376b
2 changed files with 39 additions and 0 deletions

View File

@@ -3975,6 +3975,7 @@ int add_files_to_cache(struct repository *repo, const char *prefix,
rev.diffopt.format_callback = update_callback;
rev.diffopt.format_callback_data = &data;
rev.diffopt.flags.override_submodule_config = 1;
rev.diffopt.detect_rename = 0; /* staging worktree changes does not need renames */
rev.max_count = 0; /* do not compare unmerged paths with stage #2 */
/*

View File

@@ -200,6 +200,44 @@ test_expect_success 'add -u resolves unmerged paths' '
test_cmp expect actual
'
test_expect_success 'add -u avoids rename pairing on unmerged paths' '
test_create_repo rename-crash &&
(
cd rename-crash &&
test_seq 1 100 |
sed "s/.*/line &: same text/" >conflict.txt &&
cp conflict.txt bystander.txt &&
git add conflict.txt bystander.txt &&
git commit -m "initial: two files with identical content" &&
main_branch=$(git symbolic-ref --short HEAD) &&
git checkout -b feature &&
sed "s/^line 50:.*/line 50: FEATURE/" \
conflict.txt >conflict.txt.tmp &&
mv conflict.txt.tmp conflict.txt &&
git add conflict.txt &&
git commit -m "feature: modify line 50" &&
git checkout "$main_branch" &&
sed "s/^line 50:.*/line 50: MAIN/" \
conflict.txt >conflict.txt.tmp &&
mv conflict.txt.tmp conflict.txt &&
git add conflict.txt &&
git commit -m "main: modify line 50 differently" &&
test_must_fail git merge feature &&
rm bystander.txt &&
git add -u >out &&
test_must_be_empty out &&
git ls-files -u >actual &&
test_must_be_empty actual &&
git ls-files bystander.txt conflict.txt >actual &&
cat >expect <<-\EOF &&
conflict.txt
EOF
test_cmp expect actual &&
git diff-files --name-only >actual &&
test_must_be_empty actual
)
'
test_expect_success '"add -u non-existent" should fail' '
test_must_fail git add -u non-existent &&
git ls-files >actual &&