Skip to content

Commit 7233f17

Browse files
newrengitster
authored andcommitted
clean: optimize and document cases where we recurse into subdirectories
Commit 6b1db43 ("clean: teach clean -d to preserve ignored paths", 2017-05-23) added the following code block (among others) to git-clean: if (remove_directories) dir.flags |= DIR_SHOW_IGNORED_TOO | DIR_KEEP_UNTRACKED_CONTENTS; The reason for these flags is well documented in the commit message, but isn't obvious just from looking at the code. Add some explanations to the code to make it clearer. Further, it appears git-2.26 did not correctly handle this combination of flags from git-clean. With both these flags and without DIR_SHOW_IGNORED_TOO_MODE_MATCHING set, git is supposed to recurse into all untracked AND ignored directories. git-2.26.0 clearly was not doing that. I don't know the full reasons for that or whether git < 2.27.0 had additional unknown bugs because of that misbehavior, because I don't feel it's worth digging into. As per the huge changes and craziness documented in commit 8d92fb2 ("dir: replace exponential algorithm with a linear one", 2020-04-01), the old algorithm was a mess and was thrown out. What I can say is that git-2.27.0 correctly recurses into untracked AND ignored directories with that combination. However, in clean's case we don't need to recurse into ignored directories; that is just a waste of time. Thus, when git-2.27.0 started correctly handling those flags, we got a performance regression report. Rather than relying on other bugs in fill_directory()'s former logic to provide the behavior of skipping ignored directories, make use of the DIR_SHOW_IGNORED_TOO_MODE_MATCHING value specifically added in commit eec0f7f ("status: add option to show ignored files differently", 2017-10-30) for this purpose. Reported-by: Brian Malehorn <[email protected]> Signed-off-by: Elijah Newren <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent f7f5c6c commit 7233f17

File tree

1 file changed

+31
-2
lines changed

1 file changed

+31
-2
lines changed

builtin/clean.c

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -955,8 +955,37 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
955955
remove_directories = 1;
956956
}
957957

958-
if (remove_directories && !ignored_only)
959-
dir.flags |= DIR_SHOW_IGNORED_TOO | DIR_KEEP_UNTRACKED_CONTENTS;
958+
if (remove_directories && !ignored_only) {
959+
/*
960+
* We need to know about ignored files too:
961+
*
962+
* If (ignored), then we will delete ignored files as well.
963+
*
964+
* If (!ignored), then even though we not are doing
965+
* anything with ignored files, we need to know about them
966+
* so that we can avoid deleting a directory of untracked
967+
* files that also contains an ignored file within it.
968+
*
969+
* For the (!ignored) case, since we only need to avoid
970+
* deleting ignored files, we can set
971+
* DIR_SHOW_IGNORED_TOO_MODE_MATCHING in order to avoid
972+
* recursing into a directory which is itself ignored.
973+
*/
974+
dir.flags |= DIR_SHOW_IGNORED_TOO;
975+
if (!ignored)
976+
dir.flags |= DIR_SHOW_IGNORED_TOO_MODE_MATCHING;
977+
978+
/*
979+
* Let the fill_directory() machinery know that we aren't
980+
* just recursing to collect the ignored files; we want all
981+
* the untracked ones so that we can delete them. (Note:
982+
* we could also set DIR_KEEP_UNTRACKED_CONTENTS when
983+
* ignored_only is true, since DIR_KEEP_UNTRACKED_CONTENTS
984+
* only has effect in combination with DIR_SHOW_IGNORED_TOO. It makes
985+
* the code clearer to exclude it, though.
986+
*/
987+
dir.flags |= DIR_KEEP_UNTRACKED_CONTENTS;
988+
}
960989

961990
if (read_cache() < 0)
962991
die(_("index file corrupt"));

0 commit comments

Comments
 (0)