Skip to content

Commit bd72a08

Browse files
committed
Merge branch 'ds/sparse-cone'
Management of sparsely checked-out working tree has gained a dedicated "sparse-checkout" command. * ds/sparse-cone: (21 commits) sparse-checkout: improve OS ls compatibility sparse-checkout: respect core.ignoreCase in cone mode sparse-checkout: check for dirty status sparse-checkout: update working directory in-process for 'init' sparse-checkout: cone mode should not interact with .gitignore sparse-checkout: write using lockfile sparse-checkout: use in-process update for disable subcommand sparse-checkout: update working directory in-process sparse-checkout: sanitize for nested folders unpack-trees: add progress to clear_ce_flags() unpack-trees: hash less in cone mode sparse-checkout: init and set in cone mode sparse-checkout: use hashmaps for cone patterns sparse-checkout: add 'cone' mode trace2: add region in clear_ce_flags sparse-checkout: create 'disable' subcommand sparse-checkout: add '--stdin' option to set subcommand sparse-checkout: 'set' subcommand clone: add --sparse mode sparse-checkout: create 'init' subcommand ...
2 parents f3c520e + 761e3d2 commit bd72a08

20 files changed

+1376
-48
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@
158158
/git-show-branch
159159
/git-show-index
160160
/git-show-ref
161+
/git-sparse-checkout
161162
/git-stage
162163
/git-stash
163164
/git-status

Documentation/config/core.txt

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -599,8 +599,14 @@ core.multiPackIndex::
599599
multi-pack-index design document].
600600

601601
core.sparseCheckout::
602-
Enable "sparse checkout" feature. See section "Sparse checkout" in
603-
linkgit:git-read-tree[1] for more information.
602+
Enable "sparse checkout" feature. See linkgit:git-sparse-checkout[1]
603+
for more information.
604+
605+
core.sparseCheckoutCone::
606+
Enables the "cone mode" of the sparse checkout feature. When the
607+
sparse-checkout file contains a limited set of patterns, then this
608+
mode provides significant performance advantages. See
609+
linkgit:git-sparse-checkout[1] for more information.
604610

605611
core.abbrev::
606612
Set the length object names are abbreviated to. If

Documentation/git-clone.txt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ SYNOPSIS
1515
[--dissociate] [--separate-git-dir <git dir>]
1616
[--depth <depth>] [--[no-]single-branch] [--no-tags]
1717
[--recurse-submodules[=<pathspec>]] [--[no-]shallow-submodules]
18-
[--[no-]remote-submodules] [--jobs <n>] [--] <repository>
18+
[--[no-]remote-submodules] [--jobs <n>] [--sparse] [--] <repository>
1919
[<directory>]
2020

2121
DESCRIPTION
@@ -156,6 +156,12 @@ objects from the source repository into a pack in the cloned repository.
156156
used, neither remote-tracking branches nor the related
157157
configuration variables are created.
158158

159+
--sparse::
160+
Initialize the sparse-checkout file so the working
161+
directory starts with only the files in the root
162+
of the repository. The sparse-checkout file can be
163+
modified to grow the working directory as needed.
164+
159165
--mirror::
160166
Set up a mirror of the source repository. This implies `--bare`.
161167
Compared to `--bare`, `--mirror` not only maps local branches of the

Documentation/git-read-tree.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,7 @@ support.
436436
SEE ALSO
437437
--------
438438
linkgit:git-write-tree[1]; linkgit:git-ls-files[1];
439-
linkgit:gitignore[5]
439+
linkgit:gitignore[5]; linkgit:git-sparse-checkout[1];
440440

441441
GIT
442442
---

