2017-09-22 16:35:46 +00:00
|
|
|
#!/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" != 1
|
|
|
|
then
|
|
|
|
echo "Unsupported core.fsmonitor hook version." >&2
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
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' '
|
2018-09-09 17:36:30 +00:00
|
|
|
test-tool dump-fsmonitor >actual &&
|
2017-09-22 16:35:46 +00:00
|
|
|
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 &&
|
2018-09-09 17:36:30 +00:00
|
|
|
test-tool dump-fsmonitor >actual &&
|
2017-09-22 16:35:46 +00:00
|
|
|
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 &&
|
2018-09-09 17:36:30 +00:00
|
|
|
test-tool dump-fsmonitor >actual &&
|
2017-09-22 16:35:46 +00:00
|
|
|
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' '
|
|
|
|
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' '
|
|
|
|
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 "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' '
|
|
|
|
write_script .git/hooks/fsmonitor-test<<-\EOF &&
|
|
|
|
EOF
|
|
|
|
clean_repo &&
|
|
|
|
dirty_repo &&
|
|
|
|
git add . &&
|
|
|
|
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
|
2018-09-18 23:29:37 +00:00
|
|
|
GIT_TEST_PRELOAD_INDEX=$preload_val; export GIT_TEST_PRELOAD_INDEX
|
2017-09-22 16:35:46 +00:00
|
|
|
else
|
2018-09-18 23:29:37 +00:00
|
|
|
sane_unset GIT_TEST_PRELOAD_INDEX
|
2017-09-22 16:35:46 +00:00
|
|
|
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 &&
|
|
|
|
:>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
|
|
|
|
|
2017-11-09 19:58:10 +00:00
|
|
|
# test that splitting the index dosn'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 &&
|
2018-09-09 17:36:30 +00:00
|
|
|
test-tool dump-fsmonitor >&2 && echo &&
|
2017-11-09 19:58:10 +00:00
|
|
|
git update-index --fsmonitor --split-index &&
|
2018-09-09 17:36:30 +00:00
|
|
|
test-tool dump-fsmonitor >&2 && echo &&
|
2017-11-09 19:58:10 +00:00
|
|
|
git ls-files -f >actual &&
|
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
|
dir.c: ignore paths containing .git when invalidating untracked cache
read_directory() code ignores all paths named ".git" even if it's not
a valid git repository. See treat_path() for details. Since ".git" is
basically invisible to read_directory(), when we are asked to
invalidate a path that contains ".git", we can safely ignore it
because the slow path would not consider it anyway.
This helps when fsmonitor is used and we have a real ".git" repo at
worktree top. Occasionally .git/index will be updated and if the
fsmonitor hook does not filter it, untracked cache is asked to
invalidate the path ".git/index".
Without this patch, we invalidate the root directory unncessarily,
which:
- makes read_directory() fall back to slow path for root directory
(slower)
- makes the index dirty (because UNTR extension is updated). Depending
on the index size, writing it down could also be slow.
A note about the new "safe_path" knob. Since this new check could be
relatively expensive, avoid it when we know it's not needed. If the
path comes from the index, it can't contain ".git". If it does
contain, we may be screwed up at many more levels, not just this one.
Noticed-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-02-07 09:21:40 +00:00
|
|
|
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 &&
|
2018-09-09 17:36:27 +00:00
|
|
|
test-tool dump-untracked-cache >../before
|
dir.c: ignore paths containing .git when invalidating untracked cache
read_directory() code ignores all paths named ".git" even if it's not
a valid git repository. See treat_path() for details. Since ".git" is
basically invisible to read_directory(), when we are asked to
invalidate a path that contains ".git", we can safely ignore it
because the slow path would not consider it anyway.
This helps when fsmonitor is used and we have a real ".git" repo at
worktree top. Occasionally .git/index will be updated and if the
fsmonitor hook does not filter it, untracked cache is asked to
invalidate the path ".git/index".
Without this patch, we invalidate the root directory unncessarily,
which:
- makes read_directory() fall back to slow path for root directory
(slower)
- makes the index dirty (because UNTR extension is updated). Depending
on the index size, writing it down could also be slow.
A note about the new "safe_path" knob. Since this new check could be
relatively expensive, avoid it when we know it's not needed. If the
path comes from the index, it can't contain ".git". If it does
contain, we may be screwed up at many more levels, not just this one.
Noticed-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-02-07 09:21:40 +00:00
|
|
|
) &&
|
|
|
|
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 &&
|
2018-09-09 17:36:27 +00:00
|
|
|
test-tool dump-untracked-cache >../after
|
dir.c: ignore paths containing .git when invalidating untracked cache
read_directory() code ignores all paths named ".git" even if it's not
a valid git repository. See treat_path() for details. Since ".git" is
basically invisible to read_directory(), when we are asked to
invalidate a path that contains ".git", we can safely ignore it
because the slow path would not consider it anyway.
This helps when fsmonitor is used and we have a real ".git" repo at
worktree top. Occasionally .git/index will be updated and if the
fsmonitor hook does not filter it, untracked cache is asked to
invalidate the path ".git/index".
Without this patch, we invalidate the root directory unncessarily,
which:
- makes read_directory() fall back to slow path for root directory
(slower)
- makes the index dirty (because UNTR extension is updated). Depending
on the index size, writing it down could also be slow.
A note about the new "safe_path" knob. Since this new check could be
relatively expensive, avoid it when we know it's not needed. If the
path comes from the index, it can't contain ".git". If it does
contain, we may be screwed up at many more levels, not just this one.
Noticed-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-02-07 09:21:40 +00:00
|
|
|
) &&
|
|
|
|
grep "directory invalidation" trace-before >>before &&
|
|
|
|
grep "directory invalidation" trace-after >>after &&
|
|
|
|
# UNTR extension unchanged, dir invalidation count unchanged
|
|
|
|
test_cmp before after
|
|
|
|
'
|
|
|
|
|
2019-05-07 11:10:21 +00:00
|
|
|
test_expect_success 'discard_index() also discards fsmonitor info' '
|
fsmonitor: demonstrate that it is not refreshed after discard_index()
This one is tricky.
When `core.fsmonitor` is set, a `refresh_index()` will not perform a
full scan of files that might be modified, but will query the fsmonitor
and refresh only the ones that have been actually touched.
Due to implementation details, the fsmonitor is queried in
`refresh_cache_ent()`, but of course it only has to be queried once, so
we set a flag when we did that. But when the index was discarded, we did
not re-set that flag.
So far, this is only covered by our test suite when running with
GIT_TEST_FSMONITOR=$PWD/t7519/fsmonitor-all, and only due to the way the
built-in stash interacts with the recursive merge machinery.
Let's introduce a straight-forward regression test for this.
We simply extend the "read & discard index" loop in `test-tool
read-cache` to optionally refresh the index, report on a given file's
status, and then modify that file. Due to the bug described above, only
the first refresh will actually query the fsmonitor; subsequent loop
iterations will not.
This problem was reported by Ævar Arnfjörð Bjarmason.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-05-07 11:10:20 +00:00
|
|
|
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
|
|
|
|
'
|
|
|
|
|
2019-10-16 19:35:47 +00:00
|
|
|
# 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' '
|
2019-10-11 20:11:23 +00:00
|
|
|
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
|
|
|
|
)
|
|
|
|
'
|
|
|
|
|
2017-09-22 16:35:46 +00:00
|
|
|
test_done
|