Subject: Fast git status via a file system watcher

Thanks to everyone who provided feedback.  There are lots of minor style
changes, documentation updates and a fixed leak.

The only functional change is the addition of support to set/clear the
fsmonitor valid bit via 'git update-index --[no-]fsmonitor-valid' with
the associated documentation and tests.

Interdiff between V6 and V7:

diff --git a/Documentation/config.txt b/Documentation/config.txt
index c196007a27..db52645cb4 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -418,6 +418,7 @@ core.fsmonitor::
        will identify all files that may have changed since the
        requested date/time. This information is used to speed up git by
        avoiding unnecessary processing of files that have not changed.
+       See the "fsmonitor-watchman" section of linkgit:githooks[5].
 
 core.trustctime::
        If false, the ctime differences between the index and the
diff --git a/Documentation/git-ls-files.txt b/Documentation/git-ls-files.txt
index d153c17e06..3ac3e3a77d 100644
--- a/Documentation/git-ls-files.txt
+++ b/Documentation/git-ls-files.txt
@@ -9,7 +9,7 @@ git-ls-files - Show information about files in the index and 
the working tree
 SYNOPSIS
 --------
 [verse]
-'git ls-files' [-z] [-t] [-v]
+'git ls-files' [-z] [-t] [-v] [-f]
                
(--[cached|deleted|others|ignored|stage|unmerged|killed|modified])*
                (-[c|d|o|i|s|u|k|m])*
                [--eol]
@@ -133,6 +133,11 @@ a space) at the start of each line:
        that are marked as 'assume unchanged' (see
        linkgit:git-update-index[1]).
 
+-f::
+       Similar to `-t`, but use lowercase letters for files
+       that are marked as 'fsmonitor valid' (see
+       linkgit:git-update-index[1]).
+
 --full-name::
        When run from a subdirectory, the command usually
        outputs paths relative to the current directory.  This
diff --git a/Documentation/git-update-index.txt 
b/Documentation/git-update-index.txt
index e19eba62cd..95231dbfcb 100644
--- a/Documentation/git-update-index.txt
+++ b/Documentation/git-update-index.txt
@@ -16,9 +16,11 @@ SYNOPSIS
             [--chmod=(+|-)x]
             [--[no-]assume-unchanged]
             [--[no-]skip-worktree]
+            [--[no-]fsmonitor-valid]
             [--ignore-submodules]
             [--[no-]split-index]
             [--[no-|test-|force-]untracked-cache]
+            [--[no-]fsmonitor]
             [--really-refresh] [--unresolve] [--again | -g]
             [--info-only] [--index-info]
             [-z] [--stdin] [--index-version <n>]
@@ -111,6 +113,12 @@ you will need to handle the situation manually.
        set and unset the "skip-worktree" bit for the paths. See
        section "Skip-worktree bit" below for more information.
 
+--[no-]fsmonitor-valid::
+       When one of these flags is specified, the object name recorded
+       for the paths are not updated. Instead, these options
+       set and unset the "fsmonitor valid" bit for the paths. See
+       section "File System Monitor" below for more information.
+
 -g::
 --again::
        Runs 'git update-index' itself on the paths whose index
@@ -201,6 +209,15 @@ will remove the intended effect of the option.
        `--untracked-cache` used to imply `--test-untracked-cache` but
        this option would enable the extension unconditionally.
 
+--fsmonitor::
+--no-fsmonitor::
+       Enable or disable files system monitor feature. These options
+       take effect whatever the value of the `core.fsmonitor`
+       configuration variable (see linkgit:git-config[1]). But a warning
+       is emitted when the change goes against the configured value, as
+       the configured value will take effect next time the index is
+       read and this will remove the intended effect of the option.
+
 \--::
        Do not interpret any more arguments as options.
 
@@ -447,6 +464,34 @@ command reads the index; while when 
`--[no-|force-]untracked-cache`
 are used, the untracked cache is immediately added to or removed from
 the index.
 
