From: Junio C Hamano Date: Fri, 2 Jun 2017 06:06:04 +0000 (+0900) Subject: Merge branch 'sl/clean-d-ignored-fix' X-Git-Tag: v2.14.0-rc0~126 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=f4fd99bf6e5c27265ee2a9ccb9c2495854f67acb;p=thirdparty%2Fgit.git Merge branch 'sl/clean-d-ignored-fix' "git clean -d" used to clean directories that has ignored files, even though the command should not lose ignored ones without "-x". "git status --ignored" did not list ignored and untracked files without "-uall". These have been corrected. * sl/clean-d-ignored-fix: clean: teach clean -d to preserve ignored paths dir: expose cmp_name() and check_contains() dir: hide untracked contents of untracked dirs dir: recurse into untracked dirs for ignored files t7061: status --ignored should search untracked dirs t7300: clean -d should skip dirs with ignored files --- f4fd99bf6e5c27265ee2a9ccb9c2495854f67acb diff --cc builtin/clean.c index 329b68c40b,7272033187..142bf668cf --- a/builtin/clean.c +++ b/builtin/clean.c @@@ -930,7 -959,8 +965,8 @@@ int cmd_clean(int argc, const char **ar PATHSPEC_PREFER_CWD, prefix, argv); - fill_directory(&dir, &pathspec); + fill_directory(&dir, &the_index, &pathspec); + correct_untracked_entries(&dir); for (i = 0; i < dir.nr; i++) { struct dir_entry *ent = dir.entries[i]; diff --cc dir.c index 3f3167e55a,31c6e1dac0..9efcf1eab6 --- a/dir.c +++ b/dir.c @@@ -1813,7 -1747,10 +1813,10 @@@ static enum path_treatment read_directo dir_state = state; /* recurse into subdir if instructed by treat_path */ - if (state == path_recurse) { + if ((state == path_recurse) || + ((state == path_untracked) && + (dir->flags & DIR_SHOW_IGNORED_TOO) && - (get_dtype(cdir.de, path.buf, path.len) == DT_DIR))) { ++ (get_dtype(cdir.de, istate, path.buf, path.len) == DT_DIR))) { struct untracked_cache_dir *ud; ud = lookup_untracked(dir->untracked, untracked, path.buf + baselen, @@@ -1876,8 -1813,15 +1879,16 @@@ int cmp_dir_entry(const void *p1, cons return name_compare(e1->name, e1->len, e2->name, e2->len); } + /* check if *out lexically strictly contains *in */ + int check_dir_entry_contains(const struct dir_entry *out, const struct dir_entry *in) + { + return (out->len < in->len) && + (out->name[out->len - 1] == '/') && + !memcmp(out->name, in->name, out->len); + } + static int treat_leading_path(struct dir_struct *dir, + struct index_state *istate, const char *path, int len, const struct pathspec *pathspec) { @@@ -2088,10 -2032,34 +2099,34 @@@ int read_directory(struct dir_struct *d * e.g. prep_exclude() */ dir->untracked = NULL; - if (!len || treat_leading_path(dir, path, len, pathspec)) - read_directory_recursive(dir, path, len, untracked, 0, pathspec); + if (!len || treat_leading_path(dir, istate, path, len, pathspec)) + read_directory_recursive(dir, istate, path, len, untracked, 0, pathspec); - QSORT(dir->entries, dir->nr, cmp_name); - QSORT(dir->ignored, dir->ignored_nr, cmp_name); + QSORT(dir->entries, dir->nr, cmp_dir_entry); + QSORT(dir->ignored, dir->ignored_nr, cmp_dir_entry); + + /* + * If DIR_SHOW_IGNORED_TOO is set, read_directory_recursive() will + * also pick up untracked contents of untracked dirs; by default + * we discard these, but given DIR_KEEP_UNTRACKED_CONTENTS we do not. + */ + if ((dir->flags & DIR_SHOW_IGNORED_TOO) && + !(dir->flags & DIR_KEEP_UNTRACKED_CONTENTS)) { + int i, j; + + /* remove from dir->entries untracked contents of untracked dirs */ + for (i = j = 0; j < dir->nr; j++) { + if (i && + check_dir_entry_contains(dir->entries[i - 1], dir->entries[j])) { + free(dir->entries[j]); + dir->entries[j] = NULL; + } else { + dir->entries[i++] = dir->entries[j]; + } + } + + dir->nr = i; + } + if (dir->untracked) { static struct trace_key trace_untracked_stats = TRACE_KEY_INIT(UNTRACKED_STATS); trace_printf_key(&trace_untracked_stats,