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

[PATCH v2 5/9] checkout-index: add --ignore-skip-worktree-bits option

From
Victoria Dye via GitGitGadget <gitgitgadget@gmail.com>
Date
Jan 11, 2022, 18:05 UTC
Message-ID
<601888606d1cf7d7752844dbdbc7fac20d4be8c4.1641924306.git.gitgitgadget@gmail.com>
In-Reply-To
<pull.1109.v2.git.1641924306.gitgitgadget@gmail.com>
From: Victoria Dye <vdye@github.com>

Update `checkout-index` to no longer refresh files that have the `skip-worktree` bit set, exiting with an error if `skip-worktree` filenames are directly provided to `checkout-index`. The newly-added `--ignore-skip-worktree-bits` option provides a mechanism to replicate the old behavior, checking out *all* files specified (even those with `skip-worktree` enabled).

The ability to toggle whether files should be checked-out based on `skip-worktree` already exists in `git checkout` and `git restore` (both of which have an `--ignore-skip-worktree-bits` option). The change to, by default, ignore `skip-worktree` files is especially helpful for sparse-checkout; it prevents inadvertent creation of files outside the sparse definition on disk and eliminates the need to expand a sparse index when using the `--all` option.

Internal usage of `checkout-index` in `git stash` and `git filter-branch` do not make explicit use of files with `skip-worktree` enabled, so `--ignore-skip-worktree-bits` is not added to them.

Helped-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Victoria Dye <vdye@github.com>
---
 Documentation/git-checkout-index.txt     | 10 +++++++--
 builtin/checkout-index.c                 | 13 ++++++++++++
 t/t1092-sparse-checkout-compatibility.sh | 27 +++++++++++++++---------
 3 files changed, 38 insertions(+), 12 deletions(-)
diff --git a/Documentation/git-checkout-index.txt b/Documentation/git-checkout-index.txt
index 4d33e7be0f5..01dbd5cbf54 100644
--- a/Documentation/git-checkout-index.txt
+++ b/Documentation/git-checkout-index.txt
@@ -12,6 +12,7 @@ SYNOPSIS
 'git checkout-index' [-u] [-q] [-a] [-f] [-n] [--prefix=<string>]
 		   [--stage=<number>|all]
 		   [--temp]
+		   [--ignore-skip-worktree-bits]
 		   [-z] [--stdin]
 		   [--] [<file>...]
 
@@ -37,8 +38,9 @@ OPTIONS
 
 -a::
 --all::
-	checks out all files in the index.  Cannot be used
-	together with explicit filenames.
+	checks out all files in the index except for those with the
+	skip-worktree bit set (see `--ignore-skip-worktree-bits`).
+	Cannot be used together with explicit filenames.
 
 -n::
 --no-create::
@@ -59,6 +61,10 @@ OPTIONS
 	write the content to temporary files.  The temporary name
 	associations will be written to stdout.
 
+--ignore-skip-worktree-bits::
+	Check out all files, including those with the skip-worktree bit
+	set.
+
 --stdin::
 	Instead of taking list of paths from the command line,
 	read list of paths from the standard input.  Paths are
diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c
index e21620d964e..615a118e2f5 100644
--- a/builtin/checkout-index.c
+++ b/builtin/checkout-index.c
@@ -7,6 +7,7 @@
 #define USE_THE_INDEX_COMPATIBILITY_MACROS
 #include "builtin.h"
 #include "config.h"
+#include "dir.h"
 #include "lockfile.h"
 #include "quote.h"
 #include "cache-tree.h"
@@ -17,6 +18,7 @@
 #define CHECKOUT_ALL 4
 static int nul_term_line;
 static int checkout_stage; /* default to checkout stage0 */
+static int ignore_skip_worktree; /* default to 0 */
 static int to_tempfile;
 static char topath[4][TEMPORARY_FILENAME_LENGTH + 1];
 
@@ -65,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_skipped = 1;
 	int did_checkout = 0;
 	int errs = 0;
 
@@ -78,6 +81,9 @@ static int checkout_file(const char *name, const char *prefix)
 			break;
 		has_same_name = 1;
 		pos++;
+		if (!ignore_skip_worktree && ce_skip_worktree(ce))
+			break;
+		is_skipped = 0;
 		if (ce_stage(ce) != checkout_stage
 		    && (CHECKOUT_ALL != checkout_stage || !ce_stage(ce)))
 			continue;
