summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/technical/api-directory-listing.txt6
-rw-r--r--dir.c31
-rw-r--r--dir.h3
-rwxr-xr-xt/t7061-wtstatus-ignore.sh4
4 files changed, 41 insertions, 3 deletions
diff --git a/Documentation/technical/api-directory-listing.txt b/Documentation/technical/api-directory-listing.txt
index 7f8e78d..6c77b49 100644
--- a/Documentation/technical/api-directory-listing.txt
+++ b/Documentation/technical/api-directory-listing.txt
@@ -33,6 +33,12 @@ The notable options are:
Similar to `DIR_SHOW_IGNORED`, but return ignored files in `ignored[]`
in addition to untracked files in `entries[]`.
+`DIR_KEEP_UNTRACKED_CONTENTS`:::
+
+ Only has meaning if `DIR_SHOW_IGNORED_TOO` is also set; if this is set, the
+ untracked contents of untracked directories are also returned in
+ `entries[]`.
+
`DIR_COLLECT_IGNORED`:::
Special mode for git-add. Return ignored files in `ignored[]` and
diff --git a/dir.c b/dir.c
index 6b4eeef..61561ea 100644
--- a/dir.c
+++ b/dir.c
@@ -1813,6 +1813,14 @@ static int cmp_name(const void *p1, const void *p2)
return name_compare(e1->name, e1->len, e2->name, e2->len);
}
+/* check if *out lexically strictly contains *in */
+static int check_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,
const char *path, int len,
const struct pathspec *pathspec)
@@ -2028,6 +2036,29 @@ int read_directory(struct dir_struct *dir, const char *path,
read_directory_recursive(dir, path, len, untracked, 0, pathspec);
QSORT(dir->entries, dir->nr, cmp_name);
QSORT(dir->ignored, dir->ignored_nr, cmp_name);
+
+ /*
+ * 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_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,
diff --git a/dir.h b/dir.h
index bf23a47..650e54b 100644
--- a/dir.h
+++ b/dir.h
@@ -151,7 +151,8 @@ struct dir_struct {
DIR_NO_GITLINKS = 1<<3,
DIR_COLLECT_IGNORED = 1<<4,
DIR_SHOW_IGNORED_TOO = 1<<5,
- DIR_COLLECT_KILLED_ONLY = 1<<6
+ DIR_COLLECT_KILLED_ONLY = 1<<6,
+ DIR_KEEP_UNTRACKED_CONTENTS = 1<<7
} flags;
struct dir_entry **entries;
struct dir_entry **ignored;
diff --git a/t/t7061-wtstatus-ignore.sh b/t/t7061-wtstatus-ignore.sh
index 15e7592..fc6013b 100755
--- a/t/t7061-wtstatus-ignore.sh
+++ b/t/t7061-wtstatus-ignore.sh
@@ -12,7 +12,7 @@ cat >expected <<\EOF
!! untracked/ignored
EOF
-test_expect_failure 'status untracked directory with --ignored' '
+test_expect_success 'status untracked directory with --ignored' '
echo "ignored" >.gitignore &&
mkdir untracked &&
: >untracked/ignored &&
@@ -21,7 +21,7 @@ test_expect_failure 'status untracked directory with --ignored' '
test_cmp expected actual
'
-test_expect_failure 'same with gitignore starting with BOM' '
+test_expect_success 'same with gitignore starting with BOM' '
printf "\357\273\277ignored\n" >.gitignore &&
mkdir -p untracked &&
: >untracked/ignored &&