--- I've been trying to think through how we could potentially add pathspec support for --recurse-submodule options (for builtins like ls-files or grep down the line). This is something that could be useful if the user supply's a pathspec that could match to a file in a submodule. We could match the submodule to the pathspec and then fork the process to recursively run the command on the submodule which can be passed a modified pathspec. For example with a pathspec 'sub/dir/a', where sub is a submodule in the root directory of the supermodule's repo, we could match 'sub' to that spec and then recursively call the git command with a pathspec of 'dir/a'. The child process would then have the responsibility of matching 'dir/a' to files in its repo. Does this seem like a reasonable feature to add? And if so are how is my initial approach at solving the problem? One idea I had was to add a submodule match flag in order to perform special matching just in the --recurse-submodules cases since we'll want somethings to match here that wouldn't normally match. @@ -283,6 +284,29 @@ static int match_pathspec_item(const struct pathspec_item *item, int prefix, item->nowildcard_len - prefix)) return MATCHED_FNMATCH; + /* + * Preform some checks to see if "name" is a super set of the pathspec + */ + if (flags & DO_MATCH_SUBMODULE) { + struct strbuf buf = STRBUF_INIT; + strbuf_addstr(&buf, name); + strbuf_addch(&buf, '/'); + /* + * Check if the name is a prefix of the pathspec + */ + if ((item->match[namelen] == '/') && + !ps_strncmp(item, match, name, namelen)) + return MATCHED_RECURSIVELY; + /* + * Check if the name wildmatches to the pathspec + */ + if (!wildmatch(item->match, buf.buf, + WM_PREFIX | + (item->magic & PATHSPEC_ICASE ? WM_CASEFOLD : 0), + NULL)); + return MATCHED_FNMATCH; + } + return 0; } One of the main difficulties I was having is figuring out how wildmatching should be applied in this case. What I believe we want is the ability for the whole name of the submodule to match a prefix of the pathspec pattern. To do this I was thinking of adding a flag to do prefix matching to the wildmatch function like so: diff --git a/wildmatch.c b/wildmatch.c index 57c8765..f1e1725 100644 --- a/wildmatch.c +++ b/wildmatch.c @@ -60,8 +60,12 @@ static int dowild(const uchar *p, const uchar *text, unsigned int flags) for ( ; (p_ch = *p) != '\0'; text++, p++) { int matched, match_slash, negated; uchar t_ch, prev_ch; - if ((t_ch = *text) == '\0' && p_ch != '*') - return WM_ABORT_ALL; + if ((t_ch = *text) == '\0' && p_ch != '*') { + if ((flags & WM_PREFIX) && (*(p-1) == '/')) + return WM_MATCH; + else + return WM_ABORT_ALL; + } if ((flags & WM_CASEFOLD) && ISUPPER(t_ch)) t_ch = tolower(t_ch); if ((flags & WM_CASEFOLD) && ISUPPER(p_ch)) diff --git a/wildmatch.h b/wildmatch.h index 4090c8f..490db51 100644 --- a/wildmatch.h +++ b/wildmatch.h @@ -3,6 +3,7 @@ #define WM_CASEFOLD 1 #define WM_PATHNAME 2 +#define WM_PREFIX 4 #define WM_ABORT_MALFORMED 2 #define WM_NOMATCH 1 -- Any comments or thoughts on this would be appreciated. Thanks, Brandon