3 test_description
='git status with file system watcher'
7 # Note, after "git reset --hard HEAD" no extensions exist other than 'TREE'
8 # "git update-index --fsmonitor" can be used to get the extension written
9 # before testing the results.
12 git
reset --hard HEAD
&&
21 echo 2 >dir
1/modified
&&
22 echo 3 >dir
2/modified
&&
28 write_integration_script
() {
29 write_script .git
/hooks
/fsmonitor-test
<<-\EOF
32 echo "$0: exactly 2 arguments expected"
37 echo "Unsupported core.fsmonitor hook version." >&2
40 printf "last_update_token\0"
42 printf "dir1/untracked\0"
43 printf "dir2/untracked\0"
45 printf "dir1/modified\0"
46 printf "dir2/modified\0"
53 test_lazy_prereq UNTRACKED_CACHE '
54 { git update-index --test-untracked-cache; ret=$?; } &&
58 test_expect_success 'setup' '
59 mkdir -p .git/hooks &&
68 git -c core.fsmonitor= add . &&
69 git -c core.fsmonitor= commit -m initial &&
70 git config core.fsmonitor .git/hooks/fsmonitor-test &&
71 cat >.gitignore <<-\
EOF
80 # test that the fsmonitor extension is off by default
81 test_expect_success 'fsmonitor extension is off by default' '
82 test-tool dump-fsmonitor >actual &&
83 grep "^no fsmonitor" actual
86 # test that "update-index --fsmonitor" adds the fsmonitor extension
87 test_expect_success 'update-index --fsmonitor" adds the fsmonitor extension' '
88 git update-index --fsmonitor &&
89 test-tool dump-fsmonitor >actual &&
90 grep "^fsmonitor last update" actual
93 # test that "update-index --no-fsmonitor" removes the fsmonitor extension
94 test_expect_success 'update-index --no-fsmonitor" removes the fsmonitor extension' '
95 git update-index --no-fsmonitor &&
96 test-tool dump-fsmonitor >actual &&
97 grep "^no fsmonitor" actual
109 # test that "update-index --fsmonitor-valid" sets the fsmonitor valid bit
110 test_expect_success 'update-index --fsmonitor-valid" sets the fsmonitor valid bit' '
111 write_script .git/hooks/fsmonitor-test<<-\EOF &&
112 printf "last_update_token\0"
114 git update-index --fsmonitor &&
115 git update-index --fsmonitor-valid dir1/modified &&
116 git update-index --fsmonitor-valid dir2/modified &&
117 git update-index --fsmonitor-valid modified &&
118 git ls-files -f >actual &&
119 test_cmp expect actual
131 # test that "update-index --no-fsmonitor-valid" clears the fsmonitor valid bit
132 test_expect_success 'update-index --no-fsmonitor-valid" clears the fsmonitor valid bit' '
133 git update-index --no-fsmonitor-valid dir1/modified &&
134 git update-index --no-fsmonitor-valid dir2/modified &&
135 git update-index --no-fsmonitor-valid modified &&
136 git ls-files -f >actual &&
137 test_cmp expect actual
149 # test that all files returned by the script get flagged as invalid
150 test_expect_success 'all files returned by integration script get flagged as invalid' '
151 write_integration_script &&
153 git update-index --fsmonitor &&
154 git ls-files -f >actual &&
155 test_cmp expect actual
170 # test that newly added files are marked valid
171 test_expect_success 'newly added files are marked valid' '
172 write_script .git/hooks/fsmonitor-test<<-\EOF &&
173 printf "last_update_token\0"
178 git ls-files -f >actual &&
179 test_cmp expect actual
194 # test that all unmodified files get marked valid
195 test_expect_success 'all unmodified files get marked valid' '
196 # modified files result in update-index returning 1
197 test_must_fail git update-index --refresh --force-write-index &&
198 git ls-files -f >actual &&
199 test_cmp expect actual
211 # test that *only* files returned by the integration script get flagged as invalid
212 test_expect_success '*only* files returned by the integration script get flagged as invalid' '
213 write_script .git/hooks/fsmonitor-test<<-\EOF &&
214 printf "last_update_token\0"
215 printf "dir1/modified\0"
218 git update-index --refresh --force-write-index &&
220 echo 2 >dir1/modified &&
221 echo 3 >dir2/modified &&
222 test_must_fail git update-index --refresh --force-write-index &&
223 git ls-files -f >actual &&
224 test_cmp expect actual
227 # Ensure commands that call refresh_index() to move the index back in time
228 # properly invalidate the fsmonitor cache
229 test_expect_success 'refresh_index() invalidates fsmonitor cache' '
232 write_integration_script &&
234 write_script .git/hooks/fsmonitor-test<<-\EOF &&
236 git commit -m "to reset" &&
238 git status >actual &&
239 git -c core.fsmonitor= status >expect &&
240 test_cmp expect actual
243 # test fsmonitor with and without preloadIndex
244 preload_values="false true"
245 for preload_val in $preload_values
247 test_expect_success "setup preloadIndex to $preload_val" '
248 git config core.preloadIndex $preload_val &&
249 if test $preload_val = true
251 GIT_TEST_PRELOAD_INDEX=$preload_val; export GIT_TEST_PRELOAD_INDEX
253 sane_unset GIT_TEST_PRELOAD_INDEX
257 # test fsmonitor with and without the untracked cache (if available)
259 test_have_prereq UNTRACKED_CACHE && uc_values="false true"
260 for uc_val in $uc_values
262 test_expect_success "setup untracked cache to $uc_val" '
263 git config core.untrackedcache $uc_val
266 # Status is well tested elsewhere so we'll just ensure that the results are
267 # the same when using core.fsmonitor.
268 test_expect_success 'compare status with and without fsmonitor' '
269 write_integration_script &&
275 git status >actual &&
276 git -c core.fsmonitor= status >expect &&
277 test_cmp expect actual
280 # Make sure it's actually skipping the check for modified and untracked
281 # (if enabled) files unless it is told about them.
282 test_expect_success "status doesn't detect unreported modifications" '
283 write_script .git/hooks/fsmonitor-test<<-\EOF &&
284 printf "last_update_token\0"
289 test_path_is_file marker &&
292 git status >actual &&
293 test_path_is_file marker &&
294 test_i18ngrep ! "Changes not staged for commit:" actual &&
295 if test $uc_val = true
297 test_i18ngrep ! "Untracked files:" actual
299 if test $uc_val = false
301 test_i18ngrep "Untracked files:" actual
308 # test that splitting the index doesn't interfere
309 test_expect_success 'splitting the index results in the same state' '
310 write_integration_script &&
312 git update-index --fsmonitor &&
313 git ls-files -f >expect &&
314 test-tool dump-fsmonitor >&2 && echo &&
315 git update-index --fsmonitor --split-index &&
316 test-tool dump-fsmonitor >&2 && echo &&
317 git ls-files -f >actual &&
318 test_cmp expect actual
321 test_expect_success UNTRACKED_CACHE 'ignore .git changes when invalidating UNTR' '
322 test_create_repo dot-git &&
325 mkdir -p .git/hooks &&
334 write_integration_script &&
335 git config core.fsmonitor .git/hooks/fsmonitor-test &&
336 git update-index --untracked-cache &&
337 git update-index --fsmonitor &&
338 GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace-before" \
340 test-tool dump-untracked-cache >../before
342 cat >>dot-git/.git/hooks/fsmonitor-test <<-\EOF &&
344 printf ".git/index\0"
346 printf "dir1/.git/index\0"
350 GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace-after" \
352 test-tool dump-untracked-cache >../after
354 grep "directory-invalidation" trace-before | cut -d"|" -f 9 >>before &&
355 grep "directory-invalidation" trace-after | cut -d"|" -f 9 >>after &&
356 # UNTR extension unchanged, dir invalidation count unchanged
357 test_cmp before after
360 test_expect_success 'discard_index() also discards fsmonitor info' '
361 test_config core.fsmonitor "$TEST_DIRECTORY/t7519/fsmonitor-all" &&
362 test_might_fail git update-index --refresh &&
363 test-tool read-cache --print-and-refresh=tracked 2 >actual &&
364 printf "tracked is%s up to date\n" "" " not" >expect &&
365 test_cmp expect actual
368 # Test unstaging entries that:
369 # - Are not flagged with CE_FSMONITOR_VALID
370 # - Have a position in the index >= the number of entries present in the index
372 test_expect_success
'status succeeds after staging/unstaging' '
373 test_create_repo fsmonitor-stage-unstage &&
375 cd fsmonitor-stage-unstage &&
376 test_commit initial &&
377 git update-index --fsmonitor &&
378 removed=$(test_seq 1 100 | sed "s/^/z/") &&
381 git config core.fsmonitor "$TEST_DIRECTORY/t7519/fsmonitor-env" &&
382 FSMONITOR_LIST="$removed" git restore -S $removed &&
383 FSMONITOR_LIST="$removed" git status
388 # check_sparse_index_behavior [!]
389 # If "!" is supplied, then we verify that we do not call ensure_full_index
390 # during a call to 'git status'. Otherwise, we verify that we _do_ call it.
391 check_sparse_index_behavior
() {
392 git
-C full status
--porcelain=v2
>expect
&&
393 GIT_TRACE2_EVENT
="$(pwd)/trace2.txt" \
394 git
-C sparse status
--porcelain=v2
>actual
&&
395 test_region
$1 index ensure_full_index trace2.txt
&&
396 test_region fsm_hook query trace2.txt
&&
397 test_cmp expect actual
&&
401 test_expect_success
'status succeeds with sparse index' '
403 sane_unset GIT_TEST_SPLIT_INDEX &&
406 git clone --sparse . sparse &&
407 git -C sparse sparse-checkout init --cone --sparse-index &&
408 git -C sparse sparse-checkout set dir1 dir2 &&
410 write_script .git/hooks/fsmonitor-test <<-\EOF &&
411 printf "last_update_token\0"
413 git -C full config core.fsmonitor ../.git/hooks/fsmonitor-test &&
414 git -C sparse config core.fsmonitor ../.git/hooks/fsmonitor-test &&
415 check_sparse_index_behavior ! &&
417 write_script .git/hooks/fsmonitor-test <<-\EOF &&
418 printf "last_update_token\0"
419 printf "dir1/modified\0"
421 check_sparse_index_behavior ! &&
423 git -C sparse sparse-checkout add dir1a &&
425 for repo in full sparse
427 cp -r $repo/dir1 $repo/dir1a &&
428 git -C $repo add dir1a &&
429 git -C $repo commit -m "add dir1a" || return 1
431 git -C sparse sparse-checkout set dir1 dir2 &&
433 # This one modifies outside the sparse-checkout definition
434 # and hence we expect to expand the sparse-index.
435 write_script .git/hooks/fsmonitor-test <<-\EOF &&
436 printf "last_update_token\0"
437 printf "dir1a/modified\0"
439 check_sparse_index_behavior