diff options
author | Victoria Dye <vdye@github.com> | 2023-10-10 00:58:53 +0300 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2023-10-10 01:53:13 +0300 |
commit | 5305474ec4650755f2c0437c004cabfb1c60cf6a (patch) | |
tree | 55c6343c74bc3a9a50732d2267058f9b4574d5ad /refs | |
parent | 43c8a30d150ecede9709c1f2527c8fba92c65f40 (diff) |
ref-cache.c: fix prefix matching in ref iteration
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.
This bug generally doesn't have any user-facing impact, since it requires:
1. using a non-empty prefix without a trailing slash in an iteration like
'for_each_fullref_in',
2. the callback to said iteration not reapplying the original filter (as
for-each-ref does) to ensure unmatched refs are skipped, and
3. the repository having one or more refs that match part of, but not all
of, the prefix.
However, there are some niche scenarios that meet those criteria
(specifically, 'rev-parse --bisect' and '(log|show|shortlog) --bisect'). Add
tests covering those cases to demonstrate the fix in this patch.
Signed-off-by: Victoria Dye <vdye@github.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'refs')
-rw-r--r-- | refs/ref-cache.c | 3 |
1 files changed, 2 insertions, 1 deletions
diff --git a/refs/ref-cache.c b/refs/ref-cache.c index 2294c4564f..6e3b725245 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; |