@@ -2668,13 +2668,33 @@ static void set_untracked_ident(struct untracked_cache *uc)
strbuf_addch(&uc->ident, 0);
}
-static void new_untracked_cache(struct index_state *istate)
+static unsigned configured_default_dir_flags(struct index_state *istate)
+{
+ /* This logic is coordinated with the setting of these flags in
+ * wt-status.c#wt_status_collect_untracked(), and the evaluation
+ * of the config setting in commit.c#git_status_config()
+ */
+ char *status_untracked_files_config_value;
+ int config_outcome = repo_config_get_string(istate->repo,
+ "status.showuntrackedfiles",
+ &status_untracked_files_config_value);
+ if (!config_outcome && !strcmp(status_untracked_files_config_value, "all")) {
+ return 0;
+ } else {
+ /*
+ * The default, if "all" is not set, is "normal" - leading us here.
+ * If the value is "none" then it really doesn't matter.
+ */
+ return DIR_SHOW_OTHER_DIRECTORIES | DIR_HIDE_EMPTY_DIRECTORIES;
+ }
+}
+
+static void new_untracked_cache(struct index_state *istate, unsigned flags)
{
struct untracked_cache *uc = xcalloc(1, sizeof(*uc));
strbuf_init(&uc->ident, 100);
uc->exclude_per_dir = ".gitignore";
- /* should be the same flags used by git-status */
- uc->dir_flags = DIR_SHOW_OTHER_DIRECTORIES | DIR_HIDE_EMPTY_DIRECTORIES;
+ uc->dir_flags = flags;
set_untracked_ident(uc);
istate->untracked = uc;
istate->cache_changed |= UNTRACKED_CHANGED;
@@ -2683,11 +2703,13 @@ static void new_untracked_cache(struct index_state *istate)
void add_untracked_cache(struct index_state *istate)
{
if (!istate->untracked) {
- new_untracked_cache(istate);
+ new_untracked_cache(istate,
+ configured_default_dir_flags(istate));
} else {
if (!ident_in_untracked(istate->untracked)) {
free_untracked_cache(istate->untracked);
- new_untracked_cache(istate);
+ new_untracked_cache(istate,
+ configured_default_dir_flags(istate));
}
}
}
@@ -2703,10 +2725,12 @@ void remove_untracked_cache(struct index_state *istate)
static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *dir,
int base_len,
- const struct pathspec *pathspec)
+ const struct pathspec *pathspec,
+ struct index_state *istate)
{
struct untracked_cache_dir *root;
static int untracked_cache_disabled = -1;
+ unsigned configured_dir_flags;
if (!dir->untracked)
return NULL;
@@ -2734,17 +2758,9 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d
if (base_len || (pathspec && pathspec->nr))
return NULL;
- /* Different set of flags may produce different results */
- if (dir->flags != dir->untracked->dir_flags ||
- /*
- * See treat_directory(), case index_nonexistent. Without
- * this flag, we may need to also cache .git file content
- * for the resolve_gitlink_ref() call, which we don't.
- */
- !(dir->flags & DIR_SHOW_OTHER_DIRECTORIES) ||
- /* We don't support collecting ignore files */
- (dir->flags & (DIR_SHOW_IGNORED | DIR_SHOW_IGNORED_TOO |
- DIR_COLLECT_IGNORED)))
+ /* We don't support collecting ignore files */
+ if (dir->flags & (DIR_SHOW_IGNORED | DIR_SHOW_IGNORED_TOO |
+ DIR_COLLECT_IGNORED))
return NULL;
/*
@@ -2767,6 +2783,40 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d
return NULL;
}
+ /* We don't support using or preparing the untracked cache if
+ * the current effective flags don't match the configured
+ * flags.
+ */
+ configured_dir_flags = configured_default_dir_flags(istate);
+ if (dir->flags != configured_dir_flags)
+ return NULL;
+
+ /* If the untracked structure we received does not have the same flags
+ * as configured, but the configured flags do match the effective flags,
+ * then we need to reset / create a new "untracked" structure to match
+ * the new config.
+ * Keeping the saved and used untracked cache in-line with the
+ * configuration provides an opportunity for frequent users of
+ * "git status -uall" to leverage the untracked cache by aligning their
+ * configuration (setting "status.showuntrackedfiles" to "all" or
+ * "normal" as appropriate), where previously this option was
+ * incompatible with untracked cache and *consistently* caused
+ * surprisingly bad performance (with fscache and fsmonitor enabled) on
+ * Windows.
+ *
+ * IMPROVEMENT OPPORTUNITY: If we reworked the untracked cache storage
+ * to not be as bound up with the desired output in a given run,
+ * and instead iterated through and stored enough information to
+ * correctly serve both "modes", then users could get peak performance
+ * with or without '-uall' regardless of their
+ * "status.showuntrackedfiles" config.
+ */
+ if (dir->flags != dir->untracked->dir_flags) {
+ free_untracked_cache(istate->untracked);
+ new_untracked_cache(istate, configured_dir_flags);
+ dir->untracked = istate->untracked;
+ }
+
if (!dir->untracked->root)
FLEX_ALLOC_STR(dir->untracked->root, name, "");
@@ -2838,7 +2888,7 @@ int read_directory(struct dir_struct *dir, struct index_state *istate,
return dir->nr;
}
- untracked = validate_untracked_cache(dir, len, pathspec);
+ untracked = validate_untracked_cache(dir, len, pathspec, istate);
if (!untracked)
/*
* make sure untracked cache code path is disabled,