git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v4 4/6] dir: hide untracked contents of untracked dirs

From
Samuel Lijin <sxlijin@gmail.com>
Date
May 18, 2017, 08:21 UTC
Message-ID
<20170518082154.28643-5-sxlijin@gmail.com>
In-Reply-To
<20170518082154.28643-1-sxlijin@gmail.com>

When we taught read_directory_recursive() to recurse into untracked directories in search of ignored files given DIR_SHOW_IGNORED_TOO, that had the side effect of teaching it to collect the untracked contents of untracked directories. It doesn't always make sense to return these, though (we do need them for `clean -d`), so we introduce a flag (DIR_KEEP_UNTRACKED_CONTENTS) to control whether or not read_directory() strips dir->entries of the untracked contents of untracked dirs.

We also introduce check_contains() to check if one dir_entry corresponds to a path which contains the path corresponding to another dir_entry.

This also fixes known breakages in t7061, since status --ignored now searches untracked directories for ignored files.

Signed-off-by: Samuel Lijin <sxlijin@gmail.com>
---
 Documentation/technical/api-directory-listing.txt |  6 +++++
 dir.c                                             | 30 +++++++++++++++++++++++
 dir.h                                             |  3 ++-
 t/t7061-wtstatus-ignore.sh                        |  4 +--
 4 files changed, 40 insertions(+), 3 deletions(-)
