@matheusbsbs / matheus-bagliano / commits / bab3c35908
Fork 0

sparse-checkout: create 'init' subcommand

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. 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@microsoft.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Derrick Stolee committed Nov 21, 2019 at 22:04 UTC bab3c3590879c5680060a5d5e2b93b4f97519025
3 files changed +125 -1
Documentation/git-sparse-checkout.txt
+11
@@ -30,6 +30,17 @@ COMMANDS
30 'list'::
31 Provide a list of the contents in the sparse-checkout file.
32
33 +'init'::
34 + Enable the `core.sparseCheckout` setting. If the
35 + sparse-checkout file does not exist, then populate it with
36 + patterns that match every file in the root directory and
37 + no other directories, then will remove all directories tracked
38 + by Git. Add patterns to the sparse-checkout file to
39 + repopulate the working directory.
40 ++
41 +To avoid interfering with other worktrees, it first enables the
42 +`extensions.worktreeConfig` setting and makes sure to set the
43 +`core.sparseCheckout` setting in the worktree-specific config file.
44
45 SPARSE CHECKOUT
46 ---------------
builtin/sparse-checkout.c
+74 -1
@@ -8,7 +8,7 @@
8 #include "strbuf.h"
9
10 static char const * const builtin_sparse_checkout_usage[] = {
11 - N_("git sparse-checkout list"),
11 + N_("git sparse-checkout (init|list)"),
12 NULL
13 };
14
@@ -59,6 +59,77 @@ static int sparse_checkout_list(int argc, const char **argv)
59 return 0;
60 }
61
62 +static int update_working_directory(void)
63 +{
64 + struct argv_array argv = ARGV_ARRAY_INIT;
65 + int result = 0;
66 + argv_array_pushl(&argv, "read-tree", "-m", "-u", "HEAD", NULL);
67 +
68 + if (run_command_v_opt(argv.argv, RUN_GIT_CMD)) {
69 + error(_("failed to update index with new sparse-checkout paths"));
70 + result = 1;
71 + }
72 +
73 + argv_array_clear(&argv);
74 + return result;
75 +}
76 +
77 +enum sparse_checkout_mode {
78 + MODE_NO_PATTERNS = 0,
79 + MODE_ALL_PATTERNS = 1,
80 +};
81 +
82 +static int set_config(enum sparse_checkout_mode mode)
83 +{
84 + const char *config_path;
85 +
86 + if (git_config_set_gently("extensions.worktreeConfig", "true")) {
87 + error(_("failed to set extensions.worktreeConfig setting"));
88 + return 1;
89 + }
90 +
91 + config_path = git_path("config.worktree");
92 + git_config_set_in_file_gently(config_path,
93 + "core.sparseCheckout",
94 + mode ? "true" : NULL);
95 +
96 + return 0;
97 +}
98 +
99 +static int sparse_checkout_init(int argc, const char **argv)
100 +{
101 + struct pattern_list pl;
102 + char *sparse_filename;
103 + FILE *fp;
104 + int res;
105 +
106 + if (set_config(MODE_ALL_PATTERNS))
107 + return 1;
108 +
109 + memset(&pl, 0, sizeof(pl));
110 +
111 + sparse_filename = get_sparse_checkout_filename();
112 + res = add_patterns_from_file_to_list(sparse_filename, "", 0, &pl, NULL);
113 +
114 + /* If we already have a sparse-checkout file, use it. */
115 + if (res >= 0) {
116 + free(sparse_filename);
117 + goto reset_dir;
118 + }
119 +
120 + /* initial mode: all blobs at root */
121 + fp = xfopen(sparse_filename, "w");
122 + if (!fp)
123 + die(_("failed to open '%s'"), sparse_filename);
124 +
125 + free(sparse_filename);
126 + fprintf(fp, "/*\n!/*/\n");
127 + fclose(fp);
128 +
129 +reset_dir:
130 + return update_working_directory();
131 +}
132 +
133 int cmd_sparse_checkout(int argc, const char **argv, const char *prefix)
134 {
135 static struct option builtin_sparse_checkout_options[] = {
@@ -79,6 +150,8 @@ int cmd_sparse_checkout(int argc, const char **argv, const char *prefix)
150 if (argc > 0) {
151 if (!strcmp(argv[0], "list"))
152 return sparse_checkout_list(argc, argv);
153 + if (!strcmp(argv[0], "init"))
154 + return sparse_checkout_init(argc, argv);
155 }
156
157 usage_with_options(builtin_sparse_checkout_usage,
t/t1091-sparse-checkout-builtin.sh
+40
@@ -42,4 +42,44 @@ test_expect_success 'git sparse-checkout list (populated)' '
42 test_cmp expect list
43 '
44
45 +test_expect_success 'git sparse-checkout init' '
46 + git -C repo sparse-checkout init &&
47 + cat >expect <<-EOF &&
48 + /*
49 + !/*/
50 + EOF
51 + test_cmp expect repo/.git/info/sparse-checkout &&
52 + test_cmp_config -C repo true core.sparsecheckout &&
53 + ls repo >dir &&
54 + echo a >expect &&
55 + test_cmp expect dir
56 +'
57 +
58 +test_expect_success 'git sparse-checkout list after init' '
59 + git -C repo sparse-checkout list >actual &&
60 + cat >expect <<-EOF &&
61 + /*
62 + !/*/
63 + EOF
64 + test_cmp expect actual
65 +'
66 +
67 +test_expect_success 'init with existing sparse-checkout' '
68 + echo "*folder*" >> repo/.git/info/sparse-checkout &&
69 + git -C repo sparse-checkout init &&
70 + cat >expect <<-EOF &&
71 + /*
72 + !/*/
73 + *folder*
74 + EOF
75 + test_cmp expect repo/.git/info/sparse-checkout &&
76 + ls repo >dir &&
77 + cat >expect <<-EOF &&
78 + a
79 + folder1
80 + folder2
81 + EOF
82 + test_cmp expect dir
83 +'
84 +
85 test_done