@matheusbsbs / matheus-bagliano / commits / 94c0956b60
Fork 0

sparse-checkout: create builtin with 'list' subcommand

The sparse-checkout feature is mostly hidden to users, as its only documentation is supplementary information in the docs for 'git read-tree'. In addition, users need to know how to edit the .git/info/sparse-checkout file with the right patterns, then run the appropriate 'git read-tree -mu HEAD' command. Keeping the working directory in sync with the sparse-checkout file requires care. Begin an effort to make the sparse-checkout feature a porcelain feature by creating a new 'git sparse-checkout' builtin. This builtin will be the preferred mechanism for manipulating the sparse-checkout file and syncing the working directory. The documentation provided is adapted from the "git read-tree" documentation with a few edits for clarity in the new context. Extra sections are added to hint toward a future change to a more restricted pattern set. Helped-by: Elijah Newren <newren@gmail.com> 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 94c0956b60969bbbb3ead19638d52591a59d713c
9 files changed +226 -1
.gitignore
+1
@@ -158,6 +158,7 @@
158 /git-show-branch
159 /git-show-index
160 /git-show-ref
161 +/git-sparse-checkout
162 /git-stage
163 /git-stash
164 /git-status
Documentation/git-read-tree.txt
+1 -1
@@ -436,7 +436,7 @@ support.
436 SEE ALSO
437 --------
438 linkgit:git-write-tree[1]; linkgit:git-ls-files[1];
439 -linkgit:gitignore[5]
439 +linkgit:gitignore[5]; linkgit:git-sparse-checkout[1];
440
441 GIT
442 ---
Documentation/git-sparse-checkout.txt new
+89
@@ -0,0 +1,89 @@
1 +git-sparse-checkout(1)
2 +======================
3 +
4 +NAME
5 +----
6 +git-sparse-checkout - Initialize and modify the sparse-checkout
7 +configuration, which reduces the checkout to a set of paths
8 +given by a list of atterns.
9 +
10 +
11 +SYNOPSIS
12 +--------
13 +[verse]
14 +'git sparse-checkout <subcommand> [options]'
15 +
16 +
17 +DESCRIPTION
18 +-----------
19 +
20 +Initialize and modify the sparse-checkout configuration, which reduces
21 +the checkout to a set of paths given by a list of patterns.
22 +
23 +THIS COMMAND IS EXPERIMENTAL. ITS BEHAVIOR, AND THE BEHAVIOR OF OTHER
24 +COMMANDS IN THE PRESENCE OF SPARSE-CHECKOUTS, WILL LIKELY CHANGE IN
25 +THE FUTURE.
26 +
27 +
28 +COMMANDS
29 +--------
30 +'list'::
31 + Provide a list of the contents in the sparse-checkout file.
32 +
33 +
34 +SPARSE CHECKOUT
35 +---------------
36 +
37 +"Sparse checkout" allows populating the working directory sparsely.
38 +It uses the skip-worktree bit (see linkgit:git-update-index[1]) to tell
39 +Git whether a file in the working directory is worth looking at. If
40 +the skip-worktree bit is set, then the file is ignored in the working
41 +directory. Git will not populate the contents of those files, which
42 +makes a sparse checkout helpful when working in a repository with many
43 +files, but only a few are important to the current user.
44 +
45 +The `$GIT_DIR/info/sparse-checkout` file is used to define the
46 +skip-worktree reference bitmap. When Git updates the working
47 +directory, it updates the skip-worktree bits in the index based
48 +on this file. The files matching the patterns in the file will
49 +appear in the working directory, and the rest will not.
50 +
51 +## FULL PATTERN SET
52 +
53 +By default, the sparse-checkout file uses the same syntax as `.gitignore`
54 +files.
55 +
56 +While `$GIT_DIR/info/sparse-checkout` is usually used to specify what
57 +files are included, you can also specify what files are _not_ included,
58 +using negative patterns. For example, to remove the file `unwanted`:
59 +
60 +----------------
61 +/*
62 +!unwanted
63 +----------------
64 +
65 +Another tricky thing is fully repopulating the working directory when you
66 +no longer want sparse checkout. You cannot just disable "sparse
67 +checkout" because skip-worktree bits are still in the index and your working
68 +directory is still sparsely populated. You should re-populate the working
69 +directory with the `$GIT_DIR/info/sparse-checkout` file content as
70 +follows:
71 +
72 +----------------
73 +/*
74 +----------------
75 +
76 +Then you can disable sparse checkout. Sparse checkout support in 'git
77 +checkout' and similar commands is disabled by default. You need to
78 +set `core.sparseCheckout` to `true` in order to have sparse checkout
79 +support.
80 +
81 +SEE ALSO
82 +--------
83 +
84 +linkgit:git-read-tree[1]
85 +linkgit:gitignore[5]
86 +
87 +GIT
88 +---
89 +Part of the linkgit:git[1] suite
Makefile
+1
@@ -1125,6 +1125,7 @@ BUILTIN_OBJS += builtin/shortlog.o
1125 BUILTIN_OBJS += builtin/show-branch.o
1126 BUILTIN_OBJS += builtin/show-index.o
1127 BUILTIN_OBJS += builtin/show-ref.o
1128 +BUILTIN_OBJS += builtin/sparse-checkout.o
1129 BUILTIN_OBJS += builtin/stash.o
1130 BUILTIN_OBJS += builtin/stripspace.o
1131 BUILTIN_OBJS += builtin/submodule--helper.o
builtin.h
+1
@@ -225,6 +225,7 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix);
225 int cmd_show(int argc, const char **argv, const char *prefix);
226 int cmd_show_branch(int argc, const char **argv, const char *prefix);
227 int cmd_show_index(int argc, const char **argv, const char *prefix);
228 +int cmd_sparse_checkout(int argc, const char **argv, const char *prefix);
229 int cmd_status(int argc, const char **argv, const char *prefix);
230 int cmd_stash(int argc, const char **argv, const char *prefix);
231 int cmd_stripspace(int argc, const char **argv, const char *prefix);
builtin/sparse-checkout.c new
+86
@@ -0,0 +1,86 @@
1 +#include "builtin.h"
2 +#include "config.h"
3 +#include "dir.h"
4 +#include "parse-options.h"
5 +#include "pathspec.h"
6 +#include "repository.h"
7 +#include "run-command.h"
8 +#include "strbuf.h"
9 +
10 +static char const * const builtin_sparse_checkout_usage[] = {
11 + N_("git sparse-checkout list"),
12 + NULL
13 +};
14 +
15 +static char *get_sparse_checkout_filename(void)
16 +{
17 + return git_pathdup("info/sparse-checkout");
18 +}
19 +
20 +static void write_patterns_to_file(FILE *fp, struct pattern_list *pl)
21 +{
22 + int i;
23 +
24 + for (i = 0; i < pl->nr; i++) {
25 + struct path_pattern *p = pl->patterns[i];
26 +
27 + if (p->flags & PATTERN_FLAG_NEGATIVE)
28 + fprintf(fp, "!");
29 +
30 + fprintf(fp, "%s", p->pattern);
31 +
32 + if (p->flags & PATTERN_FLAG_MUSTBEDIR)
33 + fprintf(fp, "/");
34 +
35 + fprintf(fp, "\n");
36 + }
37 +}
38 +
39 +static int sparse_checkout_list(int argc, const char **argv)
40 +{
41 + struct pattern_list pl;
42 + char *sparse_filename;
43 + int res;
44 +
45 + memset(&pl, 0, sizeof(pl));
46 +
47 + sparse_filename = get_sparse_checkout_filename();
48 + res = add_patterns_from_file_to_list(sparse_filename, "", 0, &pl, NULL);
49 + free(sparse_filename);
50 +
51 + if (res < 0) {
52 + warning(_("this worktree is not sparse (sparse-checkout file may not exist)"));
53 + return 0;
54 + }
55 +
56 + write_patterns_to_file(stdout, &pl);
57 + clear_pattern_list(&pl);
58 +
59 + return 0;
60 +}
61 +
62 +int cmd_sparse_checkout(int argc, const char **argv, const char *prefix)
63 +{
64 + static struct option builtin_sparse_checkout_options[] = {
65 + OPT_END(),
66 + };
67 +
68 + if (argc == 2 && !strcmp(argv[1], "-h"))
69 + usage_with_options(builtin_sparse_checkout_usage,
70 + builtin_sparse_checkout_options);
71 +
72 + argc = parse_options(argc, argv, prefix,
73 + builtin_sparse_checkout_options,
74 + builtin_sparse_checkout_usage,
75 + PARSE_OPT_STOP_AT_NON_OPTION);
76 +
77 + git_config(git_default_config, NULL);
78 +
79 + if (argc > 0) {
80 + if (!strcmp(argv[0], "list"))
81 + return sparse_checkout_list(argc, argv);
82 + }
83 +
84 + usage_with_options(builtin_sparse_checkout_usage,
85 + builtin_sparse_checkout_options);
86 +}
command-list.txt
+1
@@ -166,6 +166,7 @@ git-show-index plumbinginterrogators
166 git-show-ref plumbinginterrogators
167 git-sh-i18n purehelpers
168 git-sh-setup purehelpers
169 +git-sparse-checkout mainporcelain worktree
170 git-stash mainporcelain
171 git-stage complete
172 git-status mainporcelain info
git.c
+1
@@ -572,6 +572,7 @@ static struct cmd_struct commands[] = {
572 { "show-branch", cmd_show_branch, RUN_SETUP },
573 { "show-index", cmd_show_index },
574 { "show-ref", cmd_show_ref, RUN_SETUP },
575 + { "sparse-checkout", cmd_sparse_checkout, RUN_SETUP | NEED_WORK_TREE },
576 { "stage", cmd_add, RUN_SETUP | NEED_WORK_TREE },
577 /*
578 * NEEDSWORK: Until the builtin stash is thoroughly robust and no
t/t1091-sparse-checkout-builtin.sh new
+45
@@ -0,0 +1,45 @@
1 +#!/bin/sh
2 +
3 +test_description='sparse checkout builtin tests'
4 +
5 +. ./test-lib.sh
6 +
7 +test_expect_success 'setup' '
8 + git init repo &&
9 + (
10 + cd repo &&
11 + echo "initial" >a &&
12 + mkdir folder1 folder2 deep &&
13 + mkdir deep/deeper1 deep/deeper2 &&
14 + mkdir deep/deeper1/deepest &&
15 + cp a folder1 &&
16 + cp a folder2 &&
17 + cp a deep &&
18 + cp a deep/deeper1 &&
19 + cp a deep/deeper2 &&
20 + cp a deep/deeper1/deepest &&
21 + git add . &&
22 + git commit -m "initial commit"
23 + )
24 +'
25 +
26 +test_expect_success 'git sparse-checkout list (empty)' '
27 + git -C repo sparse-checkout list >list 2>err &&
28 + test_must_be_empty list &&
29 + test_i18ngrep "this worktree is not sparse (sparse-checkout file may not exist)" err
30 +'
31 +
32 +test_expect_success 'git sparse-checkout list (populated)' '
33 + test_when_finished rm -f repo/.git/info/sparse-checkout &&
34 + cat >repo/.git/info/sparse-checkout <<-EOF &&
35 + /folder1/*
36 + /deep/
37 + **/a
38 + !*bin*
39 + EOF
40 + cp repo/.git/info/sparse-checkout expect &&
41 + git -C repo sparse-checkout list >list &&
42 + test_cmp expect list
43 +'
44 +
45 +test_done