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

Re: [PATCH v3 4/8] dir: hide untracked contents of untracked dirs

From
Samuel Lijin <sxlijin@gmail.com>
Date
May 17, 2017, 07:32 UTC
Message-ID
<CAJZjrdXVzYZ_77Eod6oq-CB+tn5wdF4B3nWzN5zQvjduL9Lnfw@mail.gmail.com>
In-Reply-To
<xmqqo9usvv1m.fsf@gitster.mtv.corp.google.com>
On Wed, May 17, 2017 at 2:47 AM, Junio C Hamano <gitster@pobox.com> wrote:
Show 61 quoted lines
> Samuel Lijin <sxlijin@gmail.com> writes:
>
>> 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.
>>
>> Signed-off-by: Samuel Lijin <sxlijin@gmail.com>
>> ---
>>  dir.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>  dir.h |  3 ++-
>>  2 files changed, 56 insertions(+), 1 deletion(-)
>>
>> diff --git a/dir.c b/dir.c
>> index 6bd0350e9..214a148ee 100644
>> --- a/dir.c
>> +++ b/dir.c
>> @@ -1852,6 +1852,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 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);
>> +}
>
> OK, treat_one_path() and treat_pah_fast() both ensure that a path to
> a directory is terminated with '/' before calling dir_add_name() and
> dir_add_ignored(), so we know a dir_entry "out" that is a directory
> must end with '/'.  Good.
>
> The second and third line being overly indented is a bit
> distracting, though.
>
>>  static int treat_leading_path(struct dir_struct *dir,
>>                             const char *path, int len,
>>                             const struct pathspec *pathspec)
>> @@ -2067,6 +2075,52 @@ 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
>
>         /*
>          * Our multi-line comments are formatted like this
>          * example.  No C++/C99 // comments, outside of
>          * borrowed code and platform specific compat/ code,
>          * please.
>          */

Gahhhh, I keep forgetting about this, sorry. (There has to be a way to tell my compiler to catch this, right? It's pretty embarrassing to get called out for this twice...)

Show 5 quoted lines
>> +     if ((dir->flags & DIR_SHOW_IGNORED_TOO)
>> +                  && !(dir->flags & DIR_KEEP_UNTRACKED_CONTENTS)) {
>
> Both having && at the end and && at the beginning are valid C, but
> please stick to one style in a single file.
Got it.
Show 26 quoted lines
>> +             int i, j, nr_removed = 0;
>> +
>> +             // remove from dir->entries untracked contents of untracked dirs
>
>         /* And our single-liner comments look like this */
>
>> +             for (i = 0; i < dir->nr; i++) {
>> +                     if (!dir->entries[i])
>> +                             continue;
>> +
>> +                     for (j = i + 1; j < dir->nr; j++) {
>> +                             if (!dir->entries[j])
>> +                                     continue;
>> +                             if (check_contains(dir->entries[i], dir->entries[j])) {
>> +                                     nr_removed++;
>> +                                     free(dir->entries[j]);
>> +                                     dir->entries[j] = NULL;
>> +                             }
>> +                             else {
>> +                                     break;
>> +                             }
>> +                     }
>> +             }
>
> This loop is O(n^2).  I wonder if we can do better, especially we
> know dir->entries[] is sorted already.

Now that I think about it, dropping an `i = j - 1` into the inner loop right before the break should work:

+                             else {
+                                     i = j - 1;
+                                     break;
+                             }
Show 28 quoted lines
> Well, because it is sorted, if A/, A/B, and A/B/C are all untracked,
> the first round that scans for A/ will nuke both A/B and A/B/C, so
> we won't have to scan looking for entries inside A/B, which is a bit
> of consolation ;-)
>
>> +                     for (i = 0;;) {
>> +                             while (i < dir->nr && dir->entries[i])
>> +                                     i++;
>> +                             if (i == dir->nr)
>> +                                     break;
>> +                             j = i;
>> +                             while (j < dir->nr && !dir->entries[j])
>> +                                     j++;
>> +                             if (j == dir->nr)
>> +                                     break;
>> +                             dir->entries[i] = dir->entries[j];
>> +                             dir->entries[j] = NULL;
>> +                     }
>> +                     dir->nr -= nr_removed;
>
> This looks like an overly complicated way to scan an array and skip
> NULLs.  Are you doing an equivalent of this loop, or am I missing
> something subtle?
>
>         for (src = dst = 0; src < nr; src++)
>                 if (array[src])
>                         array[dst++] = src;
>         nr = dst;
Nope, that's pretty much it. Just me overthinking the problem.
Previous: Junio C HamanoNext: Junio C Hamano
Message 46 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.