Junio C Hamano [off-list ref] writes:
A naive and unoptimized implementation may look like this patch.
The "path_exclude_check" structure can be enhanced to record the
leading directory it has last checked to be known to be excluded so
that path_excluded() can check if the ce->name[] is still inside
that directory and return true early, but I'll leave it as an
exercise for interested readers while I look at other topics for the
upcoming release.
And an obvious and simple optimization would look like this.
We can keep the shallowest of the excluded directory (i.e. where a
traversing caller would have stopped recursing) in check->path, and
keep returning "Yes, it is excluded" as long as the path is inside
that directory.
builtin/ls-files.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 1385852..5beada0 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -218,11 +218,25 @@ static void path_exclude_check_clear(struct path_exclude_check *check)
strbuf_release(&check->path);
}
+/*
+ * Is the ce->name excluded? This is for a caller like show_files() that
+ * do not honor directory hierarchy and iterate through paths that are
+ * possibly in an ignored directory.
+ *
+ * A path to a directory known to be excluded is left in check->path to
+ * optimize for repeated checks for files in the same excluded directory.
+ */
static int path_excluded(struct path_exclude_check *check, struct cache_entry *ce)
{
int i, dtype;
struct strbuf *path = &check->path;
+ if (path->len &&
+ path->len <= ce_namelen(ce) &&
+ !memcmp(ce->name, path->buf, path->len) &&
+ (!ce->name[path->len] || ce->name[path->len] == '/'))
+ return 1;
+
strbuf_setlen(path, 0);
for (i = 0; ce->name[i]; i++) {
int ch = ce->name[i];@@ -234,6 +248,10 @@ static int path_excluded(struct path_exclude_check *check, struct cache_entry *c
}
strbuf_addch(path, ch);
}
+
+ /* An entry in the index; cannot be a directory with subentries */
+ strbuf_setlen(path, 0);
+
dtype = ce_to_dtype(ce);
return excluded(check->dir, ce->name, &dtype);
}