@@ -106,6 +112,9 @@ 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_skipped)
+			fprintf(stderr, "has skip-worktree enabled; "
+					"use '--ignore-skip-worktree-bits' to checkout");
 		else if (checkout_stage)
 			fprintf(stderr, "does not exist at stage %d",
 				checkout_stage);
@@ -125,6 +134,8 @@ static int checkout_all(const char *prefix, int prefix_length)
 	ensure_full_index(&the_index);
 	for (i = 0; i < active_nr ; i++) {
 		struct cache_entry *ce = active_cache[i];
+		if (!ignore_skip_worktree && ce_skip_worktree(ce))
+			continue;
 		if (ce_stage(ce) != checkout_stage
 		    && (CHECKOUT_ALL != checkout_stage || !ce_stage(ce)))
 			continue;
@@ -185,6 +196,8 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
 	struct option builtin_checkout_index_options[] = {
 		OPT_BOOL('a', "all", &all,
 			N_("check out all files in the index")),
+		OPT_BOOL(0, "ignore-skip-worktree-bits", &ignore_skip_worktree,
+			N_("do not skip files with skip-worktree set")),
 		OPT__FORCE(&force, N_("force overwrite of existing files"), 0),
 		OPT__QUIET(&quiet,
 			N_("no warning for existing files and files not in index")),
diff --git a/t/t1092-sparse-checkout-compatibility.sh b/t/t1092-sparse-checkout-compatibility.sh
index db7ad41109b..434ef0433c0 100755
--- a/t/t1092-sparse-checkout-compatibility.sh
+++ b/t/t1092-sparse-checkout-compatibility.sh
@@ -772,9 +772,14 @@ test_expect_success 'checkout-index inside sparse definition' '
 test_expect_success 'checkout-index outside sparse definition' '
 	init_repos &&
 
-	# File does not exist on disk yet for sparse checkouts, so checkout-index
-	# succeeds without -f
-	test_sparse_match git checkout-index -- folder1/a &&
+	# Without --ignore-skip-worktree-bits, outside-of-cone files will trigger
+	# an error
+	test_sparse_match test_must_fail git checkout-index -- folder1/a &&
+	test_i18ngrep "folder1/a has skip-worktree enabled" sparse-checkout-err &&
+	test_path_is_missing folder1/a &&
+
+	# With --ignore-skip-worktree-bits, outside-of-cone files are checked out
+	test_sparse_match git checkout-index --ignore-skip-worktree-bits -- folder1/a &&
 	test_cmp sparse-checkout/folder1/a sparse-index/folder1/a &&
 	test_cmp sparse-checkout/folder1/a full-checkout/folder1/a &&
 
@@ -783,8 +788,8 @@ test_expect_success 'checkout-index outside sparse definition' '
 	run_on_sparse mkdir -p folder1 &&
 	run_on_all cp ../new-a folder1/a &&
 
-	test_all_match test_must_fail git checkout-index -- folder1/a &&
-	test_all_match git checkout-index -f -- folder1/a &&
+	test_all_match test_must_fail git checkout-index --ignore-skip-worktree-bits -- folder1/a &&
+	test_all_match git checkout-index -f --ignore-skip-worktree-bits -- folder1/a &&
 	test_cmp sparse-checkout/folder1/a sparse-index/folder1/a &&
 	test_cmp sparse-checkout/folder1/a full-checkout/folder1/a
 '
@@ -799,14 +804,16 @@ test_expect_success 'checkout-index with folders' '
 	test_all_match test_must_fail git checkout-index -f -- folder1/
 '
 
-# NEEDSWORK: even in sparse checkouts, checkout-index --all will create all
-# files (even those outside the sparse definition) on disk. However, these files
-# don't appear in the percentage of tracked files in git status.
-test_expect_failure 'checkout-index --all' '
+test_expect_success 'checkout-index --all' '
 	init_repos &&
 
 	test_all_match git checkout-index --all &&
-	test_sparse_match test_path_is_missing folder1
+	test_sparse_match test_path_is_missing folder1 &&
+
+	# --ignore-skip-worktree-bits will cause `skip-worktree` files to be
+	# checked out, causing the outside-of-cone `folder1` to exist on-disk
+	test_all_match git checkout-index --ignore-skip-worktree-bits --all &&
+	test_all_match test_path_exists folder1
 '
 
 test_expect_success 'clean' '
-- 
gitgitgadget
Previous: Victoria Dye via GitGitGadgetNext: Elijah Newren
Message 36 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.