Documentation/git-sparse-checkout.txt

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
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+
'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+
'set'::
46+
Write a set of patterns to the sparse-checkout file, as given as
47+
a list of arguments following the 'set' subcommand. Update the
48+
working directory to match the new patterns. Enable the
49+
core.sparseCheckout config setting if it is not already enabled.
50+
+
51+
When the `--stdin` option is provided, the patterns are read from
52+
standard in as a newline-delimited list instead of from the arguments.
53+
54+
'disable'::
55+
Disable the `core.sparseCheckout` config setting, and restore the
56+
working directory to include all files. Leaves the sparse-checkout
57+
file intact so a later 'git sparse-checkout init' command may
58+
return the working directory to the same state.
59+
60+
SPARSE CHECKOUT
61+
---------------
62+
63+
"Sparse checkout" allows populating the working directory sparsely.
64+
It uses the skip-worktree bit (see linkgit:git-update-index[1]) to tell
65+
Git whether a file in the working directory is worth looking at. If
66+
the skip-worktree bit is set, then the file is ignored in the working
67+
directory. Git will not populate the contents of those files, which
68+
makes a sparse checkout helpful when working in a repository with many
69+
files, but only a few are important to the current user.
70+
71+
The `$GIT_DIR/info/sparse-checkout` file is used to define the
72+
skip-worktree reference bitmap. When Git updates the working
73+
directory, it updates the skip-worktree bits in the index based
74+
on this file. The files matching the patterns in the file will
75+
appear in the working directory, and the rest will not.
76+
77+
To enable the sparse-checkout feature, run `git sparse-checkout init` to
78+
initialize a simple sparse-checkout file and enable the `core.sparseCheckout`
79+
config setting. Then, run `git sparse-checkout set` to modify the patterns in
80+
the sparse-checkout file.
81+
82+
To repopulate the working directory with all files, use the
83+
`git sparse-checkout disable` command.
84+
85+
86+
FULL PATTERN SET
87+
----------------
88+
89+
By default, the sparse-checkout file uses the same syntax as `.gitignore`
90+
files.
91+
92+
While `$GIT_DIR/info/sparse-checkout` is usually used to specify what
93+
files are included, you can also specify what files are _not_ included,
94+
using negative patterns. For example, to remove the file `unwanted`:
95+
96+
----------------
97+
/*
98+
!unwanted
99+
----------------
100+
101+
102+
CONE PATTERN SET
103+
----------------
104+
105+
The full pattern set allows for arbitrary pattern matches and complicated
106+
inclusion/exclusion rules. These can result in O(N*M) pattern matches when
107+
updating the index, where N is the number of patterns and M is the number
108+
of paths in the index. To combat this performance issue, a more restricted
109+
pattern set is allowed when `core.spareCheckoutCone` is enabled.
110+
111+
The accepted patterns in the cone pattern set are:
112+
113+
1. *Recursive:* All paths inside a directory are included.
114+
115+
2. *Parent:* All files immediately inside a directory are included.
116+
117+
In addition to the above two patterns, we also expect that all files in the
118+
root directory are included. If a recursive pattern is added, then all
119+
leading directories are added as parent patterns.
120+
121+
By default, when running `git sparse-checkout init`, the root directory is
122+
added as a parent pattern. At this point, the sparse-checkout file contains
123+
the following patterns:
124+
125+
----------------
126+
/*
127+
!/*/
128+
----------------
129+
130+
This says "include everything in root, but nothing two levels below root."
131+
If we then add the folder `A/B/C` as a recursive pattern, the folders `A` and
132+
`A/B` are added as parent patterns. The resulting sparse-checkout file is
133+
now
134+
135+
----------------
136+
/*
137+
!/*/
138+
/A/
139+
!/A/*/
140+
/A/B/
141+
!/A/B/*/
142+
/A/B/C/
143+
----------------
144+
145+
Here, order matters, so the negative patterns are overridden by the positive
146+
patterns that appear lower in the file.
147+
148+
If `core.sparseCheckoutCone=true`, then Git will parse the sparse-checkout file
149+
expecting patterns of these types. Git will warn if the patterns do not match.
150+
If the patterns do match the expected format, then Git will use faster hash-
151+
based algorithms to compute inclusion in the sparse-checkout.
152+
153+
If `core.ignoreCase=true`, then the pattern-matching algorithm will use a
154+
case-insensitive check. This corrects for case mismatched filenames in the
155+
'git sparse-checkout set' command to reflect the expected cone in the working
156+
directory.
157+
158+
SEE ALSO
159+
--------
160+
161+
linkgit:git-read-tree[1]
162+
linkgit:gitignore[5]
163+
164+
GIT
165+
---
166+
Part of the linkgit:git[1] suite

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1127,6 +1127,7 @@ BUILTIN_OBJS += builtin/shortlog.o
11271127
BUILTIN_OBJS += builtin/show-branch.o
11281128
BUILTIN_OBJS += builtin/show-index.o
11291129
BUILTIN_OBJS += builtin/show-ref.o
1130+
BUILTIN_OBJS += builtin/sparse-checkout.o
11301131
BUILTIN_OBJS += builtin/stash.o
11311132
BUILTIN_OBJS += builtin/stripspace.o
11321133
BUILTIN_OBJS += builtin/submodule--helper.o

