If GIT_TEST_WATCHED is set to a non-zero value, Git still uses file
watcher if configured. But it does lstat() anyway and notifies the
user if a file is changed but the file watcher said otherwise.

Note that there is a race condition. Changed paths are retrieved at
time X, then refresh and validation at time Y. Even if X and Y are
very close, an update can happen between X and Y, causing a false
report.

If GIT_TEST_WATCHED is set greater than 1, git will abort instead of
just warn and move on.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclo...@gmail.com>
---
 Documentation/git-file-watcher.txt |  8 ++++++++
 cache.h                            |  5 ++++-
 read-cache.c                       | 17 +++++++++++++++++
 3 files changed, 29 insertions(+), 1 deletion(-)

diff --git a/Documentation/git-file-watcher.txt 
b/Documentation/git-file-watcher.txt
index d694fea..dd09e30 100644
--- a/Documentation/git-file-watcher.txt
+++ b/Documentation/git-file-watcher.txt
@@ -25,6 +25,14 @@ OPTIONS
 --detach::
        Run in background.
 
+TROUBLESHOOTING
+---------------
+Setting environment variable `GIT_TEST_WATCHED` to a non-zero number
+makes Git communicate with the file watcher, but do lstat anyway to
+verify that the file watcher results. Setting to 1 prints warning when
+file watcher fails to monitor files correctly. Setting to 2 aborts Git
+when it happens.
+
 BUGS
 ----
 On Linux, file watcher may fail to detect changes if you move the work
diff --git a/cache.h b/cache.h
index c229bf9..806c886 100644
--- a/cache.h
+++ b/cache.h
@@ -224,7 +224,10 @@ static inline unsigned create_ce_flags(unsigned stage)
 #define ce_mark_uptodate(ce) ((ce)->ce_flags |= CE_UPTODATE)
 static inline int ce_valid(const struct cache_entry *ce)
 {
-       return ce->ce_flags & CE_VALID;
+       extern int test_watched;
+       if (!test_watched)
+               return ce->ce_flags & CE_VALID;
+       return (ce->ce_flags & CE_VALID) && !(ce->ce_flags & CE_WATCHED);
 }
 
 #define ce_permissions(mode) (((mode) & 0100) ? 0755 : 0644)
diff --git a/read-cache.c b/read-cache.c
index 95c9ccb..d5f084a 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -37,6 +37,7 @@ static struct cache_entry *refresh_cache_entry(struct 
cache_entry *ce, int reall
 #define CACHE_EXT_WATCH 0x57415443       /* "WATC" */
 
 struct index_state the_index;
+int test_watched;
 
 static void set_index_entry(struct index_state *istate, int nr, struct 
cache_entry *ce)
 {
@@ -1117,6 +1118,16 @@ static void show_file(const char * fmt, const char * 
name, int in_porcelain,
        printf(fmt, name);
 }
 
+static void report_bad_watcher(struct index_state *istate,
+                              struct cache_entry *ce)
+{
+       if (test_watched > 1)
+               die("%s is updated but file-watcher said no",
+                   ce->name);
+       warning("%s is updated but file-watcher said no",
+               ce->name);
+}
+
 int refresh_index(struct index_state *istate, unsigned int flags,
                  const struct pathspec *pathspec,
                  char *seen, const char *header_msg)
@@ -1188,6 +1199,9 @@ int refresh_index(struct index_state *istate, unsigned 
int flags,
                                ce->ce_flags &= ~CE_VALID;
                                istate->cache_changed = 1;
                        }
+                       if (test_watched &&
+                           (ce->ce_flags & CE_WATCHED) && (ce->ce_flags & 
CE_VALID))
+                               report_bad_watcher(istate, ce);
                        if (quiet)
                                continue;
 
@@ -1460,6 +1474,9 @@ int read_index_from(struct index_state *istate, const 
char *path)
        if (istate->initialized)
                return istate->cache_nr;
 
+       if (getenv("GIT_TEST_WATCHED"))
+               test_watched = atoi(getenv("GIT_TEST_WATCHED"));
+
        istate->timestamp.sec = 0;
        istate->timestamp.nsec = 0;
        fd = open(path, O_RDONLY);
-- 
1.8.5.2.240.g8478abd

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to