Stefan Beller <sbeller@xxxxxxxxxx> writes: > So how would we go about git_all_attrs then? I think you arrived the same conclusion, but the use of git_attr_check_elem[] in the original implementation of git_all_attrs() does not translate to the use of struct git_attr_check in the new world order we have been discussing. The latter is about "here are the attributes I want to know about", i.e. the question being asked and then we would need to separate out the answer from it to prepare for the threaded future. The question git_all_attrs() asks is quite different. The caller does not even know what set of attributes it is interested in, so if you ever want to allow more than one callers pass the same callsite to the function at the same time, they need their own copy of both <attr>s and <value>s. I'd expect they'd ask about a path and then receive an array of (<attr>,<value>). This is essentially what happens in today's "array of git_attr_check_elem[]" interface. That is fundamentally different from the normal use of git_check_attr(), where <attr>s are part of questions being asked. > int git_all_attrs(const char *path, char *result_keys[], char *result_values[], > int nr, int alloc) Or wrap each (<attr>,<value>) in a struct and return an array of it. I do not see a reason why the above cannot be struct { const struct git_attr *a; const char *v; } **git_all_attr(const char *path); which returns an array of struct's with an sentinel element at the end (e.g. the 'a' field set to NULL or something).