OSDN Git Service

Merge branch 'sl/clean-d-ignored-fix'
authorJunio C Hamano <gitster@pobox.com>
Fri, 2 Jun 2017 06:06:04 +0000 (15:06 +0900)
committerJunio C Hamano <gitster@pobox.com>
Fri, 2 Jun 2017 06:06:05 +0000 (15:06 +0900)
"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

1  2 
builtin/clean.c
dir.c
dir.h

diff --cc 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
--- 1/dir.c
--- 2/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,
diff --cc dir.h
Simple merge