b640313110
Let's start with how create a new directory cache after the last one becomes invalid (e.g. because its dir mtime has changed...). In open_cached_dir(): 1. We start out with valid_cached_dir() returning false, which should call invalidate_directory() to put a directory state back to initial state, no untracked entries (untracked_nr zero), no sub directory traversal (dirs[].recurse zero). 2. Since the cache cannot be used, we go the slow path opendir() and go through items one by one via readdir(). All the directories on disk will be added back to the cache (if not already exist in dirs[]) and its flag "recurse" gets changed to one to note that it's part of the cached dir travesal next time. 3. By the time we reach close_cached_dir() we should have a good subdir list in dirs[]. Those with "recurse" flag set are the ones present in the on-disk directory. The directory is now marked "valid". Next time read_directory() is called, since the directory is marked valid, it will skip readdir(), go fast path and traverse through dirs[] array instead. Steps one and two need some tight cooperation. If a subdir is removed, readdir() will not find it and of course we cannot examine/invalidate it. To make sure removed directories on disk are gone from the cache, step one must make sure recurse flag of all subdirs are zero. But that's not true. If "valid" flag is already false, there is a chance we go straight to the end of valid_cached_dir() without calling invalidate_directory(). Or we fail to meet the "if (untracked-valid)" condition and skip over the invalidate_directory(). After step 3, we mark the cache valid. Any stale subdir with incorrect recurse flag becomes a real subdir next time we traverse the directory using dirs[] array. We could avoid this by making sure invalidate_directory() is always called (therefore dirs[].recurse cleared) at the beginning of open_cached_dir(). Which is what this patch does. As to how we get into this situation, the key in the test is this command git checkout master where "one/file" is replaced with "one" in the index. This index update triggers untracked_cache_invalidate_path(), which clears valid flag of the root directory while keeping "recurse" flag on the subdir "one" on. On the next git-status, we go through steps 1-3 above and save an incorrect cache on disk. The second git-status blindly follows the bad cache data and shows the problem. This is arguably because of a bad design where "recurse" flag plays double roles: whether a directory should be saved on disk, and whether it is part of a directory traversal. We need to keep recurse flag set at "checkout master" because of the first role: we need to keep subdir caches (dir "two" for example has not been touched at all, no reason to throw its cache away). As long as we make sure to ignore/reset "recurse" flag at the beginning of a directory traversal, we're good. But maybe eventually we should separate these two roles. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
774 lines
21 KiB
Bash
Executable File
774 lines
21 KiB
Bash
Executable File
#!/bin/sh
|
|
|
|
test_description='test untracked cache'
|
|
|
|
. ./test-lib.sh
|
|
|
|
# On some filesystems (e.g. FreeBSD's ext2 and ufs) directory mtime
|
|
# is updated lazily after contents in the directory changes, which
|
|
# forces the untracked cache code to take the slow path. A test
|
|
# that wants to make sure that the fast path works correctly should
|
|
# call this helper to make mtime of the containing directory in sync
|
|
# with the reality before checking the fast path behaviour.
|
|
#
|
|
# See <20160803174522.5571-1-pclouds@gmail.com> if you want to know
|
|
# more.
|
|
|
|
sync_mtime () {
|
|
find . -type d -ls >/dev/null
|
|
}
|
|
|
|
avoid_racy() {
|
|
sleep 1
|
|
}
|
|
|
|
status_is_clean() {
|
|
>../status.expect &&
|
|
git status --porcelain >../status.actual &&
|
|
test_cmp ../status.expect ../status.actual
|
|
}
|
|
|
|
test_lazy_prereq UNTRACKED_CACHE '
|
|
{ git update-index --test-untracked-cache; ret=$?; } &&
|
|
test $ret -ne 1
|
|
'
|
|
|
|
if ! test_have_prereq UNTRACKED_CACHE; then
|
|
skip_all='This system does not support untracked cache'
|
|
test_done
|
|
fi
|
|
|
|
test_expect_success 'core.untrackedCache is unset' '
|
|
test_must_fail git config --get core.untrackedCache
|
|
'
|
|
|
|
test_expect_success 'setup' '
|
|
git init worktree &&
|
|
cd worktree &&
|
|
mkdir done dtwo dthree &&
|
|
touch one two three done/one dtwo/two dthree/three &&
|
|
git add one two done/one &&
|
|
: >.git/info/exclude &&
|
|
git update-index --untracked-cache
|
|
'
|
|
|
|
test_expect_success 'untracked cache is empty' '
|
|
test-dump-untracked-cache >../actual &&
|
|
cat >../expect-empty <<EOF &&
|
|
info/exclude 0000000000000000000000000000000000000000
|
|
core.excludesfile 0000000000000000000000000000000000000000
|
|
exclude_per_dir .gitignore
|
|
flags 00000006
|
|
EOF
|
|
test_cmp ../expect-empty ../actual
|
|
'
|
|
|
|
cat >../status.expect <<EOF &&
|
|
A done/one
|
|
A one
|
|
A two
|
|
?? dthree/
|
|
?? dtwo/
|
|
?? three
|
|
EOF
|
|
|
|
cat >../dump.expect <<EOF &&
|
|
info/exclude $EMPTY_BLOB
|
|
core.excludesfile 0000000000000000000000000000000000000000
|
|
exclude_per_dir .gitignore
|
|
flags 00000006
|
|
/ 0000000000000000000000000000000000000000 recurse valid
|
|
dthree/
|
|
dtwo/
|
|
three
|
|
/done/ 0000000000000000000000000000000000000000 recurse valid
|
|
/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
|
|
three
|
|
/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
|
|
two
|
|
EOF
|
|
|
|
test_expect_success 'status first time (empty cache)' '
|
|
avoid_racy &&
|
|
: >../trace &&
|
|
GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
|
|
git status --porcelain >../actual &&
|
|
test_cmp ../status.expect ../actual &&
|
|
cat >../trace.expect <<EOF &&
|
|
node creation: 3
|
|
gitignore invalidation: 1
|
|
directory invalidation: 0
|
|
opendir: 4
|
|
EOF
|
|
test_cmp ../trace.expect ../trace
|
|
'
|
|
|
|
test_expect_success 'untracked cache after first status' '
|
|
test-dump-untracked-cache >../actual &&
|
|
test_cmp ../dump.expect ../actual
|
|
'
|
|
|
|
test_expect_success 'status second time (fully populated cache)' '
|
|
avoid_racy &&
|
|
: >../trace &&
|
|
GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
|
|
git status --porcelain >../actual &&
|
|
test_cmp ../status.expect ../actual &&
|
|
cat >../trace.expect <<EOF &&
|
|
node creation: 0
|
|
gitignore invalidation: 0
|
|
directory invalidation: 0
|
|
opendir: 0
|
|
EOF
|
|
test_cmp ../trace.expect ../trace
|
|
'
|
|
|
|
test_expect_success 'untracked cache after second status' '
|
|
test-dump-untracked-cache >../actual &&
|
|
test_cmp ../dump.expect ../actual
|
|
'
|
|
|
|
test_expect_success 'modify in root directory, one dir invalidation' '
|
|
avoid_racy &&
|
|
: >four &&
|
|
: >../trace &&
|
|
GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
|
|
git status --porcelain >../actual &&
|
|
cat >../status.expect <<EOF &&
|
|
A done/one
|
|
A one
|
|
A two
|
|
?? dthree/
|
|
?? dtwo/
|
|
?? four
|
|
?? three
|
|
EOF
|
|
test_cmp ../status.expect ../actual &&
|
|
cat >../trace.expect <<EOF &&
|
|
node creation: 0
|
|
gitignore invalidation: 0
|
|
directory invalidation: 1
|
|
opendir: 1
|
|
EOF
|
|
test_cmp ../trace.expect ../trace
|
|
|
|
'
|
|
|
|
test_expect_success 'verify untracked cache dump' '
|
|
test-dump-untracked-cache >../actual &&
|
|
cat >../expect <<EOF &&
|
|
info/exclude $EMPTY_BLOB
|
|
core.excludesfile 0000000000000000000000000000000000000000
|
|
exclude_per_dir .gitignore
|
|
flags 00000006
|
|
/ 0000000000000000000000000000000000000000 recurse valid
|
|
dthree/
|
|
dtwo/
|
|
four
|
|
three
|
|
/done/ 0000000000000000000000000000000000000000 recurse valid
|
|
/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
|
|
three
|
|
/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
|
|
two
|
|
EOF
|
|
test_cmp ../expect ../actual
|
|
'
|
|
|
|
test_expect_success 'new .gitignore invalidates recursively' '
|
|
avoid_racy &&
|
|
echo four >.gitignore &&
|
|
: >../trace &&
|
|
GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
|
|
git status --porcelain >../actual &&
|
|
cat >../status.expect <<EOF &&
|
|
A done/one
|
|
A one
|
|
A two
|
|
?? .gitignore
|
|
?? dthree/
|
|
?? dtwo/
|
|
?? three
|
|
EOF
|
|
test_cmp ../status.expect ../actual &&
|
|
cat >../trace.expect <<EOF &&
|
|
node creation: 0
|
|
gitignore invalidation: 1
|
|
directory invalidation: 1
|
|
opendir: 4
|
|
EOF
|
|
test_cmp ../trace.expect ../trace
|
|
|
|
'
|
|
|
|
test_expect_success 'verify untracked cache dump' '
|
|
test-dump-untracked-cache >../actual &&
|
|
cat >../expect <<EOF &&
|
|
info/exclude $EMPTY_BLOB
|
|
core.excludesfile 0000000000000000000000000000000000000000
|
|
exclude_per_dir .gitignore
|
|
flags 00000006
|
|
/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
|
|
.gitignore
|
|
dthree/
|
|
dtwo/
|
|
three
|
|
/done/ 0000000000000000000000000000000000000000 recurse valid
|
|
/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
|
|
three
|
|
/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
|
|
two
|
|
EOF
|
|
test_cmp ../expect ../actual
|
|
'
|
|
|
|
test_expect_success 'new info/exclude invalidates everything' '
|
|
avoid_racy &&
|
|
echo three >>.git/info/exclude &&
|
|
: >../trace &&
|
|
GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
|
|
git status --porcelain >../actual &&
|
|
cat >../status.expect <<EOF &&
|
|
A done/one
|
|
A one
|
|
A two
|
|
?? .gitignore
|
|
?? dtwo/
|
|
EOF
|
|
test_cmp ../status.expect ../actual &&
|
|
cat >../trace.expect <<EOF &&
|
|
node creation: 0
|
|
gitignore invalidation: 1
|
|
directory invalidation: 0
|
|
opendir: 4
|
|
EOF
|
|
test_cmp ../trace.expect ../trace
|
|
'
|
|
|
|
test_expect_success 'verify untracked cache dump' '
|
|
test-dump-untracked-cache >../actual &&
|
|
cat >../expect <<EOF &&
|
|
info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
|
|
core.excludesfile 0000000000000000000000000000000000000000
|
|
exclude_per_dir .gitignore
|
|
flags 00000006
|
|
/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
|
|
.gitignore
|
|
dtwo/
|
|
/done/ 0000000000000000000000000000000000000000 recurse valid
|
|
/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
|
|
/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
|
|
two
|
|
EOF
|
|
test_cmp ../expect ../actual
|
|
'
|
|
|
|
test_expect_success 'move two from tracked to untracked' '
|
|
git rm --cached two &&
|
|
test-dump-untracked-cache >../actual &&
|
|
cat >../expect <<EOF &&
|
|
info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
|
|
core.excludesfile 0000000000000000000000000000000000000000
|
|
exclude_per_dir .gitignore
|
|
flags 00000006
|
|
/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse
|
|
/done/ 0000000000000000000000000000000000000000 recurse valid
|
|
/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
|
|
/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
|
|
two
|
|
EOF
|
|
test_cmp ../expect ../actual
|
|
'
|
|
|
|
test_expect_success 'status after the move' '
|
|
: >../trace &&
|
|
GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
|
|
git status --porcelain >../actual &&
|
|
cat >../status.expect <<EOF &&
|
|
A done/one
|
|
A one
|
|
?? .gitignore
|
|
?? dtwo/
|
|
?? two
|
|
EOF
|
|
test_cmp ../status.expect ../actual &&
|
|
cat >../trace.expect <<EOF &&
|
|
node creation: 0
|
|
gitignore invalidation: 0
|
|
directory invalidation: 0
|
|
opendir: 1
|
|
EOF
|
|
test_cmp ../trace.expect ../trace
|
|
'
|
|
|
|
test_expect_success 'verify untracked cache dump' '
|
|
test-dump-untracked-cache >../actual &&
|
|
cat >../expect <<EOF &&
|
|
info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
|
|
core.excludesfile 0000000000000000000000000000000000000000
|
|
exclude_per_dir .gitignore
|
|
flags 00000006
|
|
/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
|
|
.gitignore
|
|
dtwo/
|
|
two
|
|
/done/ 0000000000000000000000000000000000000000 recurse valid
|
|
/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
|
|
/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
|
|
two
|
|
EOF
|
|
test_cmp ../expect ../actual
|
|
'
|
|
|
|
test_expect_success 'move two from untracked to tracked' '
|
|
git add two &&
|
|
test-dump-untracked-cache >../actual &&
|
|
cat >../expect <<EOF &&
|
|
info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
|
|
core.excludesfile 0000000000000000000000000000000000000000
|
|
exclude_per_dir .gitignore
|
|
flags 00000006
|
|
/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse
|
|
/done/ 0000000000000000000000000000000000000000 recurse valid
|
|
/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
|
|
/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
|
|
two
|
|
EOF
|
|
test_cmp ../expect ../actual
|
|
'
|
|
|
|
test_expect_success 'status after the move' '
|
|
: >../trace &&
|
|
GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
|
|
git status --porcelain >../actual &&
|
|
cat >../status.expect <<EOF &&
|
|
A done/one
|
|
A one
|
|
A two
|
|
?? .gitignore
|
|
?? dtwo/
|
|
EOF
|
|
test_cmp ../status.expect ../actual &&
|
|
cat >../trace.expect <<EOF &&
|
|
node creation: 0
|
|
gitignore invalidation: 0
|
|
directory invalidation: 0
|
|
opendir: 1
|
|
EOF
|
|
test_cmp ../trace.expect ../trace
|
|
'
|
|
|
|
test_expect_success 'verify untracked cache dump' '
|
|
test-dump-untracked-cache >../actual &&
|
|
cat >../expect <<EOF &&
|
|
info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
|
|
core.excludesfile 0000000000000000000000000000000000000000
|
|
exclude_per_dir .gitignore
|
|
flags 00000006
|
|
/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
|
|
.gitignore
|
|
dtwo/
|
|
/done/ 0000000000000000000000000000000000000000 recurse valid
|
|
/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
|
|
/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
|
|
two
|
|
EOF
|
|
test_cmp ../expect ../actual
|
|
'
|
|
|
|
test_expect_success 'set up for sparse checkout testing' '
|
|
echo two >done/.gitignore &&
|
|
echo three >>done/.gitignore &&
|
|
echo two >done/two &&
|
|
git add -f done/two done/.gitignore &&
|
|
git commit -m "first commit"
|
|
'
|
|
|
|
test_expect_success 'status after commit' '
|
|
: >../trace &&
|
|
GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
|
|
git status --porcelain >../actual &&
|
|
cat >../status.expect <<EOF &&
|
|
?? .gitignore
|
|
?? dtwo/
|
|
EOF
|
|
test_cmp ../status.expect ../actual &&
|
|
cat >../trace.expect <<EOF &&
|
|
node creation: 0
|
|
gitignore invalidation: 0
|
|
directory invalidation: 0
|
|
opendir: 2
|
|
EOF
|
|
test_cmp ../trace.expect ../trace
|
|
'
|
|
|
|
test_expect_success 'untracked cache correct after commit' '
|
|
test-dump-untracked-cache >../actual &&
|
|
cat >../expect <<EOF &&
|
|
info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
|
|
core.excludesfile 0000000000000000000000000000000000000000
|
|
exclude_per_dir .gitignore
|
|
flags 00000006
|
|
/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
|
|
.gitignore
|
|
dtwo/
|
|
/done/ 0000000000000000000000000000000000000000 recurse valid
|
|
/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
|
|
/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
|
|
two
|
|
EOF
|
|
test_cmp ../expect ../actual
|
|
'
|
|
|
|
test_expect_success 'set up sparse checkout' '
|
|
echo "done/[a-z]*" >.git/info/sparse-checkout &&
|
|
test_config core.sparsecheckout true &&
|
|
git checkout master &&
|
|
git update-index --force-untracked-cache &&
|
|
git status --porcelain >/dev/null && # prime the cache
|
|
test_path_is_missing done/.gitignore &&
|
|
test_path_is_file done/one
|
|
'
|
|
|
|
test_expect_success 'create/modify files, some of which are gitignored' '
|
|
echo two bis >done/two &&
|
|
echo three >done/three && # three is gitignored
|
|
echo four >done/four && # four is gitignored at a higher level
|
|
echo five >done/five && # five is not gitignored
|
|
echo test >base && #we need to ensure that the root dir is touched
|
|
rm base &&
|
|
sync_mtime
|
|
'
|
|
|
|
test_expect_success 'test sparse status with untracked cache' '
|
|
: >../trace &&
|
|
avoid_racy &&
|
|
GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
|
|
git status --porcelain >../status.actual &&
|
|
cat >../status.expect <<EOF &&
|
|
M done/two
|
|
?? .gitignore
|
|
?? done/five
|
|
?? dtwo/
|
|
EOF
|
|
test_cmp ../status.expect ../status.actual &&
|
|
cat >../trace.expect <<EOF &&
|
|
node creation: 0
|
|
gitignore invalidation: 1
|
|
directory invalidation: 2
|
|
opendir: 2
|
|
EOF
|
|
test_cmp ../trace.expect ../trace
|
|
'
|
|
|
|
test_expect_success 'untracked cache correct after status' '
|
|
test-dump-untracked-cache >../actual &&
|
|
cat >../expect <<EOF &&
|
|
info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
|
|
core.excludesfile 0000000000000000000000000000000000000000
|
|
exclude_per_dir .gitignore
|
|
flags 00000006
|
|
/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
|
|
.gitignore
|
|
dtwo/
|
|
/done/ 1946f0437f90c5005533cbe1736a6451ca301714 recurse valid
|
|
five
|
|
/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
|
|
/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
|
|
two
|
|
EOF
|
|
test_cmp ../expect ../actual
|
|
'
|
|
|
|
test_expect_success 'test sparse status again with untracked cache' '
|
|
avoid_racy &&
|
|
: >../trace &&
|
|
GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
|
|
git status --porcelain >../status.actual &&
|
|
cat >../status.expect <<EOF &&
|
|
M done/two
|
|
?? .gitignore
|
|
?? done/five
|
|
?? dtwo/
|
|
EOF
|
|
test_cmp ../status.expect ../status.actual &&
|
|
cat >../trace.expect <<EOF &&
|
|
node creation: 0
|
|
gitignore invalidation: 0
|
|
directory invalidation: 0
|
|
opendir: 0
|
|
EOF
|
|
test_cmp ../trace.expect ../trace
|
|
'
|
|
|
|
test_expect_success 'set up for test of subdir and sparse checkouts' '
|
|
mkdir done/sub &&
|
|
mkdir done/sub/sub &&
|
|
echo "sub" > done/sub/sub/file
|
|
'
|
|
|
|
test_expect_success 'test sparse status with untracked cache and subdir' '
|
|
avoid_racy &&
|
|
: >../trace &&
|
|
GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
|
|
git status --porcelain >../status.actual &&
|
|
cat >../status.expect <<EOF &&
|
|
M done/two
|
|
?? .gitignore
|
|
?? done/five
|
|
?? done/sub/
|
|
?? dtwo/
|
|
EOF
|
|
test_cmp ../status.expect ../status.actual &&
|
|
cat >../trace.expect <<EOF &&
|
|
node creation: 2
|
|
gitignore invalidation: 0
|
|
directory invalidation: 1
|
|
opendir: 3
|
|
EOF
|
|
test_cmp ../trace.expect ../trace
|
|
'
|
|
|
|
test_expect_success 'verify untracked cache dump (sparse/subdirs)' '
|
|
test-dump-untracked-cache >../actual &&
|
|
cat >../expect-from-test-dump <<EOF &&
|
|
info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
|
|
core.excludesfile 0000000000000000000000000000000000000000
|
|
exclude_per_dir .gitignore
|
|
flags 00000006
|
|
/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
|
|
.gitignore
|
|
dtwo/
|
|
/done/ 1946f0437f90c5005533cbe1736a6451ca301714 recurse valid
|
|
five
|
|
sub/
|
|
/done/sub/ 0000000000000000000000000000000000000000 recurse check_only valid
|
|
sub/
|
|
/done/sub/sub/ 0000000000000000000000000000000000000000 recurse check_only valid
|
|
file
|
|
/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
|
|
/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
|
|
two
|
|
EOF
|
|
test_cmp ../expect-from-test-dump ../actual
|
|
'
|
|
|
|
test_expect_success 'test sparse status again with untracked cache and subdir' '
|
|
avoid_racy &&
|
|
: >../trace &&
|
|
GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
|
|
git status --porcelain >../status.actual &&
|
|
test_cmp ../status.expect ../status.actual &&
|
|
cat >../trace.expect <<EOF &&
|
|
node creation: 0
|
|
gitignore invalidation: 0
|
|
directory invalidation: 0
|
|
opendir: 0
|
|
EOF
|
|
test_cmp ../trace.expect ../trace
|
|
'
|
|
|
|
test_expect_success 'move entry in subdir from untracked to cached' '
|
|
git add dtwo/two &&
|
|
git status --porcelain >../status.actual &&
|
|
cat >../status.expect <<EOF &&
|
|
M done/two
|
|
A dtwo/two
|
|
?? .gitignore
|
|
?? done/five
|
|
?? done/sub/
|
|
EOF
|
|
test_cmp ../status.expect ../status.actual
|
|
'
|
|
|
|
test_expect_success 'move entry in subdir from cached to untracked' '
|
|
git rm --cached dtwo/two &&
|
|
git status --porcelain >../status.actual &&
|
|
cat >../status.expect <<EOF &&
|
|
M done/two
|
|
?? .gitignore
|
|
?? done/five
|
|
?? done/sub/
|
|
?? dtwo/
|
|
EOF
|
|
test_cmp ../status.expect ../status.actual
|
|
'
|
|
|
|
test_expect_success '--no-untracked-cache removes the cache' '
|
|
git update-index --no-untracked-cache &&
|
|
test-dump-untracked-cache >../actual &&
|
|
echo "no untracked cache" >../expect-no-uc &&
|
|
test_cmp ../expect-no-uc ../actual
|
|
'
|
|
|
|
test_expect_success 'git status does not change anything' '
|
|
git status &&
|
|
test-dump-untracked-cache >../actual &&
|
|
test_cmp ../expect-no-uc ../actual
|
|
'
|
|
|
|
test_expect_success 'setting core.untrackedCache to true and using git status creates the cache' '
|
|
git config core.untrackedCache true &&
|
|
test-dump-untracked-cache >../actual &&
|
|
test_cmp ../expect-no-uc ../actual &&
|
|
git status &&
|
|
test-dump-untracked-cache >../actual &&
|
|
test_cmp ../expect-from-test-dump ../actual
|
|
'
|
|
|
|
test_expect_success 'using --no-untracked-cache does not fail when core.untrackedCache is true' '
|
|
git update-index --no-untracked-cache &&
|
|
test-dump-untracked-cache >../actual &&
|
|
test_cmp ../expect-no-uc ../actual &&
|
|
git update-index --untracked-cache &&
|
|
test-dump-untracked-cache >../actual &&
|
|
test_cmp ../expect-empty ../actual
|
|
'
|
|
|
|
test_expect_success 'setting core.untrackedCache to false and using git status removes the cache' '
|
|
git config core.untrackedCache false &&
|
|
test-dump-untracked-cache >../actual &&
|
|
test_cmp ../expect-empty ../actual &&
|
|
git status &&
|
|
test-dump-untracked-cache >../actual &&
|
|
test_cmp ../expect-no-uc ../actual
|
|
'
|
|
|
|
test_expect_success 'using --untracked-cache does not fail when core.untrackedCache is false' '
|
|
git update-index --untracked-cache &&
|
|
test-dump-untracked-cache >../actual &&
|
|
test_cmp ../expect-empty ../actual
|
|
'
|
|
|
|
test_expect_success 'setting core.untrackedCache to keep' '
|
|
git config core.untrackedCache keep &&
|
|
git update-index --untracked-cache &&
|
|
test-dump-untracked-cache >../actual &&
|
|
test_cmp ../expect-empty ../actual &&
|
|
git status &&
|
|
test-dump-untracked-cache >../actual &&
|
|
test_cmp ../expect-from-test-dump ../actual &&
|
|
git update-index --no-untracked-cache &&
|
|
test-dump-untracked-cache >../actual &&
|
|
test_cmp ../expect-no-uc ../actual &&
|
|
git update-index --force-untracked-cache &&
|
|
test-dump-untracked-cache >../actual &&
|
|
test_cmp ../expect-empty ../actual &&
|
|
git status &&
|
|
test-dump-untracked-cache >../actual &&
|
|
test_cmp ../expect-from-test-dump ../actual
|
|
'
|
|
|
|
test_expect_success 'test ident field is working' '
|
|
mkdir ../other_worktree &&
|
|
cp -R done dthree dtwo four three ../other_worktree &&
|
|
GIT_WORK_TREE=../other_worktree git status 2>../err &&
|
|
echo "warning: Untracked cache is disabled on this system or location." >../expect &&
|
|
test_i18ncmp ../expect ../err
|
|
'
|
|
|
|
test_expect_success 'untracked cache survives a checkout' '
|
|
git commit --allow-empty -m empty &&
|
|
test-dump-untracked-cache >../before &&
|
|
test_when_finished "git checkout master" &&
|
|
git checkout -b other_branch &&
|
|
test-dump-untracked-cache >../after &&
|
|
test_cmp ../before ../after &&
|
|
test_commit test &&
|
|
test-dump-untracked-cache >../before &&
|
|
git checkout master &&
|
|
test-dump-untracked-cache >../after &&
|
|
test_cmp ../before ../after
|
|
'
|
|
|
|
test_expect_success 'untracked cache survives a commit' '
|
|
test-dump-untracked-cache >../before &&
|
|
git add done/two &&
|
|
git commit -m commit &&
|
|
test-dump-untracked-cache >../after &&
|
|
test_cmp ../before ../after
|
|
'
|
|
|
|
test_expect_success 'teardown worktree' '
|
|
cd ..
|
|
'
|
|
|
|
test_expect_success SYMLINKS 'setup worktree for symlink test' '
|
|
git init worktree-symlink &&
|
|
cd worktree-symlink &&
|
|
git config core.untrackedCache true &&
|
|
mkdir one two &&
|
|
touch one/file two/file &&
|
|
git add one/file two/file &&
|
|
git commit -m"first commit" &&
|
|
git rm -rf one &&
|
|
ln -s two one &&
|
|
git add one &&
|
|
git commit -m"second commit"
|
|
'
|
|
|
|
test_expect_success SYMLINKS '"status" after symlink replacement should be clean with UC=true' '
|
|
git checkout HEAD~ &&
|
|
status_is_clean &&
|
|
status_is_clean &&
|
|
git checkout master &&
|
|
avoid_racy &&
|
|
status_is_clean &&
|
|
status_is_clean
|
|
'
|
|
|
|
test_expect_success SYMLINKS '"status" after symlink replacement should be clean with UC=false' '
|
|
git config core.untrackedCache false &&
|
|
git checkout HEAD~ &&
|
|
status_is_clean &&
|
|
status_is_clean &&
|
|
git checkout master &&
|
|
avoid_racy &&
|
|
status_is_clean &&
|
|
status_is_clean
|
|
'
|
|
|
|
test_expect_success 'setup worktree for non-symlink test' '
|
|
git init worktree-non-symlink &&
|
|
cd worktree-non-symlink &&
|
|
git config core.untrackedCache true &&
|
|
mkdir one two &&
|
|
touch one/file two/file &&
|
|
git add one/file two/file &&
|
|
git commit -m"first commit" &&
|
|
git rm -rf one &&
|
|
cp two/file one &&
|
|
git add one &&
|
|
git commit -m"second commit"
|
|
'
|
|
|
|
test_expect_success '"status" after file replacement should be clean with UC=true' '
|
|
git checkout HEAD~ &&
|
|
status_is_clean &&
|
|
status_is_clean &&
|
|
git checkout master &&
|
|
avoid_racy &&
|
|
status_is_clean &&
|
|
test-dump-untracked-cache >../actual &&
|
|
grep -F "recurse valid" ../actual >../actual.grep &&
|
|
cat >../expect.grep <<EOF &&
|
|
/ 0000000000000000000000000000000000000000 recurse valid
|
|
/two/ 0000000000000000000000000000000000000000 recurse valid
|
|
EOF
|
|
status_is_clean &&
|
|
test_cmp ../expect.grep ../actual.grep
|
|
'
|
|
|
|
test_expect_success '"status" after file replacement should be clean with UC=false' '
|
|
git config core.untrackedCache false &&
|
|
git checkout HEAD~ &&
|
|
status_is_clean &&
|
|
status_is_clean &&
|
|
git checkout master &&
|
|
avoid_racy &&
|
|
status_is_clean &&
|
|
status_is_clean
|
|
'
|
|
|
|
test_done
|