Rafael Ascensão <[email protected]> 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?