untracked cache: don't open non-existent .gitignore
authorNguyễn Thái Ngọc Duy <pclouds@gmail.com>
Sun, 8 Mar 2015 10:12:31 +0000 (17:12 +0700)
committerJunio C Hamano <gitster@pobox.com>
Thu, 12 Mar 2015 20:45:16 +0000 (13:45 -0700)
This cuts down a signficant number of open(.gitignore) because most
directories usually don't have .gitignore files.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
dir.c
diff --git a/dir.c b/dir.c
index 2d0582e8a8f36dcc5dea7f42892736908afb1746..f39024c6396bf456a9ecbfa8dc886e83aebeb3d4 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -1020,7 +1020,21 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
                /* Try to read per-directory file */
                hashclr(sha1_stat.sha1);
                sha1_stat.valid = 0;
-               if (dir->exclude_per_dir) {
+               if (dir->exclude_per_dir &&
+                   /*
+                    * If we know that no files have been added in
+                    * this directory (i.e. valid_cached_dir() has
+                    * been executed and set untracked->valid) ..
+                    */
+                   (!untracked || !untracked->valid ||
+                    /*
+                     * .. and .gitignore does not exist before
+                     * (i.e. null exclude_sha1 and skip_worktree is
+                     * not set). Then we can skip loading .gitignore,
+                     * which would result in ENOENT anyway.
+                     * skip_worktree is taken care in read_directory()
+                     */
+                    !is_null_sha1(untracked->exclude_sha1))) {
                        /*
                         * dir->basebuf gets reused by the traversal, but we
                         * need fname to remain unchanged to ensure the src
@@ -1783,6 +1797,7 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d
                                                      const struct pathspec *pathspec)
 {
        struct untracked_cache_dir *root;
+       int i;
 
        if (!dir->untracked)
                return NULL;
@@ -1834,6 +1849,15 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d
        if (dir->exclude_list_group[EXC_CMDL].nr)
                return NULL;
 
+       /*
+        * An optimization in prep_exclude() does not play well with
+        * CE_SKIP_WORKTREE. It's a rare case anyway, if a single
+        * entry has that bit set, disable the whole untracked cache.
+        */
+       for (i = 0; i < active_nr; i++)
+               if (ce_skip_worktree(active_cache[i]))
+                       return NULL;
+
        if (!dir->untracked->root) {
                const int len = sizeof(*dir->untracked->root);
                dir->untracked->root = xmalloc(len);