[PATCH 1/4] ref-cache.c: fix prefix matching in ref iteration
- From
Victoria Dye via GitGitGadget <gitgitgadget@gmail.com>
- Date
- Oct 6, 2023, 18:09 UTC
- Message-ID
- <59276a5b3fd1fd3b25db73e096cf0e834af2d4f9.1696615769.git.gitgitgadget@gmail.com>
- In-Reply-To
- <pull.1594.git.1696615769.gitgitgadget@gmail.com>
From: Victoria Dye <vdye@github.com>
Update 'cache_ref_iterator_advance' to skip over refs that are not matched by the given prefix.
Currently, a ref entry is considered "matched" if the entry name is fully contained within the prefix:
* prefix: "refs/heads/v1" * entry: "refs/heads/v1.0"
OR if the prefix is fully contained in the entry name:
* prefix: "refs/heads/v1.0" * entry: "refs/heads/v1"
The first case is always correct, but the second is only correct if the ref cache entry is a directory, for example:
* prefix: "refs/heads/example" * entry: "refs/heads/"
Modify the logic in 'cache_ref_iterator_advance' to reflect these expectations:
1. If 'overlaps_prefix' returns 'PREFIX_EXCLUDES_DIR', then the prefix and ref cache entry do not overlap at all. Skip this entry. 2. If 'overlaps_prefix' returns 'PREFIX_WITHIN_DIR', then the prefix matches inside this entry if it is a directory. Skip if the entry is not a directory, otherwise iterate over it. 3. Otherwise, 'overlaps_prefix' returned 'PREFIX_CONTAINS_DIR', indicating that the cache entry (directory or not) is fully contained by or equal to the prefix. Iterate over this entry.
Note that condition 2 relies on the names of directory entries having the appropriate trailing slash. The existing function documentation of 'create_dir_entry' explicitly calls out the trailing slash requirement, so this is a safe assumption to make.
Signed-off-by: Victoria Dye <vdye@github.com> --- refs/ref-cache.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/refs/ref-cache.c b/refs/ref-cache.c index 2294c4564fb..6e3b725245c 100644 --- a/refs/ref-cache.c +++ b/refs/ref-cache.c @@ -412,7 +412,8 @@ static int cache_ref_iterator_advance(struct ref_iterator *ref_iterator) if (level->prefix_state == PREFIX_WITHIN_DIR) { entry_prefix_state = overlaps_prefix(entry->name, iter->prefix); - if (entry_prefix_state == PREFIX_EXCLUDES_DIR) + if (entry_prefix_state == PREFIX_EXCLUDES_DIR || + (entry_prefix_state == PREFIX_WITHIN_DIR && !(entry->flag & REF_DIR))) continue; } else { entry_prefix_state = level->prefix_state;
-- gitgitgadget