+File System Monitor
+-------------------
+
+This feature is intended to speed up git operations for repos that have
+large working directories.
+
+It enables git to work together with a file system monitor (see the
+"fsmonitor-watchman" section of linkgit:githooks[5]) that can
+inform it as to what files have been modified. This enables git to avoid
+having to lstat() every file to find modified files.
+
+When used in conjunction with the untracked cache, it can further improve
+performance by avoiding the cost of scaning the entire working directory
+looking for new files.
+
+If you want to enable (or disable) this feature, it is easier to use
+the `core.fsmonitor` configuration variable (see
+linkgit:git-config[1]) than using the `--fsmonitor` option to
+`git update-index` in each repository, especially if you want to do so
+across all repositories you use, because you can set the configuration
+variable to `true` (or `false`) in your `$HOME/.gitconfig` just once
+and have it affect all repositories you touch.
+
+When the `core.fsmonitor` configuration variable is changed, the
+file system monitor is added to or removed from the index the next time
+a command reads the index. When `--[no-]fsmonitor` are used, the file
+system monitor is immediately added to or removed from the index.
+
 Configuration
 -------------
 
diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt
index da82d64b0b..ae60559cd9 100644
--- a/Documentation/githooks.txt
+++ b/Documentation/githooks.txt
@@ -455,10 +455,8 @@ the name of the file that holds the e-mail to be sent.  
Exiting with a
 non-zero status causes 'git send-email' to abort before sending any
 e-mails.
 
-
-[[fsmonitor-watchman]]
 fsmonitor-watchman
-~~~~~~~~~~~~~~~
+~~~~~~~~~~~~~~~~~~
 
 This hook is invoked when the configuration option core.fsmonitor is
 set to .git/hooks/fsmonitor-watchman.  It takes two arguments, a version
@@ -471,10 +469,17 @@ should be inclusive so that it does not miss any 
potential changes.
 The paths should be relative to the root of the working directory
 and be separated by a single NUL.
 
+It is OK to include files which have not actually changed.  All changes
+including newly-created and deleted files should be included. When
+files are renamed, both the old and the new name should be included.
+
 Git will limit what files it checks for changes as well as which
 directories are checked for untracked files based on the path names
 given.
 
+An optimized way to tell git "all files have changed" is to return
+the filename '/'.
+
 The exit status determines whether git will use the data from the
 hook to limit its search.  On error, it will fall back to verifying
 all files and folders.
diff --git a/builtin/update-index.c b/builtin/update-index.c
index b03afc1f3a..41618db098 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -33,6 +33,7 @@ static int force_remove;
 static int verbose;
 static int mark_valid_only;
 static int mark_skip_worktree_only;
+static int mark_fsmonitor_only;
 #define MARK_FLAG 1
 #define UNMARK_FLAG 2
 static struct strbuf mtime_dir = STRBUF_INIT;
@@ -229,12 +230,12 @@ static int mark_ce_flags(const char *path, int flag, int 
mark)
        int namelen = strlen(path);
        int pos = cache_name_pos(path, namelen);
        if (0 <= pos) {
+               mark_fsmonitor_invalid(&the_index, active_cache[pos]);
                if (mark)
                        active_cache[pos]->ce_flags |= flag;
                else
                        active_cache[pos]->ce_flags &= ~flag;
                active_cache[pos]->ce_flags |= CE_UPDATE_IN_BASE;
-               mark_fsmonitor_invalid(&the_index, active_cache[pos]);
                cache_tree_invalidate_path(&the_index, path);
                active_cache_changed |= CE_ENTRY_CHANGED;
                return 0;
@@ -460,6 +461,11 @@ static void update_one(const char *path)
                        die("Unable to mark file %s", path);
                return;
        }