builtin.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix);
225225
int cmd_show(int argc, const char **argv, const char *prefix);
226226
int cmd_show_branch(int argc, const char **argv, const char *prefix);
227227
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);
228229
int cmd_status(int argc, const char **argv, const char *prefix);
229230
int cmd_stash(int argc, const char **argv, const char *prefix);
230231
int cmd_stripspace(int argc, const char **argv, const char *prefix);

builtin/clone.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ static const char *real_git_dir;
5959
static char *option_upload_pack = "git-upload-pack";
6060
static int option_verbosity;
6161
static int option_progress = -1;
62+
static int option_sparse_checkout;
6263
static enum transport_family family;
6364
static struct string_list option_config = STRING_LIST_INIT_NODUP;
6465
static struct string_list option_required_reference = STRING_LIST_INIT_NODUP;
@@ -146,6 +147,8 @@ static struct option builtin_clone_options[] = {
146147
OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
147148
OPT_BOOL(0, "remote-submodules", &option_remote_submodules,
148149
N_("any cloned submodules will use their remote-tracking branch")),
150+
OPT_BOOL(0, "sparse", &option_sparse_checkout,
151+
N_("initialize sparse-checkout file to include only files at root")),
149152
OPT_END()
150153
};
151154

@@ -733,6 +736,27 @@ static void update_head(const struct ref *our, const struct ref *remote,
733736
}
734737
}
735738

739+
static int git_sparse_checkout_init(const char *repo)
740+
{
741+
struct argv_array argv = ARGV_ARRAY_INIT;
742+
int result = 0;
743+
argv_array_pushl(&argv, "-C", repo, "sparse-checkout", "init", NULL);
744+
745+
/*
746+
* We must apply the setting in the current process
747+
* for the later checkout to use the sparse-checkout file.
748+
*/
749+
core_apply_sparse_checkout = 1;
750+
751+
if (run_command_v_opt(argv.argv, RUN_GIT_CMD)) {
752+
error(_("failed to initialize sparse-checkout"));
753+
result = 1;
754+
}
755+
756+
argv_array_clear(&argv);
757+
return result;
758+
}
759+
736760
static int checkout(int submodule_progress)
737761
{
738762
struct object_id oid;
@@ -1104,6 +1128,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
11041128
if (option_required_reference.nr || option_optional_reference.nr)
11051129
setup_reference();
11061130

1131+
if (option_sparse_checkout && git_sparse_checkout_init(repo))
1132+
return 1;
1133+
11071134
remote = remote_get(option_origin);
11081135

11091136
strbuf_addf(&default_refspec, "+%s*:%s*", src_ref_prefix,

builtin/read-tree.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
185185

186186
if (opts.reset || opts.merge || opts.prefix) {
187187
if (read_cache_unmerged() && (opts.prefix || opts.merge))
188-
die("You need to resolve your current index first");
188+
die(_("You need to resolve your current index first"));
189189
stage = opts.merge = 1;
190190
}
191191
resolve_undo_clear();

0 commit comments

Comments
 (0)