On 03/09, Jonathan Tan wrote: > On 03/09/2017 01:07 PM, Brandon Williams wrote: > >diff --git a/Documentation/glossary-content.txt b/Documentation/glossary-content.txt > >index fc9320e59..5c32d1905 100644 > >--- a/Documentation/glossary-content.txt > >+++ b/Documentation/glossary-content.txt > >@@ -384,6 +384,26 @@ full pathname may have special meaning: > > + > > Glob magic is incompatible with literal magic. > > > >+attr;; > >+After `attr:` comes a space separated list of "attribute > >+requirements", all of which must be met in order for the > >+path to be considered a match; this is in addition to the > >+usual non-magic pathspec pattern matching. > >++ > >+Each of the attribute requirements for the path takes one of > >+these forms: > >+ > >+- "`ATTR`" requires that the attribute `ATTR` must be set. > > As a relative newcomer to attributes, I was confused by the fact > that "set" and "set to a value" is different (and likewise "unset" > and "unspecified"). Maybe it's worthwhile including a link to > "gitattributes" to explain the different (exclusive) states that an > attribute can be in. Good idea! I'll add in a link to gitattributes. > > >+ > >+- "`-ATTR`" requires that the attribute `ATTR` must be unset. > >+ > >+- "`ATTR=VALUE`" requires that the attribute `ATTR` must be > >+ set to the string `VALUE`. > >+ > >+- "`!ATTR`" requires that the attribute `ATTR` must be > >+ unspecified. > > It would read better to me if you omitted "must" in all 4 bullet > points (and it is redundant anyway with "requires"), but I don't > feel too strongly about this. I agree, the first paragraph already says "must" so it reads better without repeating must over and over again. > > >diff --git a/pathspec.c b/pathspec.c > >index b961f00c8..583ed5208 100644 > >--- a/pathspec.c > >+++ b/pathspec.c > >@@ -87,6 +89,72 @@ static void prefix_magic(struct strbuf *sb, int prefixlen, unsigned magic) > > strbuf_addf(sb, ",prefix:%d)", prefixlen); > > } > > > >+static void parse_pathspec_attr_match(struct pathspec_item *item, const char *value) > >+{ > >+ struct string_list_item *si; > >+ struct string_list list = STRING_LIST_INIT_DUP; > >+ > >+ if (item->attr_check) > >+ die(_("Only one 'attr:' specification is allowed.")); > >+ > >+ if (!value || !strlen(value)) > > You can write `!*value` instead of `!strlen(value)`. > Done. > >+ string_list_remove_empty_items(&list, 0); > >+ > >+ item->attr_check = attr_check_alloc(); > >+ ALLOC_GROW(item->attr_match, > >+ item->attr_match_nr + list.nr, > >+ item->attr_match_alloc); > > Is there a time when this function is called while > item->attr_match_nr is not zero? Nope, it pretty much has to be zero. I'll change this to just use list.nr. item->attr_match_nr will be incremented up to list.nr over the course of the for loop and I'll move the equality check to the end of this function. > >+ string_list_clear(&list, 0); > >+ return; > > Redundant return? I'll remove it. > > >@@ -544,6 +628,10 @@ void parse_pathspec(struct pathspec *pathspec, > > if (item[i].nowildcard_len < item[i].len) > > pathspec->has_wildcard = 1; > > pathspec->magic |= item[i].magic; > >+ > >+ if (item[i].attr_check && > >+ item[i].attr_check->nr != item[i].attr_match_nr) > >+ die("BUG: should have same number of entries"); > > I'm not sure if this check is giving us any benefit - I would expect > this type of code before some other code that assumed that the > numbers matched, and that will potentially segfault if not. I'll push the check to right after the object creation (see comment above). -- Brandon Williams