git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v7 00/12] Fast git status via a file system watcher

From
Ben Peart <benpeart@microsoft.com>
Date
Sep 19, 2017, 19:27 UTC
Message-ID
<20170919192744.19224-1-benpeart@microsoft.com>
In-Reply-To
<20170915192043.4516-1-benpeart@microsoft.com>
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
Previous: Ben PeartNext: Ben Peart
Message 73 of 137 in “Fast git status via a file system watcher”
  1. 0/7 Fast git status via a file system watcherBen Peart, Jun 10, 2017
  2. 2/7 dir: make lookup_untracked() available outside of dir.cBen Peart, Jun 10, 2017
  3. 1/7 bswap: add 64 bit endianness helper get_be64Ben Peart, Jun 10, 2017
  4. 4/7 fsmonitor: add test cases for fsmonitor extensionBen Peart, Jun 10, 2017
  5. Christian CouderJun 27, 2017
  6. Ben PeartJul 7, 2017
  7. 3/7 fsmonitor: teach git to optionally utilize a file system monitor to speed up detecting new or changed files.Ben Peart, Jun 10, 2017
  8. Christian CouderJun 27, 2017
  9. Ben PeartJul 3, 2017
  10. 6/7 fsmonitor: add a sample query-fsmonitor hook script for WatchmanBen Peart, Jun 10, 2017
  11. 7/7 fsmonitor: add a performance testBen Peart, Jun 10, 2017
  12. Ben PeartJun 10, 2017
  13. Junio C HamanoJun 12, 2017
  14. Ben PeartJun 14, 2017
  15. Junio C HamanoJun 14, 2017
  16. Ben PeartJul 7, 2017
  17. Junio C HamanoJul 7, 2017
  18. Ben PeartJul 7, 2017
  19. David TurnerJul 7, 2017
  20. Christian CouderJul 8, 2017
  21. 5/7 fsmonitor: add documentation for the fsmonitor extension.Ben Peart, Jun 10, 2017
  22. Christian CouderJun 28, 2017
  23. Ben PeartJul 10, 2017
  24. Ben PeartJul 10, 2017
  25. 00/12 Fast git status via a file system watcherBen Peart, Sep 15, 2017
  26. 01/12 bswap: add 64 bit endianness helper get_be64Ben Peart, Sep 15, 2017
  27. 04/12 fsmonitor: teach git to optionally utilize a file system monitor to speed up detecting new or changed files.Ben Peart, Sep 15, 2017
  28. David TurnerSep 15, 2017
  29. Ben PeartSep 18, 2017
  30. David TurnerSep 18, 2017
  31. Ben PeartSep 18, 2017
  32. 05/12 fsmonitor: add documentation for the fsmonitor extension.Ben Peart, Sep 15, 2017
  33. David TurnerSep 15, 2017
  34. Ben PeartSep 18, 2017
  35. Junio C HamanoSep 17, 2017
  36. Ben PeartSep 18, 2017
  37. 07/12 update-index: add fsmonitor support to update-indexBen Peart, Sep 15, 2017
  38. 06/12 ls-files: Add support in ls-files to display the fsmonitor valid bitBen Peart, Sep 15, 2017
  39. David TurnerSep 15, 2017
  40. 10/12 fsmonitor: add test cases for fsmonitor extensionBen Peart, Sep 15, 2017
  41. David TurnerSep 15, 2017
  42. David TurnerSep 19, 2017
  43. Ben PeartSep 19, 2017
  44. Torsten BögershausenSep 16, 2017
  45. 1/1 test-lint: echo -e (or -E) is not portabletboegi@web.de, Sep 17, 2017
  46. Jonathan NiederSep 19, 2017
  47. Torsten BögershausenSep 20, 2017
  48. Junio C HamanoSep 22, 2017
  49. Ben PeartSep 18, 2017
  50. Junio C HamanoSep 17, 2017
  51. Ben PeartSep 18, 2017
  52. Jonathan NiederSep 19, 2017
  53. 12/12 fsmonitor: add a performance testBen Peart, Sep 15, 2017
  54. David TurnerSep 15, 2017
  55. Johannes SchindelinSep 18, 2017
  56. Ben PeartSep 18, 2017
  57. Johannes SchindelinSep 19, 2017
  58. 11/12 fsmonitor: add a sample integration script for WatchmanBen Peart, Sep 15, 2017
  59. 08/12 fsmonitor: add a test tool to dump the index extensionBen Peart, Sep 15, 2017
  60. Junio C HamanoSep 17, 2017
  61. Ben PeartSep 18, 2017
  62. Torsten BögershausenSep 18, 2017
  63. Ben PeartSep 18, 2017
  64. Torsten BögershausenSep 19, 2017
  65. Ben PeartSep 19, 2017
  66. 09/12 split-index: disable the fsmonitor extension when running the split index testBen Peart, Sep 15, 2017
  67. Jonathan NiederSep 19, 2017
  68. Ben PeartSep 20, 2017
  69. Jonathan NiederSep 20, 2017
  70. Ben PeartSep 21, 2017
  71. 03/12 update-index: add a new --force-write-index optionBen Peart, Sep 15, 2017
  72. 02/12 preload-index: add override to enable testing preload-indexBen Peart, Sep 15, 2017
  73. 00/12 Fast git status via a file system watcherBen Peart, Sep 19, 2017
  74. 01/12 bswap: add 64 bit endianness helper get_be64Ben Peart, Sep 19, 2017
  75. 02/12 preload-index: add override to enable testing preload-indexBen Peart, Sep 19, 2017
  76. Stefan BellerSep 20, 2017
  77. Ben PeartSep 21, 2017
  78. Stefan BellerSep 21, 2017
  79. 05/12 fsmonitor: add documentation for the fsmonitor extension.Ben Peart, Sep 19, 2017
  80. Martin ÅgrenSep 20, 2017
  81. Ben PeartSep 20, 2017
  82. Martin ÅgrenSep 20, 2017
  83. 04/12 fsmonitor: teach git to optionally utilize a file system monitor to speed up detecting new or changed files.Ben Peart, Sep 19, 2017
  84. Junio C HamanoSep 20, 2017
  85. Ben PeartSep 20, 2017
  86. Junio C HamanoSep 21, 2017
  87. Ben PeartSep 21, 2017
  88. Ben PeartSep 21, 2017
  89. Junio C HamanoSep 22, 2017
  90. Junio C HamanoSep 20, 2017
  91. Ben PeartSep 20, 2017
  92. 08/12 fsmonitor: add a test tool to dump the index extensionBen Peart, Sep 19, 2017
  93. 09/12 split-index: disable the fsmonitor extension when running the split index testBen Peart, Sep 19, 2017
  94. 07/12 update-index: add fsmonitor support to update-indexBen Peart, Sep 19, 2017
  95. 10/12 fsmonitor: add test cases for fsmonitor extensionBen Peart, Sep 19, 2017
  96. 03/12 update-index: add a new --force-write-index optionBen Peart, Sep 19, 2017
  97. Junio C HamanoSep 20, 2017
  98. Ben PeartSep 20, 2017
  99. Junio C HamanoSep 21, 2017
  100. Ben PeartSep 21, 2017
  101. Junio C HamanoSep 21, 2017
  102. Junio C HamanoSep 21, 2017
  103. 12/12 fsmonitor: add a performance testBen Peart, Sep 19, 2017
  104. 11/12 fsmonitor: add a sample integration script for WatchmanBen Peart, Sep 19, 2017
  105. 06/12 ls-files: Add support in ls-files to display the fsmonitor valid bitBen Peart, Sep 19, 2017
  106. David TurnerSep 19, 2017
  107. Ben PeartSep 19, 2017
  108. David TurnerSep 19, 2017
  109. Ben PeartSep 19, 2017
  110. 00/12 Fast git status via a file system watcherBen Peart, Sep 22, 2017
  111. 02/12 preload-index: add override to enable testing preload-indexBen Peart, Sep 22, 2017
  112. 01/12 bswap: add 64 bit endianness helper get_be64Ben Peart, Sep 22, 2017
  113. Martin ÅgrenSep 22, 2017
  114. Ben PeartSep 23, 2017
  115. Jeff KingSep 24, 2017
  116. Junio C HamanoSep 24, 2017
  117. 03/12 update-index: add a new --force-write-index optionBen Peart, Sep 22, 2017
  118. 11/12 fsmonitor: add a sample integration script for WatchmanBen Peart, Sep 22, 2017
  119. 04/12 fsmonitor: teach git to optionally utilize a file system monitor to speed up detecting new or changed files.Ben Peart, Sep 22, 2017
  120. 10/12 fsmonitor: add test cases for fsmonitor extensionBen Peart, Sep 22, 2017
  121. 09/12 split-index: disable the fsmonitor extension when running the split index testBen Peart, Sep 22, 2017
  122. 12/12 fsmonitor: add a performance testBen Peart, Sep 22, 2017
  123. 06/12 ls-files: Add support in ls-files to display the fsmonitor valid bitBen Peart, Sep 22, 2017
  124. 05/12 fsmonitor: add documentation for the fsmonitor extension.Ben Peart, Sep 22, 2017
  125. 07/12 update-index: add fsmonitor support to update-indexBen Peart, Sep 22, 2017
  126. 08/12 fsmonitor: add a test tool to dump the index extensionBen Peart, Sep 22, 2017
  127. Martin ÅgrenSep 22, 2017
  128. Ben PeartSep 23, 2017
  129. Junio C HamanoSep 24, 2017
  130. Junio C HamanoSep 29, 2017
  131. Ben PeartSep 29, 2017
  132. Junio C HamanoOct 1, 2017
  133. Ben PeartOct 3, 2017
  134. Junio C HamanoOct 4, 2017
  135. Alex VandiverOct 4, 2017
  136. Ben PeartOct 4, 2017
  137. Ben PeartOct 4, 2017

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.