#!/bin/sh test_description='git status with file system watcher' . ./test-lib.sh # Note, after "git reset --hard HEAD" no extensions exist other than 'TREE' # "git update-index --fsmonitor" can be used to get the extension written # before testing the results. clean_repo () { git reset --hard HEAD && git clean -fd } dirty_repo () { : >untracked && : >dir1/untracked && : >dir2/untracked && echo 1 >modified && echo 2 >dir1/modified && echo 3 >dir2/modified && echo 4 >new && echo 5 >dir1/new && echo 6 >dir2/new } write_integration_script () { write_script .git/hooks/fsmonitor-test<<-\EOF if test "$#" -ne 2 then echo "$0: exactly 2 arguments expected" exit 2 fi if test "$1" != 2 then echo "Unsupported core.fsmonitor hook version." >&2 exit 1 fi printf "last_update_token\0" printf "untracked\0" printf "dir1/untracked\0" printf "dir2/untracked\0" printf "modified\0" printf "dir1/modified\0" printf "dir2/modified\0" printf "new\0" printf "dir1/new\0" printf "dir2/new\0" EOF } test_lazy_prereq UNTRACKED_CACHE ' { git update-index --test-untracked-cache; ret=$?; } && test $ret -ne 1 ' test_expect_success 'setup' ' mkdir -p .git/hooks && : >tracked && : >modified && mkdir dir1 && : >dir1/tracked && : >dir1/modified && mkdir dir2 && : >dir2/tracked && : >dir2/modified && git -c core.fsmonitor= add . && git -c core.fsmonitor= commit -m initial && git config core.fsmonitor .git/hooks/fsmonitor-test && cat >.gitignore <<-\EOF .gitignore expect* actual* marker* EOF ' # test that the fsmonitor extension is off by default test_expect_success 'fsmonitor extension is off by default' ' test-tool dump-fsmonitor >actual && grep "^no fsmonitor" actual ' # test that "update-index --fsmonitor" adds the fsmonitor extension test_expect_success 'update-index --fsmonitor" adds the fsmonitor extension' ' git update-index --fsmonitor && test-tool dump-fsmonitor >actual && grep "^fsmonitor last update" actual ' # test that "update-index --no-fsmonitor" removes the fsmonitor extension test_expect_success 'update-index --no-fsmonitor" removes the fsmonitor extension' ' git update-index --no-fsmonitor && test-tool dump-fsmonitor >actual && 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' ' write_script .git/hooks/fsmonitor-test<<-\EOF && printf "last_update_token\0" EOF 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 H dir2/modified H dir2/tracked H modified H tracked EOF # test that all files returned by the script get flagged as invalid test_expect_success 'all files returned by integration script get flagged as invalid' ' write_integration_script && dirty_repo && git update-index --fsmonitor && git ls-files -f >actual && test_cmp expect actual ' cat >expect <<EOF && H dir1/modified h dir1/new H dir1/tracked H dir2/modified h dir2/new H dir2/tracked H modified h new H tracked EOF # test that newly added files are marked valid test_expect_success 'newly added files are marked valid' ' write_script .git/hooks/fsmonitor-test<<-\EOF && printf "last_update_token\0" EOF git add new && git add dir1/new && git add dir2/new && git ls-files -f >actual && test_cmp expect actual ' cat >expect <<EOF && H dir1/modified h dir1/new h dir1/tracked H dir2/modified h dir2/new h dir2/tracked H modified h new h tracked EOF # test that all unmodified files get marked valid test_expect_success 'all unmodified files get marked valid' ' # modified files result in update-index returning 1 test_must_fail git update-index --refresh --force-write-index && 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 *only* files returned by the integration script get flagged as invalid test_expect_success '*only* files returned by the integration script get flagged as invalid' ' write_script .git/hooks/fsmonitor-test<<-\EOF && printf "last_update_token\0" printf "dir1/modified\0" EOF clean_repo && git update-index --refresh --force-write-index && echo 1 >modified && echo 2 >dir1/modified && echo 3 >dir2/modified && test_must_fail git update-index --refresh --force-write-index && git ls-files -f >actual && test_cmp expect actual ' # Ensure commands that call refresh_index() to move the index back in time # properly invalidate the fsmonitor cache test_expect_success 'refresh_index() invalidates fsmonitor cache' ' clean_repo && dirty_repo && write_integration_script && git add . && write_script .git/hooks/fsmonitor-test<<-\EOF && EOF git commit -m "to reset" && git reset HEAD~1 && git status >actual && git -c core.fsmonitor= status >expect && test_i18ncmp expect actual ' # test fsmonitor with and without preloadIndex preload_values="false true" for preload_val in $preload_values do test_expect_success "setup preloadIndex to $preload_val" ' git config core.preloadIndex $preload_val && if test $preload_val = true then GIT_TEST_PRELOAD_INDEX=$preload_val; export GIT_TEST_PRELOAD_INDEX else sane_unset GIT_TEST_PRELOAD_INDEX fi ' # test fsmonitor with and without the untracked cache (if available) uc_values="false" test_have_prereq UNTRACKED_CACHE && uc_values="false true" for uc_val in $uc_values do test_expect_success "setup untracked cache to $uc_val" ' git config core.untrackedcache $uc_val ' # Status is well tested elsewhere so we'll just ensure that the results are # the same when using core.fsmonitor. test_expect_success 'compare status with and without fsmonitor' ' write_integration_script && clean_repo && dirty_repo && git add new && git add dir1/new && git add dir2/new && git status >actual && git -c core.fsmonitor= status >expect && test_i18ncmp expect actual ' # Make sure it's actually skipping the check for modified and untracked # (if enabled) files unless it is told about them. test_expect_success "status doesn't detect unreported modifications" ' write_script .git/hooks/fsmonitor-test<<-\EOF && printf "last_update_token\0" :>marker EOF clean_repo && git status && test_path_is_file marker && dirty_repo && rm -f marker && git status >actual && test_path_is_file marker && test_i18ngrep ! "Changes not staged for commit:" actual && 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 done # test that splitting the index doesn't interfere test_expect_success 'splitting the index results in the same state' ' write_integration_script && dirty_repo && git update-index --fsmonitor && git ls-files -f >expect && test-tool dump-fsmonitor >&2 && echo && git update-index --fsmonitor --split-index && test-tool dump-fsmonitor >&2 && echo && git ls-files -f >actual && test_cmp expect actual ' test_expect_success UNTRACKED_CACHE 'ignore .git changes when invalidating UNTR' ' test_create_repo dot-git && ( cd dot-git && mkdir -p .git/hooks && : >tracked && : >modified && mkdir dir1 && : >dir1/tracked && : >dir1/modified && mkdir dir2 && : >dir2/tracked && : >dir2/modified && write_integration_script && git config core.fsmonitor .git/hooks/fsmonitor-test && git update-index --untracked-cache && git update-index --fsmonitor && GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace-before" \ git status && test-tool dump-untracked-cache >../before ) && cat >>dot-git/.git/hooks/fsmonitor-test <<-\EOF && printf ".git\0" printf ".git/index\0" printf "dir1/.git\0" printf "dir1/.git/index\0" EOF ( cd dot-git && GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace-after" \ git status && test-tool dump-untracked-cache >../after ) && grep "directory invalidation" trace-before >>before && grep "directory invalidation" trace-after >>after && # UNTR extension unchanged, dir invalidation count unchanged test_cmp before after ' test_expect_success 'discard_index() also discards fsmonitor info' ' test_config core.fsmonitor "$TEST_DIRECTORY/t7519/fsmonitor-all" && test_might_fail git update-index --refresh && test-tool read-cache --print-and-refresh=tracked 2 >actual && printf "tracked is%s up to date\n" "" " not" >expect && test_cmp expect actual ' # Test unstaging entries that: # - Are not flagged with CE_FSMONITOR_VALID # - Have a position in the index >= the number of entries present in the index # after unstaging. test_expect_success 'status succeeds after staging/unstaging' ' test_create_repo fsmonitor-stage-unstage && ( cd fsmonitor-stage-unstage && test_commit initial && git update-index --fsmonitor && removed=$(test_seq 1 100 | sed "s/^/z/") && touch $removed && git add $removed && git config core.fsmonitor "$TEST_DIRECTORY/t7519/fsmonitor-env" && FSMONITOR_LIST="$removed" git restore -S $removed && FSMONITOR_LIST="$removed" git status ) ' test_done