Repository navigation
index: improve file/dir conflicts handling - #7332
Merged
ethomson merged 1 commit intoAug 3, 2026
Merged
Conversation
index_existing_and_best() computes the correct sorted insertion position via index_find(), and even uses that position for the stage-matching loop a few lines later, but on the "entry not found" branch it discarded the computed position and hardcoded the *existing_position out-parameter to 0 instead. index_insert() passes this position straight through to check_file_directory_collision() and has_file_name(), which scan forward from it looking for a directory/file conflict. Starting the scan from 0 instead of the real insertion point made it bail out on the first unrelated entry sorted before the conflict, so git_index_add() silently accepted paths that collide with an existing file/directory and left the stale conflicting entry behind. Use the already-computed position instead of hardcoding 0. Add a regression test with multiple sibling entries, since the existing collision tests only ever had a single prior index entry, where the correct position happens to be 0 anyway and the bug stayed hidden. Fixes libgit2#7160
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
git_index_addsilently ignores a file/directory conflict: adding a blob at a path that collides with an existing tree entry (or vice versa) should replace the conflicting entry the way git does, but the stale entry is left in place and the add "succeeds".Cause
In
index_existing_and_best()(src/libgit2/index.c), when the entry is not already in the index,index_findhas computedpos— the sorted insertion position — but the function discards it and hardcodes the out-param to0:The sole caller,
index_insert, passes that position intocheck_file_directory_collision()→has_file_name(), which scans forward from it. Starting the scan at0instead of the real insertion position means an earlier-sorting sibling entry can end the prefix scan before the actual conflict is reached, so the collision is never found. The bug is only observable when the insertion position is non-zero — which is why the existing collision tests (each with a single prior entry, whose insertion position happens to be0) don't catch it.Fix
Report the real insertion position on the not-found branch:
posis valid here:git__bsearchsets it to the insertion index even onGIT_ENOTFOUND, and the stage-matching loop just below already relies on it.index_existing_and_bestis static with one caller, and nothing depends on the oldexisting == NULL ⇒ position == 0behaviour.Test
Adds
add_blob_with_conflicting_dir_not_at_start, which seeds sibling entries so the conflictingblobtreelands at a non-zero insertion position, reproducing the missed conflict that the fix resolves.Fixes #7160.