mirror of
https://github.com/git/git
synced 2024-08-25 02:35:46 +00:00
![Kevin Willford](/assets/img/avatar_default.png)
Some file monitors like watchman will use something other than a timestamp to keep better track of what changes happen in between calls to query the fsmonitor. The clockid in watchman is a string. Now that the index is storing an opaque token for the last update the code needs to be updated to pass that opaque token to a verion 2 of the fsmonitor hook. Because there are repos that already have version 1 of the hook and we want them to continue to work when git is updated, we need to handle both version 1 and version 2 of the hook. In order to do that a config value is being added core.fsmonitorHookVersion to force what version of the hook should be used. When this is not set it will default to -1 and then the code will attempt to call version 2 of the hook first. If that fails it will fallback to trying version 1. Signed-off-by: Kevin Willford <Kevin.Willford@microsoft.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
387 lines
9.8 KiB
Bash
Executable file
387 lines
9.8 KiB
Bash
Executable file
#!/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
|