summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2020-02-21 02:06:04 (GMT)
committerJunio C Hamano <gitster@pobox.com>2020-02-21 02:06:04 (GMT)
commit955222297822121e877d7efdc0d5945fc451afe7 (patch)
tree2959150027b12bd5e8a2a6725063107e612343f9
parentfcb202e227a2cb8d549026e6ea2a0ef33fdb1ac3 (diff)
parent79cfcce06abb81e3858ecbc22441f0ac542b626e (diff)
downloadgit-955222297822121e877d7efdc0d5945fc451afe7.zip
git-955222297822121e877d7efdc0d5945fc451afe7.tar.gz
git-955222297822121e877d7efdc0d5945fc451afe7.tar.bz2
Merge branch 'en/fill-directory-exponential' into pu
The directory traversal code had redundant recursive calls which made its performance characteristics exponential wrt the depth of the tree, which was corrected. * en/fill-directory-exponential: t7063: blindly accept diffs dir: replace exponential algorithm with a linear one dir: refactor treat_directory to clarify control flow dir: fix confusion based on variable tense dir: fix broken comment dir: consolidate treat_path() and treat_one_path()
-rw-r--r--dir.c331
-rwxr-xr-xt/t7063-status-untracked-cache.sh50
2 files changed, 208 insertions, 173 deletions
diff --git a/dir.c b/dir.c
index 0ffb1b3..919e83a 100644
--- a/dir.c
+++ b/dir.c
@@ -1727,36 +1727,41 @@ static enum exist_status directory_exists_in_index(struct index_state *istate,
static enum path_treatment treat_directory(struct dir_struct *dir,
struct index_state *istate,
struct untracked_cache_dir *untracked,
- const char *dirname, int len, int baselen, int exclude,
+ const char *dirname, int len, int baselen, int excluded,
const struct pathspec *pathspec)
{
- int nested_repo = 0;
-
+ /*
+ * WARNING: From this function, you can return path_recurse or you
+ * can call read_directory_recursive() (or neither), but
+ * you CAN'T DO BOTH.
+ */
+ enum path_treatment state;
+ int nested_repo = 0, old_ignored_nr, stop_early;
/* The "len-1" is to strip the final '/' */
- switch (directory_exists_in_index(istate, dirname, len-1)) {
- case index_directory:
- return path_recurse;
+ enum exist_status status = directory_exists_in_index(istate, dirname, len-1);
- case index_gitdir:
+ if (status == index_directory)
+ return path_recurse;
+ if (status == index_gitdir)
return path_none;
-
- case index_nonexistent:
- if ((dir->flags & DIR_SKIP_NESTED_GIT) ||
- !(dir->flags & DIR_NO_GITLINKS)) {
- struct strbuf sb = STRBUF_INIT;
- strbuf_addstr(&sb, dirname);
- nested_repo = is_nonbare_repository_dir(&sb);
- strbuf_release(&sb);
- }
- if (nested_repo)
- return ((dir->flags & DIR_SKIP_NESTED_GIT) ? path_none :
- (exclude ? path_excluded : path_untracked));
-
- if (dir->flags & DIR_SHOW_OTHER_DIRECTORIES)
- break;
- if (exclude &&
- (dir->flags & DIR_SHOW_IGNORED_TOO) &&
- (dir->flags & DIR_SHOW_IGNORED_TOO_MODE_MATCHING)) {
+ if (status != index_nonexistent)
+ BUG("Unhandled value for directory_exists_in_index: %d\n", status);
+
+ if ((dir->flags & DIR_SKIP_NESTED_GIT) ||
+ !(dir->flags & DIR_NO_GITLINKS)) {
+ struct strbuf sb = STRBUF_INIT;
+ strbuf_addstr(&sb, dirname);
+ nested_repo = is_nonbare_repository_dir(&sb);
+ strbuf_release(&sb);
+ }
+ if (nested_repo)
+ return ((dir->flags & DIR_SKIP_NESTED_GIT) ? path_none :
+ (excluded ? path_excluded : path_untracked));
+
+ if (!(dir->flags & DIR_SHOW_OTHER_DIRECTORIES)) {
+ if (excluded &&
+ (dir->flags & DIR_SHOW_IGNORED_TOO) &&
+ (dir->flags & DIR_SHOW_IGNORED_TOO_MODE_MATCHING)) {
/*
* This is an excluded directory and we are
@@ -1783,18 +1788,101 @@ static enum path_treatment treat_directory(struct dir_struct *dir,
/* This is the "show_other_directories" case */
- if (!(dir->flags & DIR_HIDE_EMPTY_DIRECTORIES))
- return exclude ? path_excluded : path_untracked;
+ /*
+ * We only need to recurse into untracked/ignored directories if
+ * either of the following bits is set:
+ * - DIR_SHOW_IGNORED_TOO (because then we need to determine if
+ * there are ignored directories below)
+ * - DIR_HIDE_EMPTY_DIRECTORIES (because we have to determine if
+ * the directory is empty)
+ */
+ if (!(dir->flags & (DIR_SHOW_IGNORED_TOO | DIR_HIDE_EMPTY_DIRECTORIES)))
+ return excluded ? path_excluded : path_untracked;
+
+ /*
+ * If we only want to determine if dirname is empty, then we can
+ * stop at the first file we find underneath that directory rather
+ * than continuing to recurse beyond it. If DIR_SHOW_IGNORED_TOO
+ * is set, then we want MORE than just determining if dirname is
+ * empty.
+ */
+ stop_early = ((dir->flags & DIR_HIDE_EMPTY_DIRECTORIES) &&
+ !(dir->flags & DIR_SHOW_IGNORED_TOO));
+
+ /*
+ * If /every/ file within an untracked directory is ignored, then
+ * we want to treat the directory as ignored (for e.g. status
+ * --porcelain), without listing the individual ignored files
+ * underneath. To do so, we'll save the current ignored_nr, and
+ * pop all the ones added after it if it turns out the entire
+ * directory is ignored.
+ */
+ old_ignored_nr = dir->ignored_nr;
+ /* Actually recurse into dirname now, we'll fixup the state later. */
untracked = lookup_untracked(dir->untracked, untracked,
dirname + baselen, len - baselen);
+ state = read_directory_recursive(dir, istate, dirname, len, untracked,
+ stop_early, stop_early, pathspec);
+
+ /* There are a variety of reasons we may need to fixup the state... */
+ if (state == path_excluded) {
+ int i;
+
+ /*
+ * When stop_early is set, read_directory_recursive() will
+ * never return path_untracked regardless of whether
+ * underlying paths were untracked or ignored (because
+ * returning early means it excluded some paths, or
+ * something like that -- see commit 5aaa7fd39aaf ("Improve
+ * performance of git status --ignored", 2017-09-18)).
+ * However, we're not really concerned with the status of
+ * files under the directory, we just wanted to know
+ * whether the directory was empty (state == path_none) or
+ * not (state == path_excluded), and if not, we'd return
+ * our original status based on whether the untracked
+ * directory matched an exclusion pattern.
+ */
+ if (stop_early)
+ state = excluded ? path_excluded : path_untracked;
+
+ else {
+ /*
+ * When
+ * !stop_early && state == path_excluded
+ * then all paths under dirname were ignored. For
+ * this case, git status --porcelain wants to just
+ * list the directory itself as ignored and not
+ * list the individual paths underneath. Remove
+ * the individual paths underneath.
+ */
+ for (i = old_ignored_nr + 1; i<dir->ignored_nr; ++i)
+ free(dir->ignored[i]);
+ dir->ignored_nr = old_ignored_nr;
+ }
+ }
/*
- * If this is an excluded directory, then we only need to check if
- * the directory contains any files.
+ * If there is nothing under the current directory and we are not
+ * hiding empty directories, then we need to report on the
+ * untracked or ignored status of the directory itself.
*/
- return read_directory_recursive(dir, istate, dirname, len,
- untracked, 1, exclude, pathspec);
+ if (state == path_none && !(dir->flags & DIR_HIDE_EMPTY_DIRECTORIES))
+ state = excluded ? path_excluded : path_untracked;
+
+ /*
+ * We can recurse into untracked directories that don't match any
+ * of the given pathspecs when some file underneath the directory
+ * might match one of the pathspecs. If so, we should make sure
+ * to note that the directory itself did not match.
+ */
+ if (pathspec &&
+ !match_pathspec(istate, pathspec, dirname, len,
+ 0 /* prefix */, NULL,
+ 0 /* do NOT special case dirs */))
+ state = path_none;
+
+ return state;
}
/*
@@ -1934,21 +2022,70 @@ static int resolve_dtype(int dtype, struct index_state *istate,
return dtype;
}
-static enum path_treatment treat_one_path(struct dir_struct *dir,
- struct untracked_cache_dir *untracked,
- struct index_state *istate,
- struct strbuf *path,
- int baselen,
- const struct pathspec *pathspec,
- int dtype)
+static enum path_treatment treat_path_fast(struct dir_struct *dir,
+ struct untracked_cache_dir *untracked,
+ struct cached_dir *cdir,
+ struct index_state *istate,
+ struct strbuf *path,
+ int baselen,
+ const struct pathspec *pathspec)
+{
+ /*
+ * WARNING: From this function, you can return path_recurse or you
+ * can call read_directory_recursive() (or neither), but
+ * you CAN'T DO BOTH.
+ */
+ strbuf_setlen(path, baselen);
+ if (!cdir->ucd) {
+ strbuf_addstr(path, cdir->file);
+ return path_untracked;
+ }
+ strbuf_addstr(path, cdir->ucd->name);
+ /* treat_one_path() does this before it calls treat_directory() */
+ strbuf_complete(path, '/');
+ if (cdir->ucd->check_only)
+ /*
+ * check_only is set as a result of treat_directory() getting
+ * to its bottom. Verify again the same set of directories
+ * with check_only set.
+ */
+ return read_directory_recursive(dir, istate, path->buf, path->len,
+ cdir->ucd, 1, 0, pathspec);
+ /*
+ * We get path_recurse in the first run when
+ * directory_exists_in_index() returns index_nonexistent. We
+ * are sure that new changes in the index does not impact the
+ * outcome. Return now.
+ */
+ return path_recurse;
+}
+
+static enum path_treatment treat_path(struct dir_struct *dir,
+ struct untracked_cache_dir *untracked,
+ struct cached_dir *cdir,
+ struct index_state *istate,
+ struct strbuf *path,
+ int baselen,
+ const struct pathspec *pathspec)
{
- int exclude;
- int has_path_in_index = !!index_file_exists(istate, path->buf, path->len, ignore_case);
+ int has_path_in_index, dtype, excluded;
enum path_treatment path_treatment;
- dtype = resolve_dtype(dtype, istate, path->buf, path->len);
+ if (!cdir->d_name)
+ return treat_path_fast(dir, untracked, cdir, istate, path,
+ baselen, pathspec);
+ if (is_dot_or_dotdot(cdir->d_name) || !fspathcmp(cdir->d_name, ".git"))
+ return path_none;
+ strbuf_setlen(path, baselen);
+ strbuf_addstr(path, cdir->d_name);
+ if (simplify_away(path->buf, path->len, pathspec))
+ return path_none;
+
+ dtype = resolve_dtype(cdir->d_type, istate, path->buf, path->len);
/* Always exclude indexed files */
+ has_path_in_index = !!index_file_exists(istate, path->buf, path->len,
+ ignore_case);
if (dtype != DT_DIR && has_path_in_index)
return path_none;
@@ -1976,13 +2113,13 @@ static enum path_treatment treat_one_path(struct dir_struct *dir,
(directory_exists_in_index(istate, path->buf, path->len) == index_nonexistent))
return path_none;
- exclude = is_excluded(dir, istate, path->buf, &dtype);
+ excluded = is_excluded(dir, istate, path->buf, &dtype);
/*
* Excluded? If we don't explicitly want to show
* ignored files, ignore it
*/
- if (exclude && !(dir->flags & (DIR_SHOW_IGNORED|DIR_SHOW_IGNORED_TOO)))
+ if (excluded && !(dir->flags & (DIR_SHOW_IGNORED|DIR_SHOW_IGNORED_TOO)))
return path_excluded;
switch (dtype) {
@@ -1992,7 +2129,7 @@ static enum path_treatment treat_one_path(struct dir_struct *dir,
strbuf_addch(path, '/');
path_treatment = treat_directory(dir, istate, untracked,
path->buf, path->len,
- baselen, exclude, pathspec);
+ baselen, excluded, pathspec);
/*
* If 1) we only want to return directories that
* match an exclude pattern and 2) this directory does
@@ -2001,7 +2138,7 @@ static enum path_treatment treat_one_path(struct dir_struct *dir,
* recurse into this directory (instead of marking the
* directory itself as an ignored path).
*/
- if (!exclude &&
+ if (!excluded &&
path_treatment == path_excluded &&
(dir->flags & DIR_SHOW_IGNORED_TOO) &&
(dir->flags & DIR_SHOW_IGNORED_TOO_MODE_MATCHING))
@@ -2009,65 +2146,10 @@ static enum path_treatment treat_one_path(struct dir_struct *dir,
return path_treatment;
case DT_REG:
case DT_LNK:
- return exclude ? path_excluded : path_untracked;
+ return excluded ? path_excluded : path_untracked;
}
}
-static enum path_treatment treat_path_fast(struct dir_struct *dir,
- struct untracked_cache_dir *untracked,
- struct cached_dir *cdir,
- struct index_state *istate,
- struct strbuf *path,
- int baselen,
- const struct pathspec *pathspec)
-{
- strbuf_setlen(path, baselen);
- if (!cdir->ucd) {
- strbuf_addstr(path, cdir->file);
- return path_untracked;
- }
- strbuf_addstr(path, cdir->ucd->name);
- /* treat_one_path() does this before it calls treat_directory() */
- strbuf_complete(path, '/');
- if (cdir->ucd->check_only)
- /*
- * check_only is set as a result of treat_directory() getting
- * to its bottom. Verify again the same set of directories
- * with check_only set.
- */
- return read_directory_recursive(dir, istate, path->buf, path->len,
- cdir->ucd, 1, 0, pathspec);
- /*
- * We get path_recurse in the first run when
- * directory_exists_in_index() returns index_nonexistent. We
- * are sure that new changes in the index does not impact the
- * outcome. Return now.
- */
- return path_recurse;
-}
-
-static enum path_treatment treat_path(struct dir_struct *dir,
- struct untracked_cache_dir *untracked,
- struct cached_dir *cdir,
- struct index_state *istate,
- struct strbuf *path,
- int baselen,
- const struct pathspec *pathspec)
-{
- if (!cdir->d_name)
- return treat_path_fast(dir, untracked, cdir, istate, path,
- baselen, pathspec);
- if (is_dot_or_dotdot(cdir->d_name) || !fspathcmp(cdir->d_name, ".git"))
- return path_none;
- strbuf_setlen(path, baselen);
- strbuf_addstr(path, cdir->d_name);
- if (simplify_away(path->buf, path->len, pathspec))
- return path_none;
-
- return treat_one_path(dir, untracked, istate, path, baselen, pathspec,
- cdir->d_type);
-}
-
static void add_untracked(struct untracked_cache_dir *dir, const char *name)
{
if (!dir)
@@ -2258,14 +2340,10 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir,
int stop_at_first_file, const struct pathspec *pathspec)
{
/*
- * WARNING WARNING WARNING:
- *
- * Any updates to the traversal logic here may need corresponding
- * updates in treat_leading_path(). See the commit message for the
- * commit adding this warning as well as the commit preceding it
- * for details.
+ * WARNING: Do NOT recurse unless path_recurse is returned from
+ * treat_path(). Recursing on any other return value
+ * can result in exponential slowdown.
*/
-
struct cached_dir cdir;
enum path_treatment state, subdir_state, dir_state = path_none;
struct strbuf path = STRBUF_INIT;
@@ -2287,13 +2365,7 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir,
dir_state = state;
/* recurse into subdir if instructed by treat_path */
- if ((state == path_recurse) ||
- ((state == path_untracked) &&
- (resolve_dtype(cdir.d_type, istate, path.buf, path.len) == DT_DIR) &&
- ((dir->flags & DIR_SHOW_IGNORED_TOO) ||
- (pathspec &&
- do_match_pathspec(istate, pathspec, path.buf, path.len,
- baselen, NULL, DO_MATCH_LEADING_PATHSPEC) == MATCHED_RECURSIVELY_LEADING_PATHSPEC)))) {
+ if (state == path_recurse) {
struct untracked_cache_dir *ud;
ud = lookup_untracked(dir->untracked, untracked,
path.buf + baselen,
@@ -2341,7 +2413,7 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir,
add_untracked(untracked, path.buf + baselen);
break;
}
- /* skip the dir_add_* part */
+ /* skip the add_path_to_appropriate_result_list() */
continue;
}
@@ -2377,15 +2449,6 @@ static int treat_leading_path(struct dir_struct *dir,
const char *path, int len,
const struct pathspec *pathspec)
{
- /*
- * WARNING WARNING WARNING:
- *
- * Any updates to the traversal logic here may need corresponding
- * updates in read_directory_recursive(). See 777b420347 (dir:
- * synchronize treat_leading_path() and read_directory_recursive(),
- * 2019-12-19) and its parent commit for details.
- */
-
struct strbuf sb = STRBUF_INIT;
struct strbuf subdir = STRBUF_INIT;
int prevlen, baselen;
@@ -2436,23 +2499,7 @@ static int treat_leading_path(struct dir_struct *dir,
strbuf_reset(&subdir);
strbuf_add(&subdir, path+prevlen, baselen-prevlen);
cdir.d_name = subdir.buf;
- state = treat_path(dir, NULL, &cdir, istate, &sb, prevlen,
- pathspec);
- if (state == path_untracked &&
- resolve_dtype(cdir.d_type, istate, sb.buf, sb.len) == DT_DIR &&
- (dir->flags & DIR_SHOW_IGNORED_TOO ||
- do_match_pathspec(istate, pathspec, sb.buf, sb.len,
- baselen, NULL, DO_MATCH_LEADING_PATHSPEC) == MATCHED_RECURSIVELY_LEADING_PATHSPEC)) {
- if (!match_pathspec(istate, pathspec, sb.buf, sb.len,
- 0 /* prefix */, NULL,
- 0 /* do NOT special case dirs */))
- state = path_none;
- add_path_to_appropriate_result_list(dir, NULL, &cdir,
- istate,
- &sb, baselen,
- pathspec, state);
- state = path_recurse;
- }
+ state = treat_path(dir, NULL, &cdir, istate, &sb, prevlen, pathspec);
if (state != path_recurse)
break; /* do not recurse into it */
diff --git a/t/t7063-status-untracked-cache.sh b/t/t7063-status-untracked-cache.sh
index 190ae14..c1b0fd0 100755
--- a/t/t7063-status-untracked-cache.sh
+++ b/t/t7063-status-untracked-cache.sh
@@ -85,9 +85,7 @@ dtwo/
three
/done/ 0000000000000000000000000000000000000000 recurse valid
/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
-three
/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
-two
EOF
test_expect_success 'status first time (empty cache)' '
@@ -140,8 +138,6 @@ test_expect_success 'modify in root directory, one dir invalidation' '
A done/one
A one
A two
-?? dthree/
-?? dtwo/
?? four
?? three
EOF
@@ -164,15 +160,11 @@ core.excludesfile 0000000000000000000000000000000000000000
exclude_per_dir .gitignore
flags 00000006
/ 0000000000000000000000000000000000000000 recurse valid
-dthree/
-dtwo/
four
three
/done/ 0000000000000000000000000000000000000000 recurse valid
/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
-three
/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
-two
EOF
test_cmp ../expect ../actual
'
@@ -217,9 +209,7 @@ dtwo/
three
/done/ 0000000000000000000000000000000000000000 recurse valid
/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
-three
/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
-two
EOF
test_cmp ../expect ../actual
'
@@ -235,6 +225,7 @@ A done/one
A one
A two
?? .gitignore
+?? dthree/
?? dtwo/
EOF
test_cmp ../status.expect ../actual &&
@@ -256,11 +247,11 @@ exclude_per_dir .gitignore
flags 00000006
/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
.gitignore
+dthree/
dtwo/
/done/ 0000000000000000000000000000000000000000 recurse valid
/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
-two
EOF
test_cmp ../expect ../actual
'
@@ -277,7 +268,6 @@ flags 00000006
/done/ 0000000000000000000000000000000000000000 recurse valid
/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
-two
EOF
test_cmp ../expect ../actual
'
@@ -290,7 +280,6 @@ test_expect_success 'status after the move' '
A done/one
A one
?? .gitignore
-?? dtwo/
?? two
EOF
test_cmp ../status.expect ../actual &&
@@ -312,12 +301,10 @@ exclude_per_dir .gitignore
flags 00000006
/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
.gitignore
-dtwo/
two
/done/ 0000000000000000000000000000000000000000 recurse valid
/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
-two
EOF
test_cmp ../expect ../actual
'
@@ -334,7 +321,6 @@ flags 00000006
/done/ 0000000000000000000000000000000000000000 recurse valid
/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
-two
EOF
test_cmp ../expect ../actual
'
@@ -348,7 +334,6 @@ A done/one
A one
A two
?? .gitignore
-?? dtwo/
EOF
test_cmp ../status.expect ../actual &&
cat >../trace.expect <<EOF &&
@@ -369,11 +354,9 @@ exclude_per_dir .gitignore
flags 00000006
/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
.gitignore
-dtwo/
/done/ 0000000000000000000000000000000000000000 recurse valid
/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
-two
EOF
test_cmp ../expect ../actual
'
@@ -392,7 +375,6 @@ test_expect_success 'status after commit' '
git status --porcelain >../actual &&
cat >../status.expect <<EOF &&
?? .gitignore
-?? dtwo/
EOF
test_cmp ../status.expect ../actual &&
cat >../trace.expect <<EOF &&
@@ -413,11 +395,9 @@ exclude_per_dir .gitignore
flags 00000006
/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
.gitignore
-dtwo/
/done/ 0000000000000000000000000000000000000000 recurse valid
/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
-two
EOF
test_cmp ../expect ../actual
'
@@ -451,7 +431,6 @@ test_expect_success 'test sparse status with untracked cache' '
M done/two
?? .gitignore
?? done/five
-?? dtwo/
EOF
test_cmp ../status.expect ../status.actual &&
cat >../trace.expect <<EOF &&
@@ -472,12 +451,10 @@ exclude_per_dir .gitignore
flags 00000006
/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
.gitignore
-dtwo/
/done/ 1946f0437f90c5005533cbe1736a6451ca301714 recurse valid
five
/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
-two
EOF
test_cmp ../expect ../actual
'
@@ -491,7 +468,6 @@ test_expect_success 'test sparse status again with untracked cache' '
M done/two
?? .gitignore
?? done/five
-?? dtwo/
EOF
test_cmp ../status.expect ../status.actual &&
cat >../trace.expect <<EOF &&
@@ -519,7 +495,6 @@ test_expect_success 'test sparse status with untracked cache and subdir' '
?? .gitignore
?? done/five
?? done/sub/
-?? dtwo/
EOF
test_cmp ../status.expect ../status.actual &&
cat >../trace.expect <<EOF &&
@@ -540,17 +515,13 @@ exclude_per_dir .gitignore
flags 00000006
/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
.gitignore
-dtwo/
/done/ 1946f0437f90c5005533cbe1736a6451ca301714 recurse valid
five
sub/
/done/sub/ 0000000000000000000000000000000000000000 recurse check_only valid
-sub/
/done/sub/sub/ 0000000000000000000000000000000000000000 recurse check_only valid
-file
/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
-two
EOF
test_cmp ../expect-from-test-dump ../actual
'
@@ -615,6 +586,23 @@ test_expect_success 'setting core.untrackedCache to true and using git status cr
test_cmp ../expect-no-uc ../actual &&
git status &&
test-tool dump-untracked-cache >../actual &&
+ cat >../expect-from-test-dump <<EOF &&
+info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
+core.excludesfile 0000000000000000000000000000000000000000
+exclude_per_dir .gitignore
+flags 00000006
+/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
+.gitignore
+dthree/
+dtwo/
+/done/ 1946f0437f90c5005533cbe1736a6451ca301714 recurse valid
+five
+sub/
+/done/sub/ 0000000000000000000000000000000000000000 recurse check_only valid
+/done/sub/sub/ 0000000000000000000000000000000000000000 recurse check_only valid
+/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
+/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
+EOF
test_cmp ../expect-from-test-dump ../actual
'