git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v2 6/9] checkout-index: integrate with sparse index

From
Victoria Dye via GitGitGadget <gitgitgadget@gmail.com>
Date
Jan 11, 2022, 18:05 UTC
Message-ID
<b4b9086dcdc62eff27f9520b9495e3b273946e39.1641924306.git.gitgitgadget@gmail.com>
In-Reply-To
<pull.1109.v2.git.1641924306.gitgitgadget@gmail.com>
From: Victoria Dye <vdye@github.com>
Add repository settings to allow usage of the sparse index.

When using the `--all` option, sparse directories are ignored by default due to the `skip-worktree` flag, so there is no need to expand the index. If `--ignore-skip-worktree-bits` is specified, the index is expanded in order to check out all files.

When checking out individual files, existing behavior in a full index is to exit with an error if a directory is specified (as the directory name will not match an index entry). However, it is possible in a sparse index to match a directory name to a sparse directory index entry, but checking out that sparse directory still results in an error on checkout. To reduce some potential confusion for users, `checkout_file(...)` explicitly exits with an informative error if provided with a sparse directory name. The test corresponding to this scenario verifies the error message, which now differs between sparse index and non-sparse index checkouts.

Signed-off-by: Victoria Dye <vdye@github.com>
---
 builtin/checkout-index.c                 | 28 ++++++++++++++++++++++--
 t/t1092-sparse-checkout-compatibility.sh | 11 +++++++++-
 2 files changed, 36 insertions(+), 3 deletions(-)
diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c
index 615a118e2f5..97e06e8c52c 100644
--- a/builtin/checkout-index.c
+++ b/builtin/checkout-index.c
@@ -67,6 +67,7 @@ static int checkout_file(const char *name, const char *prefix)
 	int namelen = strlen(name);
 	int pos = cache_name_pos(name, namelen);
 	int has_same_name = 0;
+	int is_file = 0;
 	int is_skipped = 1;
 	int did_checkout = 0;
 	int errs = 0;
@@ -81,6 +82,9 @@ static int checkout_file(const char *name, const char *prefix)
 			break;
 		has_same_name = 1;
 		pos++;
+		if (S_ISSPARSEDIR(ce->ce_mode))
+			break;
+		is_file = 1;
 		if (!ignore_skip_worktree && ce_skip_worktree(ce))
 			break;
 		is_skipped = 0;
@@ -112,6 +116,8 @@ static int checkout_file(const char *name, const char *prefix)
 		fprintf(stderr, "git checkout-index: %s ", name);
 		if (!has_same_name)
 			fprintf(stderr, "is not in the cache");
+		else if (!is_file)
+			fprintf(stderr, "is a sparse directory");
 		else if (is_skipped)
 			fprintf(stderr, "has skip-worktree enabled; "
 					"use '--ignore-skip-worktree-bits' to checkout");
@@ -130,10 +136,25 @@ static int checkout_all(const char *prefix, int prefix_length)
 	int i, errs = 0;
 	struct cache_entry *last_ce = NULL;
 
