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