In our own .gitattributes file we have attributes such as: *.[ch] whitespace=indent,trail,space When querying for attributes we want to be able to ask for the exact value, i.e. git ls-files :(attr:whitespace=indent,trail,space) should work, but the commas are used in the attr magic to introduce the next attr, such that this query currently fails with fatal: Invalid pathspec magic 'trail' in ':(attr:whitespace=indent,trail,space)' This change allows escaping characters by a backslash, such that the query git ls-files :(attr:whitespace=indent\,trail\,space) will match all path that have the value "indent,trail,space" for the whitespace attribute. To accomplish this, we need to modify two places. First `eat_long_magic` needs to not stop early upon seeing a comma or closing paren that is escaped. As a second step we need to remove any escaping from the attr value. For now we just remove any backslashes. Caveat: This doesn't allow for querying for values that have backslashes in them, e.g. git ls-files :(attr:backslashes=\\) that would ask for matches that have the `backslashes` value set to '\'. Signed-off-by: Stefan Beller <sbeller@xxxxxxxxxx> --- * This applies on top of sb/pathspec-label * Junio does this come close to what you imagine for escaped commas? Thanks, Stefan pathspec.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/pathspec.c b/pathspec.c index 0a02255..925f949 100644 --- a/pathspec.c +++ b/pathspec.c @@ -89,6 +89,22 @@ static void prefix_short_magic(struct strbuf *sb, int prefixlen, strbuf_addf(sb, ",prefix:%d)", prefixlen); } +static char *attr_value_unquote(const char *value) +{ + char *ret = xstrdup(value); + + size_t value_len = strlen(ret); + size_t len = strcspn(ret, "\\"); + + while (len != value_len) { + memmove(ret + len, ret + len + 1, value_len - len); + value_len--; + len += strcspn(ret + len, "\\"); + } + + return ret; +} + static void parse_pathspec_attr_match(struct pathspec_item *item, const char *value) { struct string_list_item *si; @@ -132,7 +148,7 @@ static void parse_pathspec_attr_match(struct pathspec_item *item, const char *va am->match_mode = MATCH_SET; else { am->match_mode = MATCH_VALUE; - am->value = xstrdup(&attr[attr_len + 1]); + am->value = attr_value_unquote(&attr[attr_len + 1]); if (strchr(am->value, '\\')) die(_("attr spec values must not contain backslashes")); } @@ -167,6 +183,9 @@ static void eat_long_magic(struct pathspec_item *item, const char *elt, *copyfrom && *copyfrom != ')'; copyfrom = nextat) { size_t len = strcspn(copyfrom, ",)"); + while (len > 0 && copyfrom[len - 1] == '\\' + && (copyfrom[len] == ',' || copyfrom[len] == ')')) + len += strcspn(copyfrom + len + 1, ",)") + 1; if (copyfrom[len] == ',') nextat = copyfrom + len + 1; else -- 2.8.2.124.g24a9db3 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html