-	/* TODO: audit for interaction with sparse-index. */
-	ensure_full_index(&the_index);
 	for (i = 0; i < active_nr ; i++) {
 		struct cache_entry *ce = active_cache[i];
+
+		if (S_ISSPARSEDIR(ce->ce_mode)) {
+			if (!ce_skip_worktree(ce))
+				BUG("sparse directory '%s' does not have skip-worktree set", ce->name);
+
+			/*
+			 * If the current entry is a sparse directory and skip-worktree
+			 * entries are being checked out, expand the index and continue
+			 * the loop on the current index position (now pointing to the
+			 * first entry inside the expanded sparse directory).
+			 */
+			if (ignore_skip_worktree) {
+				ensure_full_index(&the_index);
+				ce = active_cache[i];
+			}
+		}
+
 		if (!ignore_skip_worktree && ce_skip_worktree(ce))
 			continue;
 		if (ce_stage(ce) != checkout_stage
@@ -225,6 +246,9 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
 	git_config(git_default_config, NULL);
 	prefix_length = prefix ? strlen(prefix) : 0;
 
+	prepare_repo_settings(the_repository);
+	the_repository->settings.command_requires_full_index = 0;
+
 	if (read_cache() < 0) {
 		die("invalid cache");
 	}
diff --git a/t/t1092-sparse-checkout-compatibility.sh b/t/t1092-sparse-checkout-compatibility.sh
index 434ef0433c0..0c72c854d84 100755
--- a/t/t1092-sparse-checkout-compatibility.sh
+++ b/t/t1092-sparse-checkout-compatibility.sh
@@ -801,7 +801,14 @@ test_expect_success 'checkout-index with folders' '
 	test_all_match test_must_fail git checkout-index -f -- deep/ &&
 
 	# Outside checkout definition
-	test_all_match test_must_fail git checkout-index -f -- folder1/
+	# Note: although all tests fail (as expected), the messaging differs. For
+	# non-sparse index checkouts, the error is that the "file" does not appear
+	# in the index; for sparse checkouts, the error is explicitly that the
+	# entry is a sparse directory.
+	run_on_all test_must_fail git checkout-index -f -- folder1/ &&
+	test_cmp full-checkout-err sparse-checkout-err &&
+	! test_cmp full-checkout-err sparse-index-err &&
+	grep "is a sparse directory" sparse-index-err
 '
 
 test_expect_success 'checkout-index --all' '
@@ -972,6 +979,8 @@ test_expect_success 'sparse-index is not expanded' '
 	echo >>sparse-index/untracked.txt &&
 	ensure_not_expanded add . &&
 
+	ensure_not_expanded checkout-index -f a &&
+	ensure_not_expanded checkout-index -f --all &&
 	for ref in update-deep update-folder1 update-folder2 update-deep
 	do
 		echo >>sparse-index/README.md &&
-- 
gitgitgadget
Previous: Victoria Dye via GitGitGadgetNext: Victoria Dye via GitGitGadget
Message 32 of 39 in “Sparse index: integrate with 'clean', 'checkout-index', 'update-index'”
  1. 0/9 Sparse index: integrate with 'clean', 'checkout-index', 'update-index'Victoria Dye via GitGitGadget, Jan 4, 2022
  2. 1/9 reset: fix validation in sparse index testVictoria Dye via GitGitGadget, Jan 4, 2022
  3. 2/9 reset: reorder wildcard pathspec conditionsVictoria Dye via GitGitGadget, Jan 4, 2022
  4. 3/9 clean: integrate with sparse indexVictoria Dye via GitGitGadget, Jan 4, 2022
  5. 4/9 checkout-index: expand sparse checkout compatibility testsVictoria Dye via GitGitGadget, Jan 4, 2022
  6. Elijah NewrenJan 5, 2022
  7. Elijah NewrenJan 7, 2022
  8. 5/9 checkout-index: add --ignore-skip-worktree-bits optionVictoria Dye via GitGitGadget, Jan 4, 2022
  9. Elijah NewrenJan 6, 2022
  10. Victoria DyeJan 6, 2022
  11. Elijah NewrenJan 7, 2022
  12. 6/9 checkout-index: integrate with sparse indexVictoria Dye via GitGitGadget, Jan 4, 2022
  13. Elijah NewrenJan 6, 2022
  14. 7/9 update-index: add tests for sparse-checkout compatibilityVictoria Dye via GitGitGadget, Jan 4, 2022
  15. Elijah NewrenJan 8, 2022
  16. Victoria DyeJan 10, 2022
  17. Elijah NewrenJan 10, 2022
  18. Victoria DyeJan 10, 2022
  19. Elijah NewrenJan 10, 2022
  20. 8/9 update-index: integrate with sparse indexVictoria Dye via GitGitGadget, Jan 4, 2022
  21. Elijah NewrenJan 9, 2022
  22. Victoria DyeJan 10, 2022
  23. Elijah NewrenJan 10, 2022
  24. 9/9 update-index: reduce scope of index expansion in do_reupdateVictoria Dye via GitGitGadget, Jan 4, 2022
  25. Elijah NewrenJan 9, 2022
  26. Elijah NewrenJan 9, 2022
  27. 0/9 Sparse index: integrate with 'clean', 'checkout-index', 'update-index'Victoria Dye via GitGitGadget, Jan 11, 2022
  28. 1/9 reset: fix validation in sparse index testVictoria Dye via GitGitGadget, Jan 11, 2022
  29. 2/9 reset: reorder wildcard pathspec conditionsVictoria Dye via GitGitGadget, Jan 11, 2022
  30. 4/9 checkout-index: expand sparse checkout compatibility testsVictoria Dye via GitGitGadget, Jan 11, 2022
  31. 3/9 clean: integrate with sparse indexVictoria Dye via GitGitGadget, Jan 11, 2022
  32. 6/9 checkout-index: integrate with sparse indexVictoria Dye via GitGitGadget, Jan 11, 2022
  33. 9/9 update-index: reduce scope of index expansion in do_reupdateVictoria Dye via GitGitGadget, Jan 11, 2022
  34. 8/9 update-index: integrate with sparse indexVictoria Dye via GitGitGadget, Jan 11, 2022
  35. 7/9 update-index: add tests for sparse-checkout compatibilityVictoria Dye via GitGitGadget, Jan 11, 2022
  36. 5/9 checkout-index: add --ignore-skip-worktree-bits optionVictoria Dye via GitGitGadget, Jan 11, 2022
  37. Elijah NewrenJan 13, 2022
  38. Derrick StoleeJan 27, 2022
  39. Junio C HamanoJan 27, 2022

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.