+       if (mark_fsmonitor_only) {
+               if (mark_ce_flags(path, CE_FSMONITOR_VALID, mark_fsmonitor_only 
== MARK_FLAG))
+                       die("Unable to mark file %s", path);
+               return;
+       }
 
        if (force_remove) {
                if (remove_file_from_cache(path))
@@ -1014,6 +1020,12 @@ int cmd_update_index(int argc, const char **argv, const 
char *prefix)
                        N_("write out the index even if is not flagged as 
changed"), 1),
                OPT_BOOL(0, "fsmonitor", &fsmonitor,
                        N_("enable or disable file system monitor")),
+               {OPTION_SET_INT, 0, "fsmonitor-valid", &mark_fsmonitor_only, 
NULL,
+                       N_("mark files as fsmonitor valid"),
+                       PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, MARK_FLAG},
+               {OPTION_SET_INT, 0, "no-fsmonitor-valid", &mark_fsmonitor_only, 
NULL,
+                       N_("clear fsmonitor valid bit"),
+                       PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, UNMARK_FLAG},
                OPT_END()
        };
 
diff --git a/fsmonitor.c b/fsmonitor.c
index 144294b8df..b8b2d88fe1 100644
--- a/fsmonitor.c
+++ b/fsmonitor.c
@@ -57,12 +57,12 @@ int read_fsmonitor_extension(struct index_state *istate, 
const void *data,
 
                /* Mark all previously saved entries as dirty */
                ewah_each_bit(fsmonitor_dirty, fsmonitor_ewah_callback, istate);
-               ewah_free(fsmonitor_dirty);
 
                /* Now mark the untracked cache for fsmonitor usage */
                if (istate->untracked)
                        istate->untracked->use_fsmonitor = 1;
        }
+       ewah_free(fsmonitor_dirty);
 
        trace_printf_key(&trace_fsmonitor, "read fsmonitor extension 
successful");
        return 0;
@@ -177,7 +177,7 @@ void refresh_fsmonitor(struct index_state *istate)
        }
 
        /* a fsmonitor process can return '*' to indicate all entries are 
invalid */
-       if (query_success && query_result.buf[0] != '*') {
+       if (query_success && query_result.buf[0] != '/') {
                /* Mark all entries returned by the monitor as dirty */
                buf = query_result.buf;
                bol = 0;
diff --git a/fsmonitor.h b/fsmonitor.h
index dadbe90283..c2240b811a 100644
--- a/fsmonitor.h
+++ b/fsmonitor.h
@@ -46,7 +46,7 @@ static inline void mark_fsmonitor_valid(struct cache_entry 
*ce)
 }
 
 /*
- * Clear the given cache entries CE_FSMONITOR_VALID bit and invalidate any
+ * Clear the given cache entry's CE_FSMONITOR_VALID bit and invalidate any
  * corresponding untracked cache directory structures.
  */
 static inline void mark_fsmonitor_invalid(struct index_state *istate, struct 
cache_entry *ce)
diff --git a/t/helper/test-drop-caches.c b/t/helper/test-drop-caches.c
index 717079865c..4e5ca8f397 100644
--- a/t/helper/test-drop-caches.c
+++ b/t/helper/test-drop-caches.c
@@ -2,7 +2,7 @@
 
 #if defined(GIT_WINDOWS_NATIVE)
 
-int cmd_sync(void)
+static int cmd_sync(void)
 {
        char Buffer[MAX_PATH];
        DWORD dwRet;
@@ -49,7 +49,7 @@ typedef enum _SYSTEM_MEMORY_LIST_COMMAND {
        MemoryCommandMax
 } SYSTEM_MEMORY_LIST_COMMAND;
 
-BOOL GetPrivilege(HANDLE TokenHandle, LPCSTR lpName, int flags)
+static BOOL GetPrivilege(HANDLE TokenHandle, LPCSTR lpName, int flags)
 {
        BOOL bResult;
        DWORD dwBufferLength;
@@ -77,10 +77,11 @@ BOOL GetPrivilege(HANDLE TokenHandle, LPCSTR lpName, int 
flags)
        return bResult;
 }
 
-int cmd_dropcaches(void)
+static int cmd_dropcaches(void)
 {
        HANDLE hProcess = GetCurrentProcess();
        HANDLE hToken;
+       HMODULE ntdll;
        int status;
 
        if (!OpenProcessToken(hProcess, TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, 
&hToken))
@@ -91,7 +92,7 @@ int cmd_dropcaches(void)
 
        CloseHandle(hToken);
 
-       HMODULE ntdll = LoadLibrary("ntdll.dll");
+       ntdll = LoadLibrary("ntdll.dll");
        if (!ntdll)
                return error("Can't load ntdll.dll, wrong Windows version?");
 
@@ -118,36 +119,36 @@ int cmd_dropcaches(void)
 
 #elif defined(__linux__)
 
-int cmd_sync(void)
+static int cmd_sync(void)
 {
        return system("sync");
 }
 
-int cmd_dropcaches(void)
+static int cmd_dropcaches(void)
 {
        return system("echo 3 | sudo tee /proc/sys/vm/drop_caches");
 }
 
 #elif defined(__APPLE__)
 
-int cmd_sync(void)
+static int cmd_sync(void)
 {
        return system("sync");
 }
 
-int cmd_dropcaches(void)
+static int cmd_dropcaches(void)
 {
        return system("sudo purge");
 }
 
 #else
 
-int cmd_sync(void)
+static int cmd_sync(void)
 {
        return 0;
 }
 
-int cmd_dropcaches(void)
+static int cmd_dropcaches(void)
 {
        return error("drop caches not implemented on this platform");
 }
diff --git a/t/helper/test-dump-fsmonitor.c b/t/helper/test-dump-fsmonitor.c
index 482d749bb9..ad452707e8 100644
--- a/t/helper/test-dump-fsmonitor.c
+++ b/t/helper/test-dump-fsmonitor.c
@@ -12,7 +12,7 @@ int cmd_main(int ac, const char **av)
                printf("no fsmonitor\n");
                return 0;
        }
-       printf("fsmonitor last update %"PRIuMAX"\n", 
istate->fsmonitor_last_update);
+       printf("fsmonitor last update %"PRIuMAX"\n", 
(uintmax_t)istate->fsmonitor_last_update);
 
        for (i = 0; i < istate->cache_nr; i++)
                printf((istate->cache[i]->ce_flags & CE_FSMONITOR_VALID) ? "+" 
: "-");
diff --git a/t/perf/p7519-fsmonitor.sh b/t/perf/p7519-fsmonitor.sh
index 1c5978d5c8..16d1bf72e5 100755
--- a/t/perf/p7519-fsmonitor.sh
+++ b/t/perf/p7519-fsmonitor.sh
@@ -95,7 +95,7 @@ test_expect_success "setup for fsmonitor" '
                INTEGRATION_SCRIPT="$GIT_PERF_7519_FSMONITOR"
        else
                #
-               # Choose integration script based on existance of Watchman.
+               # Choose integration script based on existence of Watchman.
                # If Watchman exists, watch the work tree and attempt a query.
                # If everything succeeds, use Watchman integration script,
                # else fall back to an empty integration script.
diff --git a/t/t7519-status-fsmonitor.sh b/t/t7519-status-fsmonitor.sh
index 6aa1e4e924..c6df85af5e 100755
--- a/t/t7519-status-fsmonitor.sh
+++ b/t/t7519-status-fsmonitor.sh
@@ -32,14 +32,16 @@ dirty_repo () {
        echo 6 >dir2/new
 }
 
-write_integration_script() {
+write_integration_script () {
        write_script .git/hooks/fsmonitor-test<<-\EOF
-       if [ "$#" -ne 2 ]; then
+       if test "$#" -ne 2
+       then
                echo "$0: exactly 2 arguments expected"
                exit 2
        fi
-       if [ "$1" != 1 ]; then
-               echo -e "Unsupported core.fsmonitor hook version.\n" >&2
+       if test "$1" != 1
+       then
+               echo "Unsupported core.fsmonitor hook version." >&2
                exit 1
        fi
        printf "untracked\0"
@@ -100,6 +102,43 @@ test_expect_success 'update-index --no-fsmonitor" removes 
the fsmonitor extensio
        grep "^no fsmonitor" actual
 '
 
+cat >expect <<EOF &&
+h dir1/modified
+H dir1/tracked
+h dir2/modified
+H dir2/tracked
+h modified
+H tracked
+EOF
+
+# test that "update-index --fsmonitor-valid" sets the fsmonitor valid bit
+test_expect_success 'update-index --fsmonitor-valid" sets the fsmonitor valid 
bit' '
+       git update-index --fsmonitor &&
+       git update-index --fsmonitor-valid dir1/modified &&
+       git update-index --fsmonitor-valid dir2/modified &&
+       git update-index --fsmonitor-valid modified &&
+       git ls-files -f >actual &&
+       test_cmp expect actual
+'
+
+cat >expect <<EOF &&
+H dir1/modified
+H dir1/tracked
+H dir2/modified
+H dir2/tracked
+H modified
+H tracked
+EOF
+
+# test that "update-index --no-fsmonitor-valid" clears the fsmonitor valid bit
+test_expect_success 'update-index --no-fsmonitor-valid" clears the fsmonitor 
valid bit' '
+       git update-index --no-fsmonitor-valid dir1/modified &&
+       git update-index --no-fsmonitor-valid dir2/modified &&
+       git update-index --no-fsmonitor-valid modified &&
+       git ls-files -f >actual &&
+       test_cmp expect actual
+'
+
 cat >expect <<EOF &&
 H dir1/modified
 H dir1/tracked
@@ -204,7 +243,7 @@ for preload_val in $preload_values
 do
        test_expect_success "setup preloadIndex to $preload_val" '
                git config core.preloadIndex $preload_val &&
-               if [ $preload_val -eq true ]
+               if test $preload_val = true
                then
                        GIT_FORCE_PRELOAD_TEST=$preload_val; export 
GIT_FORCE_PRELOAD_TEST
                else
@@ -249,8 +288,14 @@ do
                        git status >actual &&
                        test_path_is_file marker &&
                        test_i18ngrep ! "Changes not staged for commit:" actual 
&&
-                       if [ $uc_val -eq true ]; then test_i18ngrep ! 
"Untracked files:" actual; fi &&
-                       if [ $uc_val -eq false ]; then test_i18ngrep "Untracked 
files:" actual; fi &&
+                       if test $uc_val = true
+                       then
+                               test_i18ngrep ! "Untracked files:" actual
+                       fi &&
+                       if test $uc_val = false
+                       then
+                               test_i18ngrep "Untracked files:" actual
+                       fi &&
                        rm -f marker
                '
        done
diff --git a/t/t7519/fsmonitor-all b/t/t7519/fsmonitor-all
index a3870e431e..691bc94dc2 100755
--- a/t/t7519/fsmonitor-all
+++ b/t/t7519/fsmonitor-all
@@ -9,15 +9,16 @@
 #
 #echo "$0 $*" >&2
 
-if [ "$#" -ne 2 ] ; then
-       echo -e "$0: exactly 2 arguments expected\n" >&2
+if test "$#" -ne 2
+then
+       echo "$0: exactly 2 arguments expected" >&2
        exit 2
 fi
 
-if [ "$1" != 1 ]
+if test "$1" != 1
 then
-       echo -e "Unsupported core.fsmonitor hook version.\n" >&2
+       echo "Unsupported core.fsmonitor hook version." >&2
        exit 1
 fi
 
-echo "*"
\ No newline at end of file
+echo "/"
diff --git a/t/t7519/fsmonitor-none b/t/t7519/fsmonitor-none
index c500bb0f26..ed9cf5a6a9 100755
--- a/t/t7519/fsmonitor-none
+++ b/t/t7519/fsmonitor-none
@@ -9,13 +9,14 @@
 #
 #echo "$0 $*" >&2
 
-if [ "$#" -ne 2 ] ; then
-       echo -e "$0: exactly 2 arguments expected\n" >&2
+if test "$#" -ne 2
+then
+       echo "$0: exactly 2 arguments expected" >&2
        exit 2
 fi
 
-if [ "$1" != 1 ]
+if test "$1" != 1
 then
-       echo -e "Unsupported core.fsmonitor hook version.\n" >&2
+       echo "Unsupported core.fsmonitor hook version." >&2
        exit 1
 fi
diff --git a/t/t7519/fsmonitor-watchman b/t/t7519/fsmonitor-watchman
index aaee5d1fe3..7ceb32dc18 100755
--- a/t/t7519/fsmonitor-watchman
+++ b/t/t7519/fsmonitor-watchman
@@ -17,7 +17,7 @@ use IPC::Open2;
 # 'git config core.fsmonitor .git/hooks/query-watchman'
 #
 my ($version, $time) = @ARGV;
-print STDERR "$0 $version $time\n";
+#print STDERR "$0 $version $time\n";
 
 # Check the hook interface version
 
@@ -29,7 +29,20 @@ if ($version == 1) {
            "Falling back to scanning...\n";
 }
 
-my $git_work_tree = $ENV{'PWD'};
+# Convert unix style paths to escaped Windows style paths when running
+# in Windows command prompt
+
+my $system = `uname -s`;
+$system =~ s/[\r\n]+//g;
+my $git_work_tree;
+
+if ($system =~ m/^MSYS_NT/) {
+       $git_work_tree = `cygpath -aw "\$PWD"`;
+       $git_work_tree =~ s/[\r\n]+//g;
+       $git_work_tree =~ s,\\,/,g;
+} else {
+       $git_work_tree = $ENV{'PWD'};
+}
 
 my $retry = 1;
 
@@ -57,20 +70,19 @@ sub launch_watchman {
        # creation clock (cclock) newer than $time_t value and will also not
        # currently exist.
 
+       my $query = <<" END";
+               ["query", "$git_work_tree", {
+                       "since": $time,
+                       "fields": ["name"],
+                       "expression": ["not", ["allof", ["since", $time, 
"cclock"], ["not", "exists"]]]
+               }]
+       END
+       
        open (my $fh, ">", ".git/watchman-query.json");
-       print $fh "[\"query\", \"$git_work_tree\", { \
-       \"since\": $time, \
-       \"fields\": [\"name\"], \
-       \"expression\": [\"not\", [\"allof\", [\"since\", $time, \"cclock\"], 
[\"not\", \"exists\"]]] \
-       }]";
+       print $fh $query;
        close $fh;
 
-       print CHLD_IN "[\"query\", \"$git_work_tree\", { \
-       \"since\": $time, \
-       \"fields\": [\"name\"], \
-       \"expression\": [\"not\", [\"allof\", [\"since\", $time, \"cclock\"], 
[\"not\", \"exists\"]]] \
-       }]";
-
+       print CHLD_IN $query;
        my $response = <CHLD_OUT>;
 
        open ($fh, ">", ".git/watchman-response.json");
@@ -100,17 +112,17 @@ sub launch_watchman {
                qx/watchman watch "$git_work_tree"/;
                die "Failed to make watchman watch '$git_work_tree'.\n" .
                    "Falling back to scanning...\n" if $? != 0;
-               # return fast "everything is dirty" flag"
-               print "*\0";
-               open ($fh, ">", ".git/watchman-output.out");
-               print "*\0";
-               close $fh;
 
                # Watchman will always return all files on the first query so
                # return the fast "everything is dirty" flag to git and do the
                # Watchman query just to get it over with now so we won't pay
                # the cost in git to look up each individual file.
-               print "*\0";
+
+               open ($fh, ">", ".git/watchman-output.out");
+               print "/\0";
+               close $fh;
+
+               print "/\0";
                eval { launch_watchman() };
                exit 0;
        }
@@ -118,11 +130,11 @@ sub launch_watchman {
        die "Watchman: $o->{error}.\n" .
            "Falling back to scanning...\n" if $o->{error};
 
-       binmode STDOUT, ":utf8";
-       local $, = "\0";
-       print @{$o->{files}};
-
        open ($fh, ">", ".git/watchman-output.out");
        print $fh @{$o->{files}};
        close $fh;
-}
\ No newline at end of file
+
+       binmode STDOUT, ":utf8";
+       local $, = "\0";
+       print @{$o->{files}};
+}
diff --git a/templates/hooks--fsmonitor-watchman.sample 
b/templates/hooks--fsmonitor-watchman.sample
index 2779d7edf3..870a59d237 100755
--- a/templates/hooks--fsmonitor-watchman.sample
+++ b/templates/hooks--fsmonitor-watchman.sample
@@ -69,12 +69,15 @@ sub launch_watchman {
        # creation clock (cclock) newer than $time_t value and will also not
        # currently exist.
 
-       print CHLD_IN "[\"query\", \"$git_work_tree\", { \
-       \"since\": $time, \
-       \"fields\": [\"name\"], \
-       \"expression\": [\"not\", [\"allof\", [\"since\", $time, \"cclock\"], 
[\"not\", \"exists\"]]] \
-       }]";
-
+       my $query = <<" END";
+               ["query", "$git_work_tree", {
+                       "since": $time,
+                       "fields": ["name"],
+                       "expression": ["not", ["allof", ["since", $time, 
"cclock"], ["not", "exists"]]]
+               }]
+       END
+
+       print CHLD_IN $query;
        my $response = <CHLD_OUT>;
 
        die "Watchman: command returned no output.\n" .
@@ -105,7 +108,7 @@ sub launch_watchman {
                # return the fast "everything is dirty" flag to git and do the
                # Watchman query just to get it over with now so we won't pay
                # the cost in git to look up each individual file.
-               print "*\0";
+               print "/\0";
                eval { launch_watchman() };
                exit 0;
        }

Ben Peart (12):
  bswap: add 64 bit endianness helper get_be64
  preload-index: add override to enable testing preload-index
  update-index: add a new --force-write-index option
  fsmonitor: teach git to optionally utilize a file system monitor to
    speed up detecting new or changed files.
  fsmonitor: add documentation for the fsmonitor extension.
  ls-files: Add support in ls-files to display the fsmonitor valid bit
  update-index: add fsmonitor support to update-index
  fsmonitor: add a test tool to dump the index extension
  split-index: disable the fsmonitor extension when running the split
    index test
  fsmonitor: add test cases for fsmonitor extension
  fsmonitor: add a sample integration script for Watchman
  fsmonitor: add a performance test

 Documentation/config.txt                   |   7 +
 Documentation/git-ls-files.txt             |   7 +-
 Documentation/git-update-index.txt         |  45 +++++
 Documentation/githooks.txt                 |  28 +++
 Documentation/technical/index-format.txt   |  19 ++
 Makefile                                   |   3 +
 apply.c                                    |   2 +-
 builtin/ls-files.c                         |   8 +-
 builtin/update-index.c                     |  38 +++-
 cache.h                                    |  10 +-
 compat/bswap.h                             |  22 +++
 config.c                                   |  14 ++
 config.h                                   |   1 +
 diff-lib.c                                 |   2 +
 dir.c                                      |  27 ++-
 dir.h                                      |   2 +
 entry.c                                    |   4 +-
 environment.c                              |   1 +
 fsmonitor.c                                | 253 ++++++++++++++++++++++++
 fsmonitor.h                                |  61 ++++++
 preload-index.c                            |   8 +-
 read-cache.c                               |  49 ++++-
 submodule.c                                |   2 +-
 t/helper/.gitignore                        |   1 +
 t/helper/test-drop-caches.c                | 162 +++++++++++++++
 t/helper/test-dump-fsmonitor.c             |  21 ++
 t/perf/p7519-fsmonitor.sh                  | 184 +++++++++++++++++
 t/t1700-split-index.sh                     |   1 +
 t/t7519-status-fsmonitor.sh                | 304 +++++++++++++++++++++++++++++
 t/t7519/fsmonitor-all                      |  24 +++
 t/t7519/fsmonitor-none                     |  22 +++
 t/t7519/fsmonitor-watchman                 | 140 +++++++++++++
 templates/hooks--fsmonitor-watchman.sample | 122 ++++++++++++
 unpack-trees.c                             |   8 +-
 34 files changed, 1572 insertions(+), 30 deletions(-)
 create mode 100644 fsmonitor.c
 create mode 100644 fsmonitor.h
 create mode 100644 t/helper/test-drop-caches.c
 create mode 100644 t/helper/test-dump-fsmonitor.c
 create mode 100755 t/perf/p7519-fsmonitor.sh
 create mode 100755 t/t7519-status-fsmonitor.sh
 create mode 100755 t/t7519/fsmonitor-all
 create mode 100755 t/t7519/fsmonitor-none
 create mode 100755 t/t7519/fsmonitor-watchman
 create mode 100755 templates/hooks--fsmonitor-watchman.sample

-- 
2.14.1.windows.1

Reply via email to