diff options
| author | Paul Tarjan <github@paulisageek.com> | 2026-02-28 17:37:57 +0000 |
|---|---|---|
| committer | Junio C Hamano <gitster@pobox.com> | 2026-03-02 08:15:18 -0800 |
| commit | 41366e46779865164e3e8af2bac6eb95ea6f6586 (patch) | |
| tree | d4ce4994fef7c35baf0d304a762f2f3deb4ea1dc | |
| parent | 67ad42147a7acc2af6074753ebd03d904476118f (diff) | |
| download | git-41366e46779865164e3e8af2bac6eb95ea6f6586.tar.xz | |
fsmonitor-watchman: fix variable reference and remove redundant code
The is_work_tree_watched() function in fsmonitor-watchman.sample has
two bugs:
1. Wrong variable in error check: After calling watchman_clock(), the
result is stored in $o, but the code checks $output->{error} instead
of $o->{error}. This means errors from the clock command are silently
ignored.
2. Double output violates protocol: When the retry path triggers (the
directory wasn't initially watched), output_result() is called with
the "/" flag, then launch_watchman() is called recursively which
calls output_result() again. This outputs two clock tokens to stdout,
but git's fsmonitor v2 protocol expects exactly one response.
Fix #1 by checking $o->{error} after watchman_clock().
Fix #2 by removing the recursive launch_watchman() call. The "/"
"everything is dirty" flag already tells git to do a full scan, and
git will call the hook again on the next invocation with a valid clock
token.
With the recursive call removed, the $retry guard is no longer needed
since it only existed to prevent infinite recursion. Remove it.
Apply the same fixes to the test helper scripts in t/t7519/.
Signed-off-by: Paul Tarjan <github@paulisageek.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
| -rwxr-xr-x | t/t7519/fsmonitor-watchman | 6 | ||||
| -rwxr-xr-x | t/t7519/fsmonitor-watchman-v2 | 10 | ||||
| -rwxr-xr-x | templates/hooks/fsmonitor-watchman.sample | 10 |
3 files changed, 5 insertions, 21 deletions
diff --git a/t/t7519/fsmonitor-watchman b/t/t7519/fsmonitor-watchman index 264b9daf83..bcc055c1e0 100755 --- a/t/t7519/fsmonitor-watchman +++ b/t/t7519/fsmonitor-watchman @@ -38,8 +38,6 @@ if ($^O =~ 'msys' || $^O =~ 'cygwin') { $git_work_tree = Cwd::cwd(); } -my $retry = 1; - launch_watchman(); sub launch_watchman { @@ -92,9 +90,8 @@ sub launch_watchman { my $o = $json_pkg->new->utf8->decode($response); - if ($retry > 0 and $o->{error} and $o->{error} =~ m/unable to resolve root .* directory (.*) is not watched/) { + if ($o->{error} and $o->{error} =~ m/unable to resolve root .* directory (.*) is not watched/) { print STDERR "Adding '$git_work_tree' to watchman's watch list.\n"; - $retry--; qx/watchman watch "$git_work_tree"/; die "Failed to make watchman watch '$git_work_tree'.\n" . "Falling back to scanning...\n" if $? != 0; @@ -109,7 +106,6 @@ sub launch_watchman { close $fh; print "/\0"; - eval { launch_watchman() }; exit 0; } diff --git a/t/t7519/fsmonitor-watchman-v2 b/t/t7519/fsmonitor-watchman-v2 index 14ed0aa42d..368604c278 100755 --- a/t/t7519/fsmonitor-watchman-v2 +++ b/t/t7519/fsmonitor-watchman-v2 @@ -29,8 +29,6 @@ if ($version ne 2) { my $git_work_tree = get_working_dir(); -my $retry = 1; - my $json_pkg; eval { require JSON::XS; @@ -122,8 +120,7 @@ sub watchman_query { sub is_work_tree_watched { my ($output) = @_; my $error = $output->{error}; - if ($retry > 0 and $error and $error =~ m/unable to resolve root .* directory (.*) is not watched/) { - $retry--; + if ($error and $error =~ m/unable to resolve root .* directory (.*) is not watched/) { my $response = qx/watchman watch "$git_work_tree"/; die "Failed to make watchman watch '$git_work_tree'.\n" . "Falling back to scanning...\n" if $? != 0; @@ -141,15 +138,12 @@ sub is_work_tree_watched { # Watchman query just to get it over with now so we won't pay # the cost in git to look up each individual file. my $o = watchman_clock(); - $error = $output->{error}; + $error = $o->{error}; die "Watchman: $error.\n" . "Falling back to scanning...\n" if $error; output_result($o->{clock}, ("/")); - $last_update_token = $o->{clock}; - - eval { launch_watchman() }; return 0; } diff --git a/templates/hooks/fsmonitor-watchman.sample b/templates/hooks/fsmonitor-watchman.sample index 23e856f5de..429e0a51c1 100755 --- a/templates/hooks/fsmonitor-watchman.sample +++ b/templates/hooks/fsmonitor-watchman.sample @@ -29,8 +29,6 @@ if ($version ne 2) { my $git_work_tree = get_working_dir(); -my $retry = 1; - my $json_pkg; eval { require JSON::XS; @@ -123,8 +121,7 @@ sub watchman_query { sub is_work_tree_watched { my ($output) = @_; my $error = $output->{error}; - if ($retry > 0 and $error and $error =~ m/unable to resolve root .* directory (.*) is not watched/) { - $retry--; + if ($error and $error =~ m/unable to resolve root .* directory (.*) is not watched/) { my $response = qx/watchman watch "$git_work_tree"/; die "Failed to make watchman watch '$git_work_tree'.\n" . "Falling back to scanning...\n" if $? != 0; @@ -142,15 +139,12 @@ sub is_work_tree_watched { # Watchman query just to get it over with now so we won't pay # the cost in git to look up each individual file. my $o = watchman_clock(); - $error = $output->{error}; + $error = $o->{error}; die "Watchman: $error.\n" . "Falling back to scanning...\n" if $error; output_result($o->{clock}, ("/")); - $last_update_token = $o->{clock}; - - eval { launch_watchman() }; return 0; } |
