The way match_pathspec_item() handles names and pathspecs with trailing slash characters, in conjunction with special options like DO_MATCH_DIRECTORY and DO_MATCH_LEADING_PATHSPEC were non-obvious, and broken until this patch series. Add a table in a comment explaining the intent of how these work. Signed-off-by: Elijah Newren <newren@xxxxxxxxx> --- dir.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/dir.c b/dir.c index 47c0a99cb5..3b2fe1701c 100644 --- a/dir.c +++ b/dir.c @@ -276,16 +276,27 @@ static int do_read_blob(const struct object_id *oid, struct oid_stat *oid_stat, #define DO_MATCH_LEADING_PATHSPEC (1<<2) /* - * Does 'match' match the given name? - * A match is found if + * Does the given pathspec match the given name? A match is found if * - * (1) the 'match' string is leading directory of 'name', or - * (2) the 'match' string is a wildcard and matches 'name', or - * (3) the 'match' string is exactly the same as 'name'. + * (1) the pathspec string is leading directory of 'name' ("RECURSIVELY"), or + * (2) the pathspec string has a leading part matching 'name' ("LEADING"), or + * (3) the pathspec string is a wildcard and matches 'name' ("WILDCARD"), or + * (4) the pathspec string is exactly the same as 'name' ("EXACT"). * - * and the return value tells which case it was. + * Return value tells which case it was (1-4), or 0 when there is no match. * - * It returns 0 when there is no match. + * It may be instructive to look at a small table of concrete examples + * to understand the differences between 1, 2, and 4: + * + * Pathspecs + * | a/b | a/b/ | a/b/c + * ------+-----------+-----------+------------ + * a/b | EXACT | EXACT[1] | LEADING[2] + * Names a/b/ | RECURSIVE | EXACT | LEADING[2] + * a/b/c | RECURSIVE | RECURSIVE | EXACT + * + * [1] Only if DO_MATCH_DIRECTORY is passed; otherwise, this is NOT a match. + * [2] Only if DO_MATCH_LEADING_PATHSPEC is passed; otherwise, not a match. */ static int match_pathspec_item(const struct index_state *istate, const struct pathspec_item *item, int prefix, @@ -353,7 +364,7 @@ static int match_pathspec_item(const struct index_state *istate, item->nowildcard_len - prefix)) return MATCHED_FNMATCH; - /* Perform checks to see if "name" is a super set of the pathspec */ + /* Perform checks to see if "name" is a leading string of the pathspec */ if (flags & DO_MATCH_LEADING_PATHSPEC) { /* name is a literal prefix of the pathspec */ int offset = name[namelen-1] == '/' ? 1 : 0; -- 2.22.1.17.g6e632477f7.dirty