Re: [PATCH] remote: prefer exact matches when using refspecs
- From
Jonathan Nieder <jrnieder@gmail.com>
- Date
- Jul 31, 2018, 21:31 UTC
- Message-ID
- <20180731213120.GA113554@aiede.svl.corp.google.com>
- In-Reply-To
- <20180731211832.142014-1-jonathantanmy@google.com>
Hi,
Jonathan Tan wrote:
Show 20 quoted lines
> When matching a non-wildcard LHS of a refspec against a list of refs, > find_ref_by_name_abbrev() returns the first ref that matches using the > DWIM rules used by refname_match() in refs.c, even if an exact match > occurs later in the list of refs. > > This causes unexpected behavior when (for example) fetching using the > refspec "refs/heads/s:<something>" from a remote with both > "refs/heads/refs/heads/s" and "refs/heads/s". (Even if the former was > inadvertently created, one would still expect the latter to be fetched.) > > This problem has only been observed when the desired ref comes after the > undesired ref in alphabetical order. However, for completeness, the test > in this patch also checks what happens when the desired ref comes first > alphabetically. > > Signed-off-by: Jonathan Tan <jonathantanmy@google.com> > --- > remote.c | 7 +++++-- > t/t5510-fetch.sh | 28 ++++++++++++++++++++++++++++ > 2 files changed, 33 insertions(+), 2 deletions(-)
Very clear analysis --- thank you.
Show 13 quoted lines
> --- a/remote.c
> +++ b/remote.c
> @@ -1687,12 +1687,15 @@ static struct ref *get_expanded_map(const struct ref *remote_refs,
>
> static const struct ref *find_ref_by_name_abbrev(const struct ref *refs, const char *name)
> {
> + const struct ref *best_match = NULL;
> const struct ref *ref;
> for (ref = refs; ref; ref = ref->next) {
> - if (refname_match(name, ref->name))
> + if (!strcmp(name, ref->name))
> return ref;
> + if (refname_match(name, ref->name))Should this check be
if (!best_match && refname_match(name, ref->name))
? Otherwise, this would make us prefer the last ref instead of the first (which probably doesn't matter but would be an unintended behavior change).
Show 16 quoted lines
> + best_match = ref; > } > - return NULL; > + return best_match; > } > > struct ref *get_remote_ref(const struct ref *remote_refs, const char *name) > diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh > index e402aee6a..da88f35f0 100755 > --- a/t/t5510-fetch.sh > +++ b/t/t5510-fetch.sh > @@ -535,6 +535,34 @@ test_expect_success "should be able to fetch with duplicate refspecs" ' > ) > ' > > +test_expect_success 'LHS of refspec prefers exact matches' '
Nice.
With or without the suggested tweak,
Reviewed-by: Jonathan Nieder <jrnieder@gmail.com>
Thanks for a pleasant read.
Show 30 quoted lines
> + mkdir lhs-exact &&
> + (
> + cd lhs-exact &&
> + git init server &&
> + test_commit -C server unwanted &&
> + test_commit -C server wanted &&
> +
> + git init client &&
> +
> + # Check a name coming after "refs" alphabetically ...
> + git -C server update-ref refs/heads/s wanted &&
> + git -C server update-ref refs/heads/refs/heads/s unwanted &&
> + git -C client fetch ../server refs/heads/s:refs/heads/checkthis &&
> + git -C server rev-parse wanted >expect &&
> + git -C client rev-parse checkthis >actual &&
> + test_cmp expect actual &&
> +
> + # ... and one before.
> + git -C server update-ref refs/heads/q wanted &&
> + git -C server update-ref refs/heads/refs/heads/q unwanted &&
> + git -C client fetch ../server refs/heads/q:refs/heads/checkthis &&
> + git -C server rev-parse wanted >expect &&
> + git -C client rev-parse checkthis >actual &&
> + test_cmp expect actual
> + )
> +'
> +
> # configured prune tests
>
> set_config_tristate () {