diff --git a/Documentation/technical/api-directory-listing.txt b/Documentation/technical/api-directory-listing.txt
index 7f8e78d91..6c77b4920 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 68cf6e47c..4b0a99323 100644
--- a/dir.c
+++ b/dir.c
@@ -1850,6 +1850,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)
@@ -2065,6 +2073,28 @@ 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, 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 bf23a470a..650e54bdf 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 15e7592b6..fc6013ba3 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 &&
-- 
2.13.0
Previous: Samuel LijinNext: Junio C Hamano
Message 68 of 89 in “Bug Report: .gitignore behavior is not matching in git clean and git status”
  1. Chris JohnsonApr 28, 2017
  2. Junio C HamanoMay 1, 2017
  3. Chris JohnsonMay 1, 2017
  4. Junio C HamanoMay 1, 2017
  5. Samuel LijinMay 1, 2017
  6. Samuel LijinMay 1, 2017
  7. Junio C HamanoMay 2, 2017
  8. 0/7 Keep git clean -d from inadvertently removing ignored filesSamuel Lijin, May 3, 2017
  9. 1/7 t7300: skip untracked dirs containing ignored filesSamuel Lijin, May 3, 2017
  10. Stefan BellerMay 3, 2017
  11. Samuel LijinMay 3, 2017
  12. Stefan BellerMay 3, 2017
  13. 7/7 t7061: check for ignored file in untracked dirSamuel Lijin, May 3, 2017
  14. 5/7 dir: change linkage of cmp_name() and check_contains()Samuel Lijin, May 3, 2017
  15. 3/7 dir: add method to check if a dir_entry lexically contains anotherSamuel Lijin, May 3, 2017
  16. Stefan BellerMay 3, 2017
  17. 6/7 builtin/clean: teach clean -d to skip dirs containing ignored filesSamuel Lijin, May 3, 2017
  18. 2/7 dir: recurse into untracked dirs for ignored filesSamuel Lijin, May 3, 2017
  19. 4/7 dir: hide untracked contents of untracked dirsSamuel Lijin, May 3, 2017
  20. 0/9 Keep git clean -d from inadvertently removing ignored filesSamuel Lijin, May 5, 2017
  21. 1/9 t7300: skip untracked dirs containing ignored filesSamuel Lijin, May 5, 2017
  22. Torsten BögershausenMay 7, 2017
  23. Samuel LijinMay 8, 2017
  24. 2/9 t7061: expect failure where expected behavior will changeSamuel Lijin, May 5, 2017
  25. Junio C HamanoMay 8, 2017
  26. 4/9 dir: add method to check if a dir_entry lexically contains anotherSamuel Lijin, May 5, 2017
  27. 6/9 dir: change linkage of cmp_name() and check_contains()Samuel Lijin, May 5, 2017
  28. Junio C HamanoMay 8, 2017
  29. 3/9 dir: recurse into untracked dirs for ignored filesSamuel Lijin, May 5, 2017
  30. 7/9 builtin/clean: teach clean -d to skip dirs containing ignored filesSamuel Lijin, May 5, 2017
  31. 8/9 t7300: clean -d now skips untracked dirs containing ignored filesSamuel Lijin, May 5, 2017
  32. 5/9 dir: hide untracked contents of untracked dirsSamuel Lijin, May 5, 2017
  33. 9/9 t7061: expect ignored files in untracked dirsSamuel Lijin, May 5, 2017
  34. Junio C HamanoMay 8, 2017
  35. Junio C HamanoMay 8, 2017
  36. Samuel LijinMay 8, 2017
  37. Junio C HamanoMay 9, 2017
  38. 0/8 Fix clean -d and status --ignoredSamuel Lijin, May 16, 2017
  39. 1/8 t7300: clean -d should skip dirs with ignored filesSamuel Lijin, May 16, 2017
  40. 3/8 dir: recurse into untracked dirs for ignored filesSamuel Lijin, May 16, 2017
  41. Junio C HamanoMay 17, 2017
  42. Samuel LijinMay 17, 2017
  43. 2/8 t7061: status --ignored should search untracked dirsSamuel Lijin, May 16, 2017
  44. 4/8 dir: hide untracked contents of untracked dirsSamuel Lijin, May 16, 2017
  45. Junio C HamanoMay 17, 2017
  46. Samuel LijinMay 17, 2017
  47. Junio C HamanoMay 17, 2017
  48. 5/8 dir: expose cmp_name() and check_contains()Samuel Lijin, May 16, 2017
  49. 6/8 clean: teach clean -d to skip dirs containing ignored filesSamuel Lijin, May 16, 2017
  50. Junio C HamanoMay 18, 2017
  51. Samuel LijinMay 18, 2017
  52. 7/8 t7300: clean -d now skips untracked dirs containing ignored filesSamuel Lijin, May 16, 2017
  53. Junio C HamanoMay 18, 2017
  54. 8/8 t7061: status --ignored now searches untracked dirsSamuel Lijin, May 16, 2017
  55. Junio C HamanoMay 18, 2017
  56. 0/6 Fix clean -d and status --ignoredSamuel Lijin, May 18, 2017
  57. 1/6 t7300: clean -d should skip dirs with ignored filesSamuel Lijin, May 18, 2017
  58. 5/6 dir: expose cmp_name() and check_contains()Samuel Lijin, May 18, 2017
  59. Junio C HamanoMay 22, 2017
  60. 6/6 clean: teach clean -d to skip dirs containing ignored filesSamuel Lijin, May 18, 2017
  61. Junio C HamanoMay 22, 2017
  62. Samuel LijinMay 22, 2017
  63. Junio C HamanoMay 22, 2017
  64. Samuel LijinMay 23, 2017
  65. Junio C HamanoMay 23, 2017
  66. 3/6 dir: recurse into untracked dirs for ignored filesSamuel Lijin, May 18, 2017
  67. 2/6 t7061: status --ignored should search untracked dirsSamuel Lijin, May 18, 2017
  68. 4/6 dir: hide untracked contents of untracked dirsSamuel Lijin, May 18, 2017
  69. Junio C HamanoMay 22, 2017
  70. 0/6 Fix clean -d and status --ignoredSamuel Lijin, May 23, 2017
  71. 1/6 t7300: clean -d should skip dirs with ignored filesSamuel Lijin, May 23, 2017
  72. 2/6 t7061: status --ignored should search untracked dirsSamuel Lijin, May 23, 2017
  73. 3/6 dir: recurse into untracked dirs for ignored filesSamuel Lijin, May 23, 2017
  74. 5/6 dir: expose cmp_name() and check_contains()Samuel Lijin, May 23, 2017
  75. 4/6 dir: hide untracked contents of untracked dirsSamuel Lijin, May 23, 2017
  76. 6/6 clean: teach clean -d to preserve ignored pathsSamuel Lijin, May 23, 2017
  77. Junio C HamanoMay 23, 2017
  78. Samuel LijinMay 23, 2017
  79. 0/6 Fix clean -d and status --ignoredSamuel Lijin, May 23, 2017
  80. 1/6 t7300: clean -d should skip dirs with ignored filesSamuel Lijin, May 23, 2017
  81. 2/6 t7061: status --ignored should search untracked dirsSamuel Lijin, May 23, 2017
  82. 3/6 dir: recurse into untracked dirs for ignored filesSamuel Lijin, May 23, 2017
  83. 5/6 dir: expose cmp_name() and check_contains()Samuel Lijin, May 23, 2017
  84. 4/6 dir: hide untracked contents of untracked dirsSamuel Lijin, May 23, 2017
  85. 6/6 clean: teach clean -d to preserve ignored pathsSamuel Lijin, May 23, 2017
  86. Junio C HamanoMay 23, 2017
  87. Torsten BögershausenMay 24, 2017
  88. Samuel LijinMay 25, 2017
  89. Junio C HamanoMay 26, 2017

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.