From 1530ff3553c197ae04b5d9363e2c2b1f7d4198e1 Mon Sep 17 00:00:00 2001 From: Elijah Newren Date: Tue, 14 Dec 2021 04:09:03 +0000 Subject: sparse-checkout: pass use_stdin as a parameter instead of as a global add_patterns_from_input() has relied on a global variable, set_opts.use_stdin, which has been used by both the `set` and `add` subcommands of sparse-checkout. Once we introduce an add_opts.use_stdin, the hardcoding of set_opts.use_stdin will be incorrect. Pass the value as function parameter instead to allow us to make subsequent changes. Reviewed-by: Derrick Stolee Reviewed-by: Victoria Dye Signed-off-by: Elijah Newren Signed-off-by: Junio C Hamano --- builtin/sparse-checkout.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) (limited to 'builtin') diff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c index d0f5c4702b..8612328e5d 100644 --- a/builtin/sparse-checkout.c +++ b/builtin/sparse-checkout.c @@ -525,7 +525,8 @@ static struct sparse_checkout_set_opts { } set_opts; static void add_patterns_from_input(struct pattern_list *pl, - int argc, const char **argv) + int argc, const char **argv, + int use_stdin) { int i; if (core_sparse_checkout_cone) { @@ -535,7 +536,7 @@ static void add_patterns_from_input(struct pattern_list *pl, hashmap_init(&pl->parent_hashmap, pl_hashmap_cmp, NULL, 0); pl->use_cone_patterns = 1; - if (set_opts.use_stdin) { + if (use_stdin) { struct strbuf unquoted = STRBUF_INIT; while (!strbuf_getline(&line, stdin)) { if (line.buf[0] == '"') { @@ -559,7 +560,7 @@ static void add_patterns_from_input(struct pattern_list *pl, } } } else { - if (set_opts.use_stdin) { + if (use_stdin) { struct strbuf line = STRBUF_INIT; while (!strbuf_getline(&line, stdin)) { @@ -580,7 +581,8 @@ enum modify_type { }; static void add_patterns_cone_mode(int argc, const char **argv, - struct pattern_list *pl) + struct pattern_list *pl, + int use_stdin) { struct strbuf buffer = STRBUF_INIT; struct pattern_entry *pe; @@ -588,7 +590,7 @@ static void add_patterns_cone_mode(int argc, const char **argv, struct pattern_list existing; char *sparse_filename = get_sparse_checkout_filename(); - add_patterns_from_input(pl, argc, argv); + add_patterns_from_input(pl, argc, argv, use_stdin); memset(&existing, 0, sizeof(existing)); existing.use_cone_patterns = core_sparse_checkout_cone; @@ -614,17 +616,19 @@ static void add_patterns_cone_mode(int argc, const char **argv, } static void add_patterns_literal(int argc, const char **argv, - struct pattern_list *pl) + struct pattern_list *pl, + int use_stdin) { char *sparse_filename = get_sparse_checkout_filename(); if (add_patterns_from_file_to_list(sparse_filename, "", 0, pl, NULL, 0)) die(_("unable to load existing sparse-checkout patterns")); free(sparse_filename); - add_patterns_from_input(pl, argc, argv); + add_patterns_from_input(pl, argc, argv, use_stdin); } -static int modify_pattern_list(int argc, const char **argv, enum modify_type m) +static int modify_pattern_list(int argc, const char **argv, int use_stdin, + enum modify_type m) { int result; int changed_config = 0; @@ -633,13 +637,13 @@ static int modify_pattern_list(int argc, const char **argv, enum modify_type m) switch (m) { case ADD: if (core_sparse_checkout_cone) - add_patterns_cone_mode(argc, argv, pl); + add_patterns_cone_mode(argc, argv, pl, use_stdin); else - add_patterns_literal(argc, argv, pl); + add_patterns_literal(argc, argv, pl, use_stdin); break; case REPLACE: - add_patterns_from_input(pl, argc, argv); + add_patterns_from_input(pl, argc, argv, use_stdin); break; } @@ -675,7 +679,7 @@ static int sparse_checkout_set(int argc, const char **argv, const char *prefix, builtin_sparse_checkout_set_usage, PARSE_OPT_KEEP_UNKNOWN); - return modify_pattern_list(argc, argv, m); + return modify_pattern_list(argc, argv, set_opts.use_stdin, m); } static char const * const builtin_sparse_checkout_reapply_usage[] = { -- cgit v1.2.3 From 0b624e039cc2c9e30333445e8c67002f41d63678 Mon Sep 17 00:00:00 2001 From: Elijah Newren Date: Tue, 14 Dec 2021 04:09:04 +0000 Subject: sparse-checkout: break apart functions for sparse_checkout_(set|add) sparse_checkout_set() was reused by sparse_checkout_add() with the only difference being a single parameter being passed to that function. However, we would like sparse_checkout_set() to do the same work that sparse_checkout_init() does if sparse checkouts are not already enabled. To facilitate this transition, give each mode their own copy of the function. This does not introduce any behavioral changes; that will come in a subsequent patch. Reviewed-by: Derrick Stolee Reviewed-by: Victoria Dye Signed-off-by: Elijah Newren Signed-off-by: Junio C Hamano --- builtin/sparse-checkout.c | 54 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 14 deletions(-) (limited to 'builtin') diff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c index 8612328e5d..e252b82136 100644 --- a/builtin/sparse-checkout.c +++ b/builtin/sparse-checkout.c @@ -515,15 +515,6 @@ static void strbuf_to_cone_pattern(struct strbuf *line, struct pattern_list *pl) insert_recursive_pattern(pl, line); } -static char const * const builtin_sparse_checkout_set_usage[] = { - N_("git sparse-checkout (set|add) (--stdin | )"), - NULL -}; - -static struct sparse_checkout_set_opts { - int use_stdin; -} set_opts; - static void add_patterns_from_input(struct pattern_list *pl, int argc, const char **argv, int use_stdin) @@ -663,8 +654,43 @@ static int modify_pattern_list(int argc, const char **argv, int use_stdin, return result; } -static int sparse_checkout_set(int argc, const char **argv, const char *prefix, - enum modify_type m) +static char const * const builtin_sparse_checkout_add_usage[] = { + N_("git sparse-checkout add (--stdin | )"), + NULL +}; + +static struct sparse_checkout_add_opts { + int use_stdin; +} add_opts; + +static int sparse_checkout_add(int argc, const char **argv, const char *prefix) +{ + static struct option builtin_sparse_checkout_add_options[] = { + OPT_BOOL(0, "stdin", &add_opts.use_stdin, + N_("read patterns from standard in")), + OPT_END(), + }; + + repo_read_index(the_repository); + + argc = parse_options(argc, argv, prefix, + builtin_sparse_checkout_add_options, + builtin_sparse_checkout_add_usage, + PARSE_OPT_KEEP_UNKNOWN); + + return modify_pattern_list(argc, argv, add_opts.use_stdin, ADD); +} + +static char const * const builtin_sparse_checkout_set_usage[] = { + N_("git sparse-checkout set (--stdin | )"), + NULL +}; + +static struct sparse_checkout_set_opts { + int use_stdin; +} set_opts; + +static int sparse_checkout_set(int argc, const char **argv, const char *prefix) { static struct option builtin_sparse_checkout_set_options[] = { OPT_BOOL(0, "stdin", &set_opts.use_stdin, @@ -679,7 +705,7 @@ static int sparse_checkout_set(int argc, const char **argv, const char *prefix, builtin_sparse_checkout_set_usage, PARSE_OPT_KEEP_UNKNOWN); - return modify_pattern_list(argc, argv, set_opts.use_stdin, m); + return modify_pattern_list(argc, argv, set_opts.use_stdin, REPLACE); } static char const * const builtin_sparse_checkout_reapply_usage[] = { @@ -762,9 +788,9 @@ int cmd_sparse_checkout(int argc, const char **argv, const char *prefix) if (!strcmp(argv[0], "init")) return sparse_checkout_init(argc, argv); if (!strcmp(argv[0], "set")) - return sparse_checkout_set(argc, argv, prefix, REPLACE); + return sparse_checkout_set(argc, argv, prefix); if (!strcmp(argv[0], "add")) - return sparse_checkout_set(argc, argv, prefix, ADD); + return sparse_checkout_add(argc, argv, prefix); if (!strcmp(argv[0], "reapply")) return sparse_checkout_reapply(argc, argv); if (!strcmp(argv[0], "disable")) -- cgit v1.2.3 From 45c5e47048a89e08a9e844bcf976401af8b60478 Mon Sep 17 00:00:00 2001 From: Elijah Newren Date: Tue, 14 Dec 2021 04:09:05 +0000 Subject: sparse-checkout: add sanity-checks on initial sparsity state Most sparse-checkout subcommands (list, add, reapply) only make sense when already in a sparse state. Add a quick check that will error out early if this is not the case. Also document with a comment why we do not exit early in `disable` even when core.sparseCheckout starts as false. Reviewed-by: Derrick Stolee Reviewed-by: Victoria Dye Signed-off-by: Elijah Newren Signed-off-by: Junio C Hamano --- builtin/sparse-checkout.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'builtin') diff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c index e252b82136..eb8fbd36b0 100644 --- a/builtin/sparse-checkout.c +++ b/builtin/sparse-checkout.c @@ -56,6 +56,9 @@ static int sparse_checkout_list(int argc, const char **argv) char *sparse_filename; int res; + if (!core_apply_sparse_checkout) + die(_("this worktree is not sparse")); + argc = parse_options(argc, argv, NULL, builtin_sparse_checkout_list_options, builtin_sparse_checkout_list_usage, 0); @@ -671,6 +674,9 @@ static int sparse_checkout_add(int argc, const char **argv, const char *prefix) OPT_END(), }; + if (!core_apply_sparse_checkout) + die(_("no sparse-checkout to add to")); + repo_read_index(the_repository); argc = parse_options(argc, argv, prefix, @@ -719,6 +725,9 @@ static int sparse_checkout_reapply(int argc, const char **argv) OPT_END(), }; + if (!core_apply_sparse_checkout) + die(_("must be in a sparse-checkout to reapply sparsity patterns")); + argc = parse_options(argc, argv, NULL, builtin_sparse_checkout_reapply_options, builtin_sparse_checkout_reapply_usage, 0); @@ -740,6 +749,17 @@ static int sparse_checkout_disable(int argc, const char **argv) struct pattern_list pl; struct strbuf match_all = STRBUF_INIT; + /* + * We do not exit early if !core_apply_sparse_checkout; due to the + * ability for users to manually muck things up between + * direct editing of .git/info/sparse-checkout + * running read-tree -m u HEAD or update-index --skip-worktree + * direct toggling of config options + * users might end up with an index with SKIP_WORKTREE bit set on + * some files and not know how to undo it. So, here we just + * forcibly return to a dense checkout regardless of initial state. + */ + argc = parse_options(argc, argv, NULL, builtin_sparse_checkout_disable_options, builtin_sparse_checkout_disable_usage, 0); -- cgit v1.2.3 From f85751a147996f7f0a8edf3ea2a00217c9ddfc99 Mon Sep 17 00:00:00 2001 From: Elijah Newren Date: Tue, 14 Dec 2021 04:09:06 +0000 Subject: sparse-checkout: disallow --no-stdin as an argument to set We intentionally added --stdin as an option to `sparse-checkout set`, but didn't intend for --no-stdin to be permitted as well. Reported-by: Victoria Dye Reviewed-by: Derrick Stolee Reviewed-by: Victoria Dye Signed-off-by: Elijah Newren Signed-off-by: Junio C Hamano --- builtin/sparse-checkout.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'builtin') diff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c index eb8fbd36b0..387903eafe 100644 --- a/builtin/sparse-checkout.c +++ b/builtin/sparse-checkout.c @@ -699,8 +699,9 @@ static struct sparse_checkout_set_opts { static int sparse_checkout_set(int argc, const char **argv, const char *prefix) { static struct option builtin_sparse_checkout_set_options[] = { - OPT_BOOL(0, "stdin", &set_opts.use_stdin, - N_("read patterns from standard in")), + OPT_BOOL_F(0, "stdin", &set_opts.use_stdin, + N_("read patterns from standard in"), + PARSE_OPT_NONEG), OPT_END(), }; -- cgit v1.2.3 From be61fd1181f62dcb7b6a5f41021e7f086d7c30b0 Mon Sep 17 00:00:00 2001 From: Elijah Newren Date: Tue, 14 Dec 2021 04:09:07 +0000 Subject: sparse-checkout: split out code for tweaking settings config `init` has some code for handling updates to either cone mode or the sparse-index setting. We would like to be able to reuse this elsewhere, namely in `set` and `reapply`. Split this function out, and make it slightly more general so it can handle being called from the new callers. Reviewed-by: Derrick Stolee Reviewed-by: Victoria Dye Signed-off-by: Elijah Newren Signed-off-by: Junio C Hamano --- builtin/sparse-checkout.c | 56 +++++++++++++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 19 deletions(-) (limited to 'builtin') diff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c index 387903eafe..3b74779bb4 100644 --- a/builtin/sparse-checkout.c +++ b/builtin/sparse-checkout.c @@ -383,6 +383,41 @@ static int set_config(enum sparse_checkout_mode mode) return 0; } +static int update_modes(int *cone_mode, int *sparse_index) +{ + int mode, record_mode; + + /* Determine if we need to record the mode; ensure sparse checkout on */ + record_mode = (*cone_mode != -1) || !core_apply_sparse_checkout; + + /* If not specified, use previous definition of cone mode */ + if (*cone_mode == -1 && core_apply_sparse_checkout) + *cone_mode = core_sparse_checkout_cone; + + /* Set cone/non-cone mode appropriately */ + core_apply_sparse_checkout = 1; + if (*cone_mode == 1) { + mode = MODE_CONE_PATTERNS; + core_sparse_checkout_cone = 1; + } else { + mode = MODE_ALL_PATTERNS; + } + if (record_mode && set_config(mode)) + return 1; + + /* Set sparse-index/non-sparse-index mode if specified */ + if (*sparse_index >= 0) { + if (set_sparse_index_config(the_repository, *sparse_index) < 0) + die(_("failed to modify sparse-index config")); + + /* force an index rewrite */ + repo_read_index(the_repository); + the_repository->index->updated_workdir = 1; + } + + return 0; +} + static char const * const builtin_sparse_checkout_init_usage[] = { N_("git sparse-checkout init [--cone] [--[no-]sparse-index]"), NULL @@ -399,7 +434,6 @@ static int sparse_checkout_init(int argc, const char **argv) char *sparse_filename; int res; struct object_id oid; - int mode; struct strbuf pattern = STRBUF_INIT; static struct option builtin_sparse_checkout_init_options[] = { @@ -412,19 +446,14 @@ static int sparse_checkout_init(int argc, const char **argv) repo_read_index(the_repository); + init_opts.cone_mode = -1; init_opts.sparse_index = -1; argc = parse_options(argc, argv, NULL, builtin_sparse_checkout_init_options, builtin_sparse_checkout_init_usage, 0); - if (init_opts.cone_mode) { - mode = MODE_CONE_PATTERNS; - core_sparse_checkout_cone = 1; - } else - mode = MODE_ALL_PATTERNS; - - if (set_config(mode)) + if (update_modes(&init_opts.cone_mode, &init_opts.sparse_index)) return 1; memset(&pl, 0, sizeof(pl)); @@ -432,17 +461,6 @@ static int sparse_checkout_init(int argc, const char **argv) sparse_filename = get_sparse_checkout_filename(); res = add_patterns_from_file_to_list(sparse_filename, "", 0, &pl, NULL, 0); - if (init_opts.sparse_index >= 0) { - if (set_sparse_index_config(the_repository, init_opts.sparse_index) < 0) - die(_("failed to modify sparse-index config")); - - /* force an index rewrite */ - repo_read_index(the_repository); - the_repository->index->updated_workdir = 1; - } - - core_apply_sparse_checkout = 1; - /* If we already have a sparse-checkout file, use it. */ if (res >= 0) { free(sparse_filename); -- cgit v1.2.3 From f2e3a218e80fc3fd357afe65c9a26b9a90a9f5f7 Mon Sep 17 00:00:00 2001 From: Elijah Newren Date: Tue, 14 Dec 2021 04:09:08 +0000 Subject: sparse-checkout: enable `set` to initialize sparse-checkout mode The previously suggested workflow: git sparse-checkout init ... git sparse-checkout set ... Suffered from three problems: 1) It would delete nearly all files in the first step, then restore them in the second. That was poor performance and forced unnecessary rebuilds. 2) The two-step process resulted in two progress bars, which was suboptimal from a UI point of view for wrappers that invoked both of these commands but only exposed a single command to their end users. 3) With cone mode, the first step would delete nearly all ignored files everywhere, because everything was considered to be outside of the specified sparsity paths. (The user was not allowed to specify any sparsity paths in the `init` step.) Avoid these problems by teaching `set` to understand the extra parameters that `init` takes and performing any necessary initialization if not already in a sparse checkout. Reviewed-by: Derrick Stolee Reviewed-by: Victoria Dye Signed-off-by: Elijah Newren Signed-off-by: Junio C Hamano --- builtin/sparse-checkout.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) (limited to 'builtin') diff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c index 3b74779bb4..16daae8497 100644 --- a/builtin/sparse-checkout.c +++ b/builtin/sparse-checkout.c @@ -706,17 +706,26 @@ static int sparse_checkout_add(int argc, const char **argv, const char *prefix) } static char const * const builtin_sparse_checkout_set_usage[] = { - N_("git sparse-checkout set (--stdin | )"), + N_("git sparse-checkout set [--[no-]cone] [--[no-]sparse-index] (--stdin | )"), NULL }; static struct sparse_checkout_set_opts { + int cone_mode; + int sparse_index; int use_stdin; } set_opts; static int sparse_checkout_set(int argc, const char **argv, const char *prefix) { + int default_patterns_nr = 2; + const char *default_patterns[] = {"/*", "!/*/", NULL}; + static struct option builtin_sparse_checkout_set_options[] = { + OPT_BOOL(0, "cone", &set_opts.cone_mode, + N_("initialize the sparse-checkout in cone mode")), + OPT_BOOL(0, "sparse-index", &set_opts.sparse_index, + N_("toggle the use of a sparse index")), OPT_BOOL_F(0, "stdin", &set_opts.use_stdin, N_("read patterns from standard in"), PARSE_OPT_NONEG), @@ -725,11 +734,27 @@ static int sparse_checkout_set(int argc, const char **argv, const char *prefix) repo_read_index(the_repository); + set_opts.cone_mode = -1; + set_opts.sparse_index = -1; + argc = parse_options(argc, argv, prefix, builtin_sparse_checkout_set_options, builtin_sparse_checkout_set_usage, PARSE_OPT_KEEP_UNKNOWN); + if (update_modes(&set_opts.cone_mode, &set_opts.sparse_index)) + return 1; + + /* + * Cone mode automatically specifies the toplevel directory. For + * non-cone mode, if nothing is specified, manually select just the + * top-level directory (much as 'init' would do). + */ + if (!core_sparse_checkout_cone && argc == 0) { + argv = default_patterns; + argc = default_patterns_nr; + } + return modify_pattern_list(argc, argv, set_opts.use_stdin, REPLACE); } -- cgit v1.2.3 From 4e256731d687a553fd7443f7596019dbe5b10598 Mon Sep 17 00:00:00 2001 From: Elijah Newren Date: Tue, 14 Dec 2021 04:09:09 +0000 Subject: sparse-checkout: enable reapply to take --[no-]{cone,sparse-index} Folks may want to switch to or from cone mode, or to or from a sparse-index without changing their sparsity paths. Allow them to do so using the reapply command. Reviewed-by: Derrick Stolee Reviewed-by: Victoria Dye Signed-off-by: Elijah Newren Signed-off-by: Junio C Hamano --- builtin/sparse-checkout.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'builtin') diff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c index 16daae8497..0dae44c575 100644 --- a/builtin/sparse-checkout.c +++ b/builtin/sparse-checkout.c @@ -759,13 +759,22 @@ static int sparse_checkout_set(int argc, const char **argv, const char *prefix) } static char const * const builtin_sparse_checkout_reapply_usage[] = { - N_("git sparse-checkout reapply"), + N_("git sparse-checkout reapply [--[no-]cone] [--[no-]sparse-index] "), NULL }; +static struct sparse_checkout_reapply_opts { + int cone_mode; + int sparse_index; +} reapply_opts; + static int sparse_checkout_reapply(int argc, const char **argv) { static struct option builtin_sparse_checkout_reapply_options[] = { + OPT_BOOL(0, "cone", &reapply_opts.cone_mode, + N_("initialize the sparse-checkout in cone mode")), + OPT_BOOL(0, "sparse-index", &reapply_opts.sparse_index, + N_("toggle the use of a sparse index")), OPT_END(), }; @@ -777,6 +786,13 @@ static int sparse_checkout_reapply(int argc, const char **argv) builtin_sparse_checkout_reapply_usage, 0); repo_read_index(the_repository); + + reapply_opts.cone_mode = -1; + reapply_opts.sparse_index = -1; + + if (update_modes(&reapply_opts.cone_mode, &reapply_opts.sparse_index)) + return 1; + return update_working_directory(NULL); } -- cgit v1.2.3 From d35954160a2c00a741e41030ff8449a9ae958439 Mon Sep 17 00:00:00 2001 From: Elijah Newren Date: Tue, 14 Dec 2021 04:09:12 +0000 Subject: clone: avoid using deprecated `sparse-checkout init` The previous commits marked `sparse-checkout init` as deprecated; we can just use `set` instead here and pass it no paths. Reviewed-by: Derrick Stolee Reviewed-by: Victoria Dye Signed-off-by: Elijah Newren Signed-off-by: Junio C Hamano --- builtin/clone.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'builtin') diff --git a/builtin/clone.c b/builtin/clone.c index fb377b2765..5bed37f8b5 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -633,7 +633,7 @@ static int git_sparse_checkout_init(const char *repo) { struct strvec argv = STRVEC_INIT; int result = 0; - strvec_pushl(&argv, "-C", repo, "sparse-checkout", "init", NULL); + strvec_pushl(&argv, "-C", repo, "sparse-checkout", "set", NULL); /* * We must apply the setting in the current process -- cgit v1.2.3 From dfac9b609f86cd4f6ce896df9e1172d2a02cde48 Mon Sep 17 00:00:00 2001 From: Elijah Newren Date: Thu, 23 Dec 2021 17:07:03 +0000 Subject: sparse-checkout: remove stray trailing space Reported-by: Jiang Xin Signed-off-by: Elijah Newren Signed-off-by: Junio C Hamano --- builtin/sparse-checkout.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'builtin') diff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c index 0dae44c575..45e838d8f8 100644 --- a/builtin/sparse-checkout.c +++ b/builtin/sparse-checkout.c @@ -759,7 +759,7 @@ static int sparse_checkout_set(int argc, const char **argv, const char *prefix) } static char const * const builtin_sparse_checkout_reapply_usage[] = { - N_("git sparse-checkout reapply [--[no-]cone] [--[no-]sparse-index] "), + N_("git sparse-checkout reapply [--[no-]cone] [--[no-]sparse-index]"), NULL }; -- cgit v1.2.3