> I dunno. This is why I submitted the initial patch as the simplest fix. ;) > The first patch is Reviewed-by: Stefan Beller <sbeller@xxxxxxxxxx> Diffing across both patches, this seems to be the relevant part: ---8<--- @@ -1111,14 +1116,13 @@ static void collect_some_attrs(const struct index_state *istate, prepare_attr_stack(istate, path, dirlen, &check->stack); all_attrs_init(&g_attr_hashmap, check); - determine_macros(check->all_attrs, check->stack); if (check->nr) { rem = 0; for (i = 0; i < check->nr; i++) { int n = check->items[i].attr->attr_nr; struct all_attrs_item *item = &check->all_attrs[n]; - if (item->macro) { + if (!item->attr->in_stack) { item->value = ATTR__UNSET; rem++; } @@ -1127,6 +1131,8 @@ static void collect_some_attrs(const struct index_state *istate, return; } + determine_macros(check->all_attrs, check->stack); + rem = check->all_attrs_nr; fill(path, pathlen, basename_offset, check->stack, check->all_attrs, rem); } ---8<--- which I think is correct. Maybe we could refactor the big condition (if (check->nr)) to be its own function and have if (!check_overlaps_all_attrs(check)) return; instead. The function would allow for a natural place to put a comment convincing us why the optimisation works as expected. :-) And after rereading that code, the optimisation checks if any of the requested attributes in 'check' are touched in all_attrs, which sounds like a natural optimisation when we assume that filling in the actual values take a lot of time as the stack of attribute files might be large. I think this patch is correct, too. Stefan