--- v2
+++ v4
@@ -1,60 +1,77 @@
From: Derrick Stolee <dstolee@microsoft.com>
-When walking trees using traverse_trees_recursive() and
-unpack_callback(), we must not attempt to walk into a sparse directory
-entry. There are no index entries within that directory to compare to
-the tree object at that position, so skip over the entries of that tree.
+Before moving to update 'git status' and 'git add' to work with sparse
+indexes, add an explicit test that ensures the sparse-index works the
+same as a normal sparse-checkout when the worktree contains directories
+and files outside of the sparse cone.
-This code is used in many places, so the only way to test it is to start
-removing the command_requres_full_index option from one builtin at a
-time and carefully test that its use of unpack_trees() behaves correctly
-with a sparse-index. Such tests will be added by later changes.
+Specifically, 'folder1/a' is a file in our test repo, but 'folder1' is
+not in the sparse cone. When 'folder1/a' is modified, the file is not
+shown as modified and adding it will fail. This is new behavior as of
+a20f704 (add: warn when asked to update SKIP_WORKTREE entries,
+2021-04-08). Before that change, these adds would be silently ignored.
+
+Untracked files are fine: adding new files both with 'git add .' and
+'git add folder1/' works just as in a full checkout. This may not be
+entirely desirable, but we are not intending to change behavior at the
+moment, only document it. A future change could alter the behavior to
+be more sensible, and this test could be modified to satisfy the new
+expected behavior.
Signed-off-by: Derrick Stolee <dstolee@microsoft.com>
---
- unpack-trees.c | 10 ++++++++--
- 1 file changed, 8 insertions(+), 2 deletions(-)
+ t/t1092-sparse-checkout-compatibility.sh | 38 ++++++++++++++++++++++++
+ 1 file changed, 38 insertions(+)
-diff --git a/unpack-trees.c b/unpack-trees.c
-index 3af797093095..67777570f829 100644
---- a/unpack-trees.c
-+++ b/unpack-trees.c
-@@ -1256,6 +1256,7 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str
- struct cache_entry *src[MAX_UNPACK_TREES + 1] = { NULL, };
- struct unpack_trees_options *o = info->data;
- const struct name_entry *p = names;
-+ unsigned unpack_tree = 1;
+diff --git a/t/t1092-sparse-checkout-compatibility.sh b/t/t1092-sparse-checkout-compatibility.sh
+index 98257695979a..fba98d5484ae 100755
+--- a/t/t1092-sparse-checkout-compatibility.sh
++++ b/t/t1092-sparse-checkout-compatibility.sh
+@@ -238,6 +238,44 @@ test_expect_success 'add, commit, checkout' '
+ test_all_match git checkout -
+ '
- /* Find first entry with a real name (we could use "mask" too) */
- while (!p->mode)
-@@ -1297,12 +1298,16 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str
- }
- }
- src[0] = ce;
++test_expect_success 'status/add: outside sparse cone' '
++ init_repos &&
+
-+ if (S_ISSPARSEDIR(ce->ce_mode))
-+ unpack_tree = 0;
- }
- break;
- }
- }
++ # adding a "missing" file outside the cone should fail
++ test_sparse_match test_must_fail git add folder1/a &&
++
++ # folder1 is at HEAD, but outside the sparse cone
++ run_on_sparse mkdir folder1 &&
++ cp initial-repo/folder1/a sparse-checkout/folder1/a &&
++ cp initial-repo/folder1/a sparse-index/folder1/a &&
++
++ test_sparse_match git status &&
++
++ write_script edit-contents <<-\EOF &&
++ echo text >>$1
++ EOF
++ run_on_sparse ../edit-contents folder1/a &&
++ run_on_all ../edit-contents folder1/new &&
++
++ test_sparse_match git status --porcelain=v2 &&
++
++ # This "git add folder1/a" fails with a warning
++ # in the sparse repos, differing from the full
++ # repo. This is intentional.
++ test_sparse_match test_must_fail git add folder1/a &&
++ test_sparse_match test_must_fail git add --refresh folder1/a &&
++ test_all_match git status --porcelain=v2 &&
++
++ test_all_match git add . &&
++ test_all_match git status --porcelain=v2 &&
++ test_all_match git commit -m folder1/new &&
++
++ run_on_all ../edit-contents folder1/newer &&
++ test_all_match git add folder1/ &&
++ test_all_match git status --porcelain=v2 &&
++ test_all_match git commit -m folder1/newer
++'
++
+ test_expect_success 'checkout and reset --hard' '
+ init_repos &&
-- if (unpack_nondirectories(n, mask, dirmask, src, names, info) < 0)
-+ if (unpack_tree &&
-+ unpack_nondirectories(n, mask, dirmask, src, names, info) < 0)
- return -1;
-
- if (o->merge && src[0]) {
-@@ -1332,7 +1337,8 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str
- }
- }
-
-- if (traverse_trees_recursive(n, dirmask, mask & ~dirmask,
-+ if (unpack_tree &&
-+ traverse_trees_recursive(n, dirmask, mask & ~dirmask,
- names, info) < 0)
- return -1;
- return mask;
--
gitgitgadget