Subject: [PATCH 07/20] untracked cache: invalidate dirs recursively if .gitignore changes

From: Nguyễn Thái Ngọc Duy <[email-masked]>
Date: Wed, 7 May 2014 21:51:47 +0700

It's easy to see that if an existing .gitignore changes, its SHA-1
would be different and invalidate_gitignore() is called.

If .gitignore is removed, add_excludes() will treat it like an empty
.gitignore, which again should invalidate the cached directory data.

if .gitignore is added, lookup_untracked() already fills initial
.gitignore SHA-1 as "empty file", so again invalidate_gitignore() is
called.
---
 dir.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/dir.c b/dir.c
index a198aa8..6370f6e 100644
--- a/dir.c
+++ b/dir.c
@@ -1007,7 +1007,26 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
 			add_excludes(el->src, el->src, stk->baselen, el, 1,
 				     untracked ? sha1 : NULL, NULL, NULL);
 		}
+		/*
+		 * NEEDSWORK: when untracked cache is enabled,
+		 * prep_exclude() will first be called in
+		 * valid_cached_dir() then maybe many times more in
+		 * last_exclude_matching(). When the cache is used,
+		 * last_exclude_matching() will not be called and
+		 * reading .gitignore content will be a waste.
+		 *
+		 * So when it's called by valid_cached_dir() and we
+		 * can get .gitignore SHA-1 from the index
+		 * (i.e. .gitignore is not modified on work tree), we
+		 * could delay reading the .gitignore content until we
+		 * absolutely need it in last_exclude_matching(). Be
+		 * careful about ignore rule order, though, if you do
+		 * that.
+		 */
 		if (untracked) {
+			if (hashcmp(sha1, untracked->exclude_sha1))
+				invalidate_gitignore(dir->untracked,
+						     untracked);
 			hashcpy(untracked->exclude_sha1, sha1);
 		}
 		dir->exclude_stack = stk;
-- 
1.9.1.346.ga2b5940