Re: [PATCH 1/4] ref-cache.c: fix prefix matching in ref iteration
- From
Junio C Hamano <gitster@pobox.com>
- Date
- Oct 6, 2023, 21:51 UTC
- Message-ID
- <xmqqfs2n8lnn.fsf@gitster.g>
- In-Reply-To
- <59276a5b3fd1fd3b25db73e096cf0e834af2d4f9.1696615769.git.gitgitgadget@gmail.com>
"Victoria Dye via GitGitGadget" <gitgitgadget@gmail.com> writes:
Show 38 quoted lines
> 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.
Thanks for explaining it very well and clearly.
Allowing prefix="refs/heads/v1.0" to yield entry="refs/heads/v1" (case #2 above that this patch fixes the behaviour for) would cause ref_iterator_advance() to return a ref outside the hierarhcy, wouldn't it? So it appears to me that either one of the two would be true:
* the code is structured in such a way that such a condition does not actually happen (in which case this patch would be a no-op), or
* there is a bug in the current code that is fixed by this patch, whose externally observable behaviour can be verified with a test.
It is not quite clear to me which is the case here. The code with the patch looks more logical than the original, but I am not sure how to demonstrate the existing breakage (if any).
Show 19 quoted lines
> 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;