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

Re: [PATCH 13/23] fsmonitor-fs-listen-win32: implement FSMonitor backend on Windows

From
JHJeff Hostetler <git@jeffhostetler.com>
Date
Apr 30, 2021, 19:32 UTC
Message-ID
<1c6dec17-89be-7f5f-7125-263e6778d2ba@jeffhostetler.com>
In-Reply-To
<4b0066f5-5962-e57e-5987-5358f3d394f7@gmail.com>
On 4/27/21 1:22 PM, Derrick Stolee wrote:
Show 20 quoted lines
> On 4/1/2021 11:40 AM, Jeff Hostetler via GitGitGadget wrote:
>> From: Jeff Hostetler <jeffhost@microsoft.com>
>>
>> Teach the win32 backend to register a watch on the working tree
>> root directory (recursively).  Also watch the <gitdir> if it is
>> not inside the working tree.  And to collect path change notifications
>> into batches and publish.
> 
> Is it valuable to list the important API methods here for an interested
> reader to discover them? Perhaps using links to the docs [1] might be
> too ephemeral, in case those URLs stop being valid.
> 
> In any case, here are the URLs I found helpful:
> 
> [1] https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-readdirectorychangesw
> [2] https://docs.microsoft.com/en-us/windows/win32/api/ioapiset/nf-ioapiset-getoverlappedresult
> [3] https://docs.microsoft.com/en-us/windows/win32/fileio/cancelioex-func
> [4] https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-resetevent
> [5] https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-file_notify_information
> [6] https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitformultipleobjects

