On Mon, Oct 21, 2019 at 01:56:11PM +0000, Derrick Stolee via GitGitGadget wrote: > From: Derrick Stolee <dstolee@xxxxxxxxxxxxx> > > Getting started with a sparse-checkout file can be daunting. Help > users start their sparse enlistment using 'git sparse-checkout init'. > This will set 'core.sparseCheckout=true' in their config, write > an initial set of patterns to the sparse-checkout file, and update > their working directory. Reading this I was wandering what those "initial set of patterns" might be ... > Make sure to use the `extensions.worktreeConfig` setting and write > the sparse checkout config to the worktree-specific config file. > This avoids confusing interactions with other worktrees. > > The use of running another process for 'git read-tree' is sub- > optimal. This will be removed in a later change. > > Signed-off-by: Derrick Stolee <dstolee@xxxxxxxxxxxxx> > --- > Documentation/git-sparse-checkout.txt | 11 ++++ > builtin/sparse-checkout.c | 79 ++++++++++++++++++++++++++- > t/t1091-sparse-checkout-builtin.sh | 41 ++++++++++++++ > 3 files changed, 130 insertions(+), 1 deletion(-) > > diff --git a/Documentation/git-sparse-checkout.txt b/Documentation/git-sparse-checkout.txt > index 9d6ca22917..930a361567 100644 > --- a/Documentation/git-sparse-checkout.txt > +++ b/Documentation/git-sparse-checkout.txt > @@ -30,6 +30,17 @@ COMMANDS > 'list':: > Provide a list of the contents in the sparse-checkout file. > > +'init':: > + Enable the `core.sparseCheckout` setting. If the > + sparse-checkout file does not exist, then populate it with > + patterns that match every file in the root directory and > + no other directories, then will remove all directories tracked > + by Git. Add patterns to the sparse-checkout file to > + repopulate the working directory. ... and then reading this I was wandering why these are those "initial set of patterns". > ++ > +To avoid interfering with other worktrees, it first enables the > +`extensions.worktreeConfig` setting and makes sure to set the > +`core.sparseCheckout` setting in the worktree-specific config file. > > SPARSE CHECKOUT > --------------- > diff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c > index 5717c9b2cb..77aa52ca01 100644 > --- a/builtin/sparse-checkout.c > +++ b/builtin/sparse-checkout.c > @@ -8,7 +8,7 @@ > #include "strbuf.h" > > static char const * const builtin_sparse_checkout_usage[] = { > - N_("git sparse-checkout list"), > + N_("git sparse-checkout (init|list)"), > NULL > }; > > @@ -59,6 +59,81 @@ static int sparse_checkout_list(int argc, const char **argv) > return 0; > } > > +static int update_working_directory(void) > +{ > + struct argv_array argv = ARGV_ARRAY_INIT; > + int result = 0; > + argv_array_pushl(&argv, "read-tree", "-m", "-u", "HEAD", NULL); > + > + if (run_command_v_opt(argv.argv, RUN_GIT_CMD)) { > + error(_("failed to update index with new sparse-checkout paths")); > + result = 1; > + } > + > + argv_array_clear(&argv); > + return result; > +} > + > +enum sparse_checkout_mode { > + MODE_NO_PATTERNS = 0, > + MODE_ALL_PATTERNS = 1, > +}; > + > +static int sc_set_config(enum sparse_checkout_mode mode) Nit: s/sc_//, perhaps? I suppose that "sc" prefix stands for "sparse checkout", but this is a static function in 'builtin/sparse-checkout.c', so it doesn't need a distinguising prefix. Even at the end of this patch series no other functions have this "sc" prefix. > +{ > + struct argv_array argv = ARGV_ARRAY_INIT; This 'argv_array' is not cleared at the end of the function, but... > + if (git_config_set_gently("extensions.worktreeConfig", "true")) { > + error(_("failed to set extensions.worktreeConfig setting")); > + return 1; > + } > + > + argv_array_pushl(&argv, "config", "--worktree", "core.sparseCheckout", NULL); > + > + if (mode) > + argv_array_pushl(&argv, "true", NULL); > + else > + argv_array_pushl(&argv, "false", NULL); > + > + if (run_command_v_opt(argv.argv, RUN_GIT_CMD)) { > + error(_("failed to enable core.sparseCheckout")); > + return 1; > + } Why the external 'git config' invocation? git_config_set_in_file_gently(git_path("config.worktree"), "core.sparseCheckout", mode ? "true" : "false") > + > + return 0; > +} > + > +static int sparse_checkout_init(int argc, const char **argv) > +{ > + struct pattern_list pl; > + char *sparse_filename; > + FILE *fp; > + int res; > + > + if (sc_set_config(MODE_ALL_PATTERNS)) > + return 1; > + > + memset(&pl, 0, sizeof(pl)); > + > + sparse_filename = get_sparse_checkout_filename(); > + res = add_patterns_from_file_to_list(sparse_filename, "", 0, &pl, NULL); > + > + /* If we already have a sparse-checkout file, use it. */ > + if (res >= 0) { > + free(sparse_filename); > + goto reset_dir; > + } > + > + /* initial mode: all blobs at root */ > + fp = xfopen(sparse_filename, "w"); > + free(sparse_filename); > + fprintf(fp, "/*\n!/*/\n"); What if this fprintf() call were to fail? > + fclose(fp); > + > +reset_dir: > + return update_working_directory(); > +} > + > int cmd_sparse_checkout(int argc, const char **argv, const char *prefix) > { > static struct option builtin_sparse_checkout_options[] = { > @@ -79,6 +154,8 @@ int cmd_sparse_checkout(int argc, const char **argv, const char *prefix) > if (argc > 0) { > if (!strcmp(argv[0], "list")) > return sparse_checkout_list(argc, argv); > + if (!strcmp(argv[0], "init")) > + return sparse_checkout_init(argc, argv); > } > > usage_with_options(builtin_sparse_checkout_usage, > diff --git a/t/t1091-sparse-checkout-builtin.sh b/t/t1091-sparse-checkout-builtin.sh > index 9b73d44907..cd56cc384b 100755 > --- a/t/t1091-sparse-checkout-builtin.sh > +++ b/t/t1091-sparse-checkout-builtin.sh > @@ -42,4 +42,45 @@ test_expect_success 'git sparse-checkout list (populated)' ' > test_cmp expect list > ' > > +test_expect_success 'git sparse-checkout init' ' > + git -C repo sparse-checkout init && > + cat >expect <<-EOF && > + /* > + !/*/ > + EOF > + test_cmp expect repo/.git/info/sparse-checkout && > + git -C repo config --list >config && > + test_i18ngrep "core.sparsecheckout=true" config && We have the 'test_cmp_config' helper function to check the expected value of configuration variables. > + ls repo >dir && > + echo a >expect && > + test_cmp expect dir > +' > + > +test_expect_success 'git sparse-checkout list after init' ' > + git -C repo sparse-checkout list >actual && > + cat >expect <<-EOF && > + /* > + !/*/ > + EOF > + test_cmp expect actual > +' > + > +test_expect_success 'init with existing sparse-checkout' ' > + echo "*folder*" >> repo/.git/info/sparse-checkout && > + git -C repo sparse-checkout init && > + cat >expect <<-EOF && > + /* > + !/*/ > + *folder* > + EOF > + test_cmp expect repo/.git/info/sparse-checkout && > + ls repo >dir && > + cat >expect <<-EOF && > + a > + folder1 > + folder2 > + EOF > + test_cmp expect dir > +' > + > test_done > -- > gitgitgadget >