Rafael Ascensão <rafa.al...@gmail.com> writes:

> I agree that describe should receive the "normalize" treatment. However,
> and following the same reasoning, why should describe users adopt the
> rules imposed by --glob? I could argue they're also used to the way it
> works now.
>
> That being said, the suggestion I mentioned earlier would allow to keep
> both current behaviors consistent at the expense of the extra call to
> refs.c::ref_exists().

In any case, updating the "describe" for consistency is something we
can and should leave for later, to be done as a separate topic.

While I agree with you that the consistent behaviour between
commands is desirable, and also I agree with you that given a
pattern $X that does not have any glob char, trying to match $X when
a ref whose name exactly is $X exists and trying to match $X/*
otherwise would give us a consistent semantics without hurting any
existing uses, I do not think you need to pay any extra expense of
calling ref_exists() at all to achieve that.

That is because when $X exists, you already know $X/otherthing does
not exist.  And when $X does not exist, $X/otherthing might.  So a
naive implementation would be just to add two patterns $X and $X/*
to the filter list and be done with it.  If you exactly have
refs/heads/master, even with the naive logic may throw both
refs/heads/master and refs/heads/master/* to the filter list,
nothing will match the latter to contaminate your result (and vice
versa).

A bit more clever implementation "just throw in two items" would go
like this.  It is not all that involved:

 - In load_ref_decorations(), before running add_ref_decoration for
   each ref and head ref, iterate over the elements in the refname
   filter list.  For each element:

   - if item->string has a trailing '/', trim that.

   - store NULL in the item->util field for item whose string field
     has a glob char.

   - store something non-NULL (e.g. item->string) for item whose
     string field does not have a glob char.

 - In add_ref_decoration(), where your previous round iterates over
   filter->{include,exclude}, get rid of normalize_glob_ref() and
   use of real_pattern.  Instead do something like:

        matched = 0;
        if (item->util == NULL) {
                if (!wildmatch(item->string, refname, 0))
                        matched = 1;
        } else {
                const char *rest;
                if (skip_prefix(refname, item->string, &rest) &&
                    (!*rest || *rest == '/'))
                        matched = 1;
        }
        if (matched)
                ...

   Of course, you would probably want to encapsulate the logic to
   set matched = 1/0 in a helper function, e.g.

        static int match_ref_pattern(const char *refname,
                                     const struct string_list_item *item) {
                int matched = 0;
                ... do either wildmatch or head match with tail validation
                ... depending on the item->util's NULLness (see above)
                return matched;
        }

   and call that from the two loops for exclude and include list.

Hmm?

Reply via email to