I could see adding them. I think I had some in an earlier draft. (And I'm always glad to find them when I go back and revisit the code later :-)

And yes, the Win32 APIs and code are a bit dense and tricky to understand -- especially the async IO stuff, so this would be good.

> 
>> Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
...
Show 9 quoted lines
>> +static struct one_watch *create_watch(struct fsmonitor_daemon_state *state,
>> +				      const char *path)
>> +{
>> +	struct one_watch *watch = NULL;
>> +	DWORD desired_access = FILE_LIST_DIRECTORY;
>> +	DWORD share_mode =
>> +		FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE;
> 
> Ah, this is probably why we can delete a repo that is under a watch.

Yes, we're holding a handle to the directory (and we're CD'd into it), but I have code in there to detect when the .git directory is deleted and trigger a shutdown. A "rm -rf" on the worktree will delete the .git directory first and we "usually" win that race before "rm" gets around to deleting the root directory.

I intend to harden this a bit more. The Git startup code does the CD to the root directory and I'd like to CD out after we get everything setup.

...
Show 16 quoted lines
>> +static int recv_rdcw_watch(struct one_watch *watch)
>> +{
>> +	watch->is_active = FALSE;
>> +
>> +	if (GetOverlappedResult(watch->hDir, &watch->overlapped, &watch->count,
>> +				TRUE))
>> +		return 0;
>> +
>> +	// TODO If an external <gitdir> is deleted, the above returns an error.
>> +	// TODO I'm not sure that there's anything that we can do here other
>> +	// TODO than failing -- the <worktree>/.git link file would be broken
>> +	// TODO anyway.  We might try to check for that and return a better
>> +	// TODO error message.
> 
> These are not fit C-style comments. This situation can be handled
> by a later patch series, if valuable enough.
Oooops, I missed that one before I posted it.
Show 46 quoted lines
> 
>> +
>> +	error("GetOverlappedResult failed on '%s' [GLE %ld]",
>> +	      watch->path.buf, GetLastError());
>> +	return -1;
>> +}
>> +
>> +static void cancel_rdcw_watch(struct one_watch *watch)
>> +{
>> +	DWORD count;
>> +
>> +	if (!watch || !watch->is_active)
>> +		return;
>> +
>> +	CancelIoEx(watch->hDir, &watch->overlapped);
>> +	GetOverlappedResult(watch->hDir, &watch->overlapped, &count, TRUE);
>> +	watch->is_active = FALSE;
>> +}
>> +
>> +/*
>> + * Process filesystem events that happen anywhere (recursively) under the
>> + * <worktree> root directory.  For a normal working directory, this includes
>> + * both version controlled files and the contents of the .git/ directory.
>> + *
>> + * If <worktree>/.git is a file, then we only see events for the file
>> + * itself.
>> + */
>> +static int process_worktree_events(struct fsmonitor_daemon_state *state)
>> +{
>> +	struct fsmonitor_daemon_backend_data *data = state->backend_data;
>> +	struct one_watch *watch = data->watch_worktree;
>> +	struct strbuf path = STRBUF_INIT;
>> +	struct string_list cookie_list = STRING_LIST_INIT_DUP;
>> +	struct fsmonitor_batch *batch = NULL;
>> +	const char *p = watch->buffer;
>> +
>> +	/*
>> +	 * If the kernel gets more events than will fit in the kernel
>> +	 * buffer associated with our RDCW handle, it drops them and
>> +	 * returns a count of zero.  (A successful call, but with
>> +	 * length zero.)
>> +	 */
> 
> I suppose that since we create a cookie file, we don't expect a zero
> result to ever be a meaningful value? Or, is there another way to
> differentiate between "nothing happened" and "too much happened"?

This is independent of cookie files. We have a thread watching watching for FS events and building up batches of changes and assembling the list of batches. This is always running.

Cookies are created by the threads in the IPC thread pool and those threads wait until we get a FS event for their cookie file.

All of these threads are running independently.

The code here is saying that Windows will give us a non-error but zero result when the kernel had to drop events. (The "too much happened" case.)

If nothing happens on the FS, our Async IO doesn't trigger a wakeup and the FS listener thread stays in the WaitForMultipleObjects().

All of this is pretty dense I realize.
Show 72 quoted lines
> 
>> +	if (!watch->count) {
>> +		trace2_data_string("fsmonitor", NULL, "fsm-listen/kernel",
>> +				   "overflow");
>> +		fsmonitor_force_resync(state);
>> +		return LISTENER_HAVE_DATA_WORKTREE;
>> +	}
>> +
>> +	/*
>> +	 * On Windows, `info` contains an "array" of paths that are
>> +	 * relative to the root of whichever directory handle received
>> +	 * the event.
>> +	 */
>> +	for (;;) {
>> +		FILE_NOTIFY_INFORMATION *info = (void *)p;
>> +		const char *slash;
>> +		enum fsmonitor_path_type t;
>> +
>> +		strbuf_reset(&path);
>> +		if (normalize_path_in_utf8(info, &path) == -1)
>> +			goto skip_this_path;
>> +
>> +		t = fsmonitor_classify_path_workdir_relative(path.buf);
>> +
>> +		switch (t) {
>> +		case IS_INSIDE_DOT_GIT_WITH_COOKIE_PREFIX:
>> +			/* special case cookie files within .git */
>> +
>> +			/* Use just the filename of the cookie file. */
>> +			slash = find_last_dir_sep(path.buf);
>> +			string_list_append(&cookie_list,
>> +					   slash ? slash + 1 : path.buf);
> 
> Ok, I see now how we special-case cookies in the list of events.
> 
>> +			break;
>> +
>> +		case IS_INSIDE_DOT_GIT:
>> +			/* ignore everything inside of "<worktree>/.git/" */
>> +			break;
>> +
>> +		case IS_DOT_GIT:
>> +			/* "<worktree>/.git" was deleted (or renamed away) */
>> +			if ((info->Action == FILE_ACTION_REMOVED) ||
>> +			    (info->Action == FILE_ACTION_RENAMED_OLD_NAME)) {
>> +				trace2_data_string("fsmonitor", NULL,
>> +						   "fsm-listen/dotgit",
>> +						   "removed");
>> +				goto force_shutdown;
>> +			}
>> +			break;
>> +
>> +		case IS_WORKDIR_PATH:
>> +			/* queue normal pathname */
>> +			if (!batch)
>> +				batch = fsmonitor_batch__new();
>> +			fsmonitor_batch__add_path(batch, path.buf);
>> +			break;
>> +
>> +		case IS_GITDIR:
>> +		case IS_INSIDE_GITDIR:
>> +		case IS_INSIDE_GITDIR_WITH_COOKIE_PREFIX:
>> +		default:
>> +			BUG("unexpected path classification '%d' for '%s'",
>> +			    t, path.buf);
> So these events should be caught by the _other_ watcher. I suppose
> BUG() is somewhat appropriate, but also seems heavy-handed. For
> example, the 'goto' in the next line will never be visited. A die()
> would even be appropriate, but somewhat less harsh than a BUG(),
> especially for a background process.
> 
>> +			goto skip_this_path;

Right, the IS_*GITDIR events should only happen in the other watcher. They are bugs in the sense that the path classifier failed. And the "default:" is my usual backstop for such an enum where any other value would be a bug.

I'm not sure whether BUG(), die(), or error() is better than the other. The daemon runs with without a console normally, so the messages will not be seen -- unless you're debugging it or running it in the foreground.

I could get rid of the goto.
Show 41 quoted lines
>> +		}
>> +
>> +skip_this_path:
>> +		if (!info->NextEntryOffset)
>> +			break;
>> +		p += info->NextEntryOffset;
>> +	}
>> +
>> +	fsmonitor_publish(state, batch, &cookie_list);
>> +	batch = NULL;
>> +	string_list_clear(&cookie_list, 0);
>> +	strbuf_release(&path);
>> +	return LISTENER_HAVE_DATA_WORKTREE;
>> +
>> +force_shutdown:
>> +	fsmonitor_batch__free(batch);
>> +	string_list_clear(&cookie_list, 0);
>> +	strbuf_release(&path);
>> +	return LISTENER_SHUTDOWN;
>> +}
>> +
>> +/*
>> + * Process filesystem events that happend anywhere (recursively) under the
> 
> s/happend/happened
> 
>> + * external <gitdir> (such as non-primary worktrees or submodules).
>> + * We only care about cookie files that our client threads created here.
>> + *
>> + * Note that we DO NOT get filesystem events on the external <gitdir>
>> + * itself (it is not inside something that we are watching).  In particular,
>> + * we do not get an event if the external <gitdir> is deleted.
> 
> This is an interesting change of behavior. I forget if it is listed in
> the documentation file, but definitely could be. I imagine wanting a
> "Troubleshooting" section that describes special cases like this.
> 
> Also, because of this worktree-specific behavior, we might want to
> recommend using 'git config --worktree' when choosing to use FS Monitor,
> so that each worktree is opted-in as requested. Without --worktree, all
> worktrees with a common base would stard using FS Monitor simultaneously.
I'll take a look.
Show 86 quoted lines
> 
>> + */
>> +static int process_gitdir_events(struct fsmonitor_daemon_state *state)
>> +{
>> +	struct fsmonitor_daemon_backend_data *data = state->backend_data;
>> +	struct one_watch *watch = data->watch_gitdir;
>> +	struct strbuf path = STRBUF_INIT;
>> +	struct string_list cookie_list = STRING_LIST_INIT_DUP;
>> +	const char *p = watch->buffer;
>> +
>> +	if (!watch->count) {
>> +		trace2_data_string("fsmonitor", NULL, "fsm-listen/kernel",
>> +				   "overflow");
>> +		fsmonitor_force_resync(state);
>> +		return LISTENER_HAVE_DATA_GITDIR;
>> +	}
>> +
>> +	for (;;) {
>> +		FILE_NOTIFY_INFORMATION *info = (void *)p;
>> +		const char *slash;
>> +		enum fsmonitor_path_type t;
>> +
>> +		strbuf_reset(&path);
>> +		if (normalize_path_in_utf8(info, &path) == -1)
>> +			goto skip_this_path;
>> +
>> +		t = fsmonitor_classify_path_gitdir_relative(path.buf);
>> +
>> +		trace_printf_key(&trace_fsmonitor, "BBB: %s", path.buf);
>> +
>> +		switch (t) {
>> +		case IS_INSIDE_GITDIR_WITH_COOKIE_PREFIX:
>> +			/* special case cookie files within gitdir */
>> +
>> +			/* Use just the filename of the cookie file. */
>> +			slash = find_last_dir_sep(path.buf);
>> +			string_list_append(&cookie_list,
>> +					   slash ? slash + 1 : path.buf);
>> +			break;
>> +
>> +		case IS_INSIDE_GITDIR:
>> +			goto skip_this_path;
>> +
>> +		default:
>> +			BUG("unexpected path classification '%d' for '%s'",
>> +			    t, path.buf);
> 
> If we decide against BUG() earlier, then also get this one.
> 
>> +			goto skip_this_path;
>> +		}
>> +
>> +skip_this_path:
>> +		if (!info->NextEntryOffset)
>> +			break;
>> +		p += info->NextEntryOffset;
>> +	}
>> +
>> +	fsmonitor_publish(state, NULL, &cookie_list);
>> +	string_list_clear(&cookie_list, 0);
>> +	strbuf_release(&path);
>> +	return LISTENER_HAVE_DATA_GITDIR;
>>   }
>>   
>>   void fsmonitor_fs_listen__loop(struct fsmonitor_daemon_state *state)
>>   {
>> +	struct fsmonitor_daemon_backend_data *data = state->backend_data;
>> +	DWORD dwWait;
>> +
>> +	state->error_code = 0;
>> +
>> +	if (start_rdcw_watch(data, data->watch_worktree) == -1)
>> +		goto force_error_stop;
>> +
>> +	if (data->watch_gitdir &&
>> +	    start_rdcw_watch(data, data->watch_gitdir) == -1)
>> +		goto force_error_stop;
>> +
>> +	for (;;) {
>> +		dwWait = WaitForMultipleObjects(data->nr_listener_handles,
>> +						data->hListener,
>> +						FALSE, INFINITE);
> 
> Since you use INFINITE here, that says that we will wait for at least one
> signal, solving the confusion about zero results: zero results unambiguously
> indicates a loss of events.
Right.
Show 86 quoted lines
> 
>> +
>> +		if (dwWait == WAIT_OBJECT_0 + LISTENER_HAVE_DATA_WORKTREE) {
>> +			if (recv_rdcw_watch(data->watch_worktree) == -1)
>> +				goto force_error_stop;
>> +			if (process_worktree_events(state) == LISTENER_SHUTDOWN)
>> +				goto force_shutdown;
>> +			if (start_rdcw_watch(data, data->watch_worktree) == -1)
>> +				goto force_error_stop;
>> +			continue;
>> +		}
>> +
>> +		if (dwWait == WAIT_OBJECT_0 + LISTENER_HAVE_DATA_GITDIR) {
>> +			if (recv_rdcw_watch(data->watch_gitdir) == -1)
>> +				goto force_error_stop;
>> +			if (process_gitdir_events(state) == LISTENER_SHUTDOWN)
>> +				goto force_shutdown;
>> +			if (start_rdcw_watch(data, data->watch_gitdir) == -1)
>> +				goto force_error_stop;
>> +			continue;
>> +		}
>> +
>> +		if (dwWait == WAIT_OBJECT_0 + LISTENER_SHUTDOWN)
>> +			goto clean_shutdown;
>> +
>> +		error(_("could not read directory changes [GLE %ld]"),
>> +		      GetLastError());
>> +		goto force_error_stop;
>> +	}
>> +
>> +force_error_stop:
>> +	state->error_code = -1;
>> +
>> +force_shutdown:
>> +	/*
>> +	 * Tell the IPC thead pool to stop (which completes the await
>> +	 * in the main thread (which will also signal this thread (if
>> +	 * we are still alive))).
>> +	 */
>> +	ipc_server_stop_async(state->ipc_server_data);
>> +
>> +clean_shutdown:
>> +	cancel_rdcw_watch(data->watch_worktree);
>> +	cancel_rdcw_watch(data->watch_gitdir);
>>   }
>>   
>>   int fsmonitor_fs_listen__ctor(struct fsmonitor_daemon_state *state)
>>   {
>> +	struct fsmonitor_daemon_backend_data *data;
>> +
>> +	data = xcalloc(1, sizeof(*data));
> 
> CALLOC_ARRAY()
> 
>> +
>> +	data->hEventShutdown = CreateEvent(NULL, TRUE, FALSE, NULL);
>> +
>> +	data->watch_worktree = create_watch(state,
>> +					    state->path_worktree_watch.buf);
>> +	if (!data->watch_worktree)
>> +		goto failed;
>> +
>> +	if (state->nr_paths_watching > 1) {
>> +		data->watch_gitdir = create_watch(state,
>> +						  state->path_gitdir_watch.buf);
>> +		if (!data->watch_gitdir)
>> +			goto failed;
>> +	}
>> +
>> +	data->hListener[LISTENER_SHUTDOWN] = data->hEventShutdown;
>> +	data->nr_listener_handles++;
>> +
>> +	data->hListener[LISTENER_HAVE_DATA_WORKTREE] =
>> +		data->watch_worktree->hEvent;
>> +	data->nr_listener_handles++;
>> +
>> +	if (data->watch_gitdir) {
>> +		data->hListener[LISTENER_HAVE_DATA_GITDIR] =
>> +			data->watch_gitdir->hEvent;
>> +		data->nr_listener_handles++;
>> +	}
> 
> This is a clever organization of the event handles. I imagine it
> will requires some rework if we decide to include another optional
> handle whose inclusion is orthogonal to the gitdir one, but that
> is unlikely enough to keep these well-defined array indices.

I think we're good here. I think an INVALID_HANDLE value can be used to supply a hole in the vector of event handles. But yes, we don't have to worry about that now.

Show 35 quoted lines
> 
>> +	state->backend_data = data;
>> +	return 0;
>> +
>> +failed:
>> +	CloseHandle(data->hEventShutdown);
>> +	destroy_watch(data->watch_worktree);
>> +	destroy_watch(data->watch_gitdir);
>> +
>>   	return -1;
>>   }
>>   
>>   void fsmonitor_fs_listen__dtor(struct fsmonitor_daemon_state *state)
>>   {
>> +	struct fsmonitor_daemon_backend_data *data;
>> +
>> +	if (!state || !state->backend_data)
>> +		return;
>> +
>> +	data = state->backend_data;
>> +
>> +	CloseHandle(data->hEventShutdown);
>> +	destroy_watch(data->watch_worktree);
>> +	destroy_watch(data->watch_gitdir);
>> +
>> +	FREE_AND_NULL(state->backend_data);
>>   }
> 
> I tried to follow all the API calls and check the documentation for
> any misuse, but did not find any. I can only contribute nitpicks
> here, and rely on the tests to really see that this is working as
> expected.
> 
> I was hoping to find in here why we need to sleep in the test suite,
> but have not pinpointed that issue yet.

The sleep was only needed on severely under-powered CI machines (think 1 core). I revisit this. I think I might be able to get rid of it.

Thanks, Jeff

Previous: Eric SunshineNext: Jeff Hostetler via GitGitGadget
Message 67 of 237 in “[RFC] Builtin FSMonitor Feature”
  1. 00/23 [RFC] Builtin FSMonitor FeatureJeff Hostetler via GitGitGadget, Apr 1, 2021
  2. 17/23 fsmonitor--daemon: periodically truncate list of modified filesJeff Hostetler via GitGitGadget, Apr 1, 2021
  3. Derrick StoleeApr 27, 2021
  4. 14/23 fsmonitor-fs-listen-macos: add macos header files for FSEventJeff Hostetler via GitGitGadget, Apr 1, 2021
  5. Derrick StoleeApr 27, 2021
  6. 06/23 fsmonitor--daemon: implement client command optionsJeff Hostetler via GitGitGadget, Apr 1, 2021
  7. Derrick StoleeApr 26, 2021
  8. Jeff HostetlerApr 30, 2021
  9. 20/23 fsmonitor: force update index when fsmonitor token advancesJeff Hostetler via GitGitGadget, Apr 1, 2021
  10. Derrick StoleeApr 27, 2021
  11. 19/23 fsmonitor--daemon: use a cookie file to sync with file systemJeff Hostetler via GitGitGadget, Apr 1, 2021
  12. Derrick StoleeApr 27, 2021
  13. Jeff HostetlerMay 3, 2021
  14. 02/23 fsmonitor-ipc: create client routines for git-fsmonitor--daemonJeff Hostetler via GitGitGadget, Apr 1, 2021
  15. Derrick StoleeApr 26, 2021
  16. Eric SunshineApr 26, 2021
  17. Derrick StoleeApr 26, 2021
  18. Jeff HostetlerApr 28, 2021
  19. 04/23 fsmonitor: introduce `core.useBuiltinFSMonitor` to call the daemon via IPCJohannes Schindelin via GitGitGadget, Apr 1, 2021
  20. Derrick StoleeApr 26, 2021
  21. Ævar Arnfjörð BjarmasonApr 27, 2021
  22. Derrick StoleeApr 27, 2021
  23. Ævar Arnfjörð BjarmasonApr 28, 2021
  24. repo-settings.c: simplify the setupÆvar Arnfjörð Bjarmason, Apr 28, 2021
  25. Nesting topics within other threads (was: [PATCH] repo-settings.c: simplify the setup)Derrick Stolee, Apr 28, 2021
  26. Ævar Arnfjörð BjarmasonApr 28, 2021
  27. Johannes SchindelinMay 5, 2021
  28. Junio C HamanoApr 29, 2021
  29. Ævar Arnfjörð BjarmasonApr 29, 2021
  30. Jeff KingApr 29, 2021
  31. Junio C HamanoApr 30, 2021
  32. Jeff HostetlerApr 30, 2021
  33. 15/23 fsmonitor-fs-listen-macos: implement FSEvent listener on MacOSJeff Hostetler via GitGitGadget, Apr 1, 2021
  34. Derrick StoleeApr 27, 2021
  35. Jeff HostetlerApr 30, 2021
  36. 12/23 fsmonitor--daemon: create token-based changed path cacheJeff Hostetler via GitGitGadget, Apr 1, 2021
  37. Derrick StoleeApr 26, 2021
  38. Jeff HostetlerApr 30, 2021
  39. 09/23 fsmonitor--daemon: implement daemon command optionsJeff Hostetler via GitGitGadget, Apr 1, 2021
  40. Derrick StoleeApr 26, 2021
  41. Derrick StoleeApr 26, 2021
  42. Jeff HostetlerApr 30, 2021
  43. Jeff HostetlerApr 30, 2021
  44. 11/23 fsmonitor--daemon: define token-idsJeff Hostetler via GitGitGadget, Apr 1, 2021
  45. Derrick StoleeApr 26, 2021
  46. Eric SunshineApr 26, 2021
  47. Derrick StoleeApr 26, 2021
  48. Jeff HostetlerApr 30, 2021
  49. 23/23 t7527: test status with untracked-cache and fsmonitor--daemonJeff Hostetler via GitGitGadget, Apr 1, 2021
  50. Derrick StoleeApr 27, 2021
  51. 21/23 t7527: create test for fsmonitor--daemonJeff Hostetler via GitGitGadget, Apr 1, 2021
  52. Derrick StoleeApr 27, 2021
  53. 16/23 fsmonitor--daemon: implement handle_client callbackJeff Hostetler via GitGitGadget, Apr 1, 2021
  54. Derrick StoleeApr 26, 2021
  55. Jeff HostetlerMay 3, 2021
  56. Derrick StoleeMay 13, 2021
  57. 05/23 fsmonitor--daemon: add a built-in fsmonitor daemonJeff Hostetler via GitGitGadget, Apr 1, 2021
  58. Derrick StoleeApr 26, 2021
  59. Derrick StoleeApr 26, 2021
  60. Jeff HostetlerApr 30, 2021
  61. 08/23 fsmonitor-fs-listen-macos: stub in backend for MacOSJeff Hostetler via GitGitGadget, Apr 1, 2021
  62. 18/23 fsmonitor--daemon:: introduce client delay for testingJeff Hostetler via GitGitGadget, Apr 1, 2021
  63. Derrick StoleeApr 27, 2021
  64. 13/23 fsmonitor-fs-listen-win32: implement FSMonitor backend on WindowsJeff Hostetler via GitGitGadget, Apr 1, 2021
  65. Derrick StoleeApr 27, 2021
  66. Eric SunshineApr 27, 2021
  67. Jeff HostetlerApr 30, 2021
  68. 22/23 p7519: add fsmonitor--daemonJeff Hostetler via GitGitGadget, Apr 1, 2021
  69. Derrick StoleeApr 27, 2021
  70. 10/23 fsmonitor--daemon: add pathname classificationJeff Hostetler via GitGitGadget, Apr 1, 2021
  71. Derrick StoleeApr 26, 2021
  72. Eric SunshineApr 26, 2021
  73. Derrick StoleeApr 26, 2021
  74. 03/23 config: FSMonitor is repository-specificJohannes Schindelin via GitGitGadget, Apr 1, 2021
  75. 07/23 fsmonitor-fs-listen-win32: stub in backend for WindowsJeff Hostetler via GitGitGadget, Apr 1, 2021
  76. Derrick StoleeApr 26, 2021
  77. 01/23 fsmonitor--daemon: man page and documentationJeff Hostetler via GitGitGadget, Apr 1, 2021
  78. Derrick StoleeApr 26, 2021
  79. Jeff HostetlerApr 28, 2021
  80. Junio C HamanoApr 16, 2021
  81. Johannes SchindelinApr 20, 2021
  82. Jeff HostetlerApr 20, 2021
  83. Derrick StoleeApr 21, 2021
  84. FS Monitor Windows Performance (was [PATCH 00/23] [RFC] Builtin FSMonitor Feature)Derrick Stolee, Apr 27, 2021
  85. FS Monitor macOS Performance (was [PATCH 00/23] [RFC] Builtin FSMonitor Feature)Derrick Stolee, Apr 27, 2021
  86. 00/28 Builtin FSMonitor FeatureJeff Hostetler via GitGitGadget, May 22, 2021
  87. 01/28 simple-ipc: preparations for supporting binary messages.Jeff Hostetler via GitGitGadget, May 22, 2021
  88. 05/28 help: include fsmonitor--daemon feature flag in version infoJeff Hostetler via GitGitGadget, May 22, 2021
  89. 03/28 fsmonitor--daemon: update fsmonitor documentationJeff Hostetler via GitGitGadget, May 22, 2021
  90. 02/28 fsmonitor--daemon: man pageJeff Hostetler via GitGitGadget, May 22, 2021
  91. 04/28 fsmonitor-ipc: create client routines for git-fsmonitor--daemonJeff Hostetler via GitGitGadget, May 22, 2021
  92. Johannes SchindelinJun 2, 2021
  93. Johannes SchindelinJun 14, 2021
  94. 06/28 config: FSMonitor is repository-specificJohannes Schindelin via GitGitGadget, May 22, 2021
  95. 08/28 fsmonitor--daemon: add a built-in fsmonitor daemonJeff Hostetler via GitGitGadget, May 22, 2021
  96. 07/28 fsmonitor: introduce `core.useBuiltinFSMonitor` to call the daemon via IPCJohannes Schindelin via GitGitGadget, May 22, 2021
  97. Johannes SchindelinJun 14, 2021
  98. 09/28 fsmonitor--daemon: implement client command optionsJeff Hostetler via GitGitGadget, May 22, 2021
  99. 10/28 t/helper/fsmonitor-client: create IPC client to talk to FSMonitor DaemonJeff Hostetler via GitGitGadget, May 22, 2021
  100. Junio C HamanoJun 11, 2021
  101. 12/28 fsmonitor-fs-listen-macos: stub in backend for MacOSJeff Hostetler via GitGitGadget, May 22, 2021
  102. 11/28 fsmonitor-fs-listen-win32: stub in backend for WindowsJeff Hostetler via GitGitGadget, May 22, 2021
  103. 13/28 fsmonitor--daemon: implement daemon command optionsJeff Hostetler via GitGitGadget, May 22, 2021
  104. 14/28 fsmonitor--daemon: add pathname classificationJeff Hostetler via GitGitGadget, May 22, 2021
  105. 17/28 fsmonitor-fs-listen-win32: implement FSMonitor backend on WindowsJeff Hostetler via GitGitGadget, May 22, 2021
  106. 16/28 fsmonitor--daemon: create token-based changed path cacheJeff Hostetler via GitGitGadget, May 22, 2021
  107. 15/28 fsmonitor--daemon: define token-idsJeff Hostetler via GitGitGadget, May 22, 2021
  108. 24/28 fsmonitor: force update index after large responsesJeff Hostetler via GitGitGadget, May 22, 2021
  109. 20/28 fsmonitor--daemon: implement handle_client callbackJeff Hostetler via GitGitGadget, May 22, 2021
  110. 21/28 fsmonitor--daemon: periodically truncate list of modified filesJeff Hostetler via GitGitGadget, May 22, 2021
  111. 19/28 fsmonitor-fs-listen-macos: implement FSEvent listener on MacOSJeff Hostetler via GitGitGadget, May 22, 2021
  112. 18/28 fsmonitor-fs-listen-macos: add macos header files for FSEventJeff Hostetler via GitGitGadget, May 22, 2021
  113. 23/28 fsmonitor: enhance existing commentsJeff Hostetler via GitGitGadget, May 22, 2021
  114. 22/28 fsmonitor--daemon: use a cookie file to sync with file systemJeff Hostetler via GitGitGadget, May 22, 2021
  115. Johannes SchindelinJun 14, 2021
  116. 25/28 t7527: create test for fsmonitor--daemonJeff Hostetler via GitGitGadget, May 22, 2021
  117. 26/28 p7519: add fsmonitor--daemonJeff Hostetler via GitGitGadget, May 22, 2021
  118. 27/28 t7527: test status with untracked-cache and fsmonitor--daemonJeff Hostetler via GitGitGadget, May 22, 2021
  119. 28/28 t/perf: avoid copying builtin fsmonitor files into test repoJeff Hostetler via GitGitGadget, May 22, 2021
  120. Junio C HamanoMay 27, 2021
  121. Johannes SchindelinJun 2, 2021
  122. Jeff HostetlerJun 22, 2021
  123. 00/34 Builtin FSMonitor FeatureJeff Hostetler via GitGitGadget, Jul 1, 2021
  124. 02/34 fsmonitor--daemon: man pageJeff Hostetler via GitGitGadget, Jul 1, 2021
  125. Ævar Arnfjörð BjarmasonJul 1, 2021
  126. Johannes SchindelinJul 5, 2021
  127. Jeff HostetlerJul 12, 2021
  128. Ævar Arnfjörð BjarmasonJul 13, 2021
  129. Johannes SchindelinJul 16, 2021
  130. Felipe ContrerasJul 16, 2021
  131. 01/34 simple-ipc: preparations for supporting binary messages.Jeff Hostetler via GitGitGadget, Jul 1, 2021
  132. 04/34 fsmonitor-ipc: create client routines for git-fsmonitor--daemonJeff Hostetler via GitGitGadget, Jul 1, 2021
  133. 05/34 help: include fsmonitor--daemon feature flag in version infoJeff Hostetler via GitGitGadget, Jul 1, 2021
  134. 03/34 fsmonitor--daemon: update fsmonitor documentationJeff Hostetler via GitGitGadget, Jul 1, 2021
  135. Ævar Arnfjörð BjarmasonJul 1, 2021
  136. 07/34 fsmonitor: use IPC to query the builtin FSMonitor daemonJeff Hostetler via GitGitGadget, Jul 1, 2021
  137. 08/34 fsmonitor--daemon: add a built-in fsmonitor daemonJeff Hostetler via GitGitGadget, Jul 1, 2021
  138. Ævar Arnfjörð BjarmasonJul 1, 2021
  139. Jeff HostetlerJul 19, 2021
  140. 06/34 fsmonitor: config settings are repository-specificJeff Hostetler via GitGitGadget, Jul 1, 2021
  141. Ævar Arnfjörð BjarmasonJul 1, 2021
  142. Jeff HostetlerJul 19, 2021
  143. 09/34 fsmonitor--daemon: implement 'stop' and 'status' commandsJeff Hostetler via GitGitGadget, Jul 1, 2021
  144. 11/34 fsmonitor-fs-listen-win32: stub in backend for WindowsJeff Hostetler via GitGitGadget, Jul 1, 2021
  145. Ævar Arnfjörð BjarmasonJul 1, 2021
  146. Johannes SchindelinJul 16, 2021
  147. Ævar Arnfjörð BjarmasonJul 16, 2021
  148. Junio C HamanoJul 17, 2021
  149. Junio C HamanoJul 17, 2021
  150. Ævar Arnfjörð BjarmasonJul 17, 2021
  151. Junio C HamanoJul 19, 2021
  152. Felipe ContrerasJul 16, 2021
  153. Jeff HostetlerJul 19, 2021
  154. Ævar Arnfjörð BjarmasonJul 20, 2021
  155. 13/34 fsmonitor--daemon: implement 'run' commandJeff Hostetler via GitGitGadget, Jul 1, 2021
  156. 10/34 t/helper/fsmonitor-client: create IPC client to talk to FSMonitor DaemonJeff Hostetler via GitGitGadget, Jul 1, 2021
  157. Ævar Arnfjörð BjarmasonJul 1, 2021
  158. 12/34 fsmonitor-fs-listen-macos: stub in backend for MacOSJeff Hostetler via GitGitGadget, Jul 1, 2021
  159. Ævar Arnfjörð BjarmasonJul 1, 2021
  160. Johannes SchindelinJul 16, 2021
  161. Ævar Arnfjörð BjarmasonJul 16, 2021
  162. Johannes SchindelinJul 26, 2021
  163. Junio C HamanoJul 26, 2021
  164. Jeff HostetlerJul 27, 2021
  165. Ævar Arnfjörð BjarmasonJul 27, 2021
  166. Junio C HamanoJul 27, 2021
  167. Felipe ContrerasJul 27, 2021
  168. 14/34 fsmonitor--daemon: implement 'start' commandJeff Hostetler via GitGitGadget, Jul 1, 2021
  169. Ævar Arnfjörð BjarmasonJul 1, 2021
  170. Johannes SchindelinJul 5, 2021
  171. Jeff HostetlerJul 13, 2021
  172. Ævar Arnfjörð BjarmasonJul 13, 2021
  173. Jeff HostetlerJul 13, 2021
  174. Ævar Arnfjörð BjarmasonJul 20, 2021
  175. 15/34 fsmonitor: do not try to operate on bare reposJeff Hostetler via GitGitGadget, Jul 1, 2021
  176. Ævar Arnfjörð BjarmasonJul 1, 2021
  177. 16/34 fsmonitor--daemon: add pathname classificationJeff Hostetler via GitGitGadget, Jul 1, 2021
  178. 18/34 fsmonitor--daemon: create token-based changed path cacheJeff Hostetler via GitGitGadget, Jul 1, 2021
  179. 17/34 fsmonitor--daemon: define token-idsJeff Hostetler via GitGitGadget, Jul 1, 2021
  180. Ævar Arnfjörð BjarmasonJul 1, 2021
  181. Jeff HostetlerJul 13, 2021
  182. Ævar Arnfjörð BjarmasonJul 13, 2021
  183. 20/34 fsmonitor-fs-listen-macos: add macos header files for FSEventJeff Hostetler via GitGitGadget, Jul 1, 2021
  184. 19/34 fsmonitor-fs-listen-win32: implement FSMonitor backend on WindowsJeff Hostetler via GitGitGadget, Jul 1, 2021
  185. Ævar Arnfjörð BjarmasonJul 1, 2021
  186. Jeff HostetlerJul 13, 2021
  187. Ævar Arnfjörð BjarmasonJul 13, 2021
  188. Johannes SchindelinJul 16, 2021
  189. Ævar Arnfjörð BjarmasonJul 16, 2021
  190. Eric WongJul 17, 2021
  191. Jeff HostetlerJul 19, 2021
  192. Felipe ContrerasJul 16, 2021
  193. Johannes SchindelinJul 6, 2021
  194. Jeff HostetlerJul 13, 2021
  195. 23/34 t/helper/test-touch: add helper to touch a series of filesJeff Hostetler via GitGitGadget, Jul 1, 2021
  196. Junio C HamanoJul 1, 2021
  197. Jeff HostetlerJul 13, 2021
  198. 24/34 t/perf/p7519: speed up test using "test-tool touch"Jeff Hostetler via GitGitGadget, Jul 1, 2021
  199. Ævar Arnfjörð BjarmasonJul 1, 2021
  200. Jeff HostetlerJul 13, 2021
  201. Elijah NewrenJul 13, 2021
  202. Junio C HamanoJul 13, 2021
  203. Elijah NewrenJul 13, 2021
  204. Jeff HostetlerJul 13, 2021
  205. Junio C HamanoJul 13, 2021
  206. Jeff HostetlerJul 13, 2021
  207. Ævar Arnfjörð BjarmasonJul 13, 2021
  208. Jeff HostetlerJul 13, 2021
  209. Ævar Arnfjörð BjarmasonJul 20, 2021
  210. Jeff HostetlerJul 13, 2021
  211. 22/34 fsmonitor--daemon: implement handle_client callbackJeff Hostetler via GitGitGadget, Jul 1, 2021
  212. 21/34 fsmonitor-fs-listen-macos: implement FSEvent listener on MacOSJeff Hostetler via GitGitGadget, Jul 1, 2021
  213. 25/34 t/perf: avoid copying builtin fsmonitor files into test repoJeff Hostetler via GitGitGadget, Jul 1, 2021
  214. Ævar Arnfjörð BjarmasonJul 1, 2021
  215. 29/34 fsmonitor--daemon: use a cookie file to sync with file systemJeff Hostetler via GitGitGadget, Jul 1, 2021
  216. Ævar Arnfjörð BjarmasonJul 1, 2021
  217. Jeff HostetlerJul 21, 2021
  218. 27/34 t7527: create test for fsmonitor--daemonJeff Hostetler via GitGitGadget, Jul 1, 2021
  219. Ævar Arnfjörð BjarmasonJul 1, 2021
  220. 26/34 t/perf/p7519: add fsmonitor--daemon test casesJeff Hostetler via GitGitGadget, Jul 1, 2021
  221. 28/34 fsmonitor--daemon: periodically truncate list of modified filesJeff Hostetler via GitGitGadget, Jul 1, 2021
  222. 30/34 fsmonitor: enhance existing commentsJeff Hostetler via GitGitGadget, Jul 1, 2021
  223. 32/34 t7527: test status with untracked-cache and fsmonitor--daemonJeff Hostetler via GitGitGadget, Jul 1, 2021
  224. 31/34 fsmonitor: force update index after large responsesJeff Hostetler via GitGitGadget, Jul 1, 2021
  225. 33/34 fsmonitor: handle shortname for .gitJeff Hostetler via GitGitGadget, Jul 1, 2021
  226. 34/34 t7527: test FS event reporing on MacOS WRT case and UnicodeJeff Hostetler via GitGitGadget, Jul 1, 2021
  227. Ævar Arnfjörð BjarmasonJul 1, 2021
  228. Ævar Arnfjörð BjarmasonJul 1, 2021
  229. Jeff HostetlerJul 1, 2021
  230. Ævar Arnfjörð BjarmasonJul 1, 2021
  231. Jeff HostetlerJul 2, 2021
  232. Ævar Arnfjörð BjarmasonJul 5, 2021
  233. Johannes SchindelinJul 5, 2021
  234. Ævar Arnfjörð BjarmasonJul 5, 2021
  235. Johannes SchindelinJul 6, 2021
  236. Felipe ContrerasJul 7, 2021
  237. Felipe ContrerasJul 7, 2021

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.