Skip to content

Commit ef2d425

Browse files
committed
Merge branch 'ds/sparse-cone' into pu
Management of sparsely checked-out working tree has gained a dedicated "sparse-checkout" command. Seems not to play well with the hashmap updates. * ds/sparse-cone: sparse-checkout: cone mode should not interact with .gitignore sparse-checkout: write using lockfile sparse-checkout: update working directory in-process sparse-checkout: sanitize for nested folders read-tree: show progress by default 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 sparse-checkout: create builtin with 'list' subcommand
2 parents 04ef486 + 8aedbda commit ef2d425

19 files changed

+1280
-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
@@ -593,8 +593,14 @@ core.multiPackIndex::
593593
multi-pack-index design document].
594594

595595
core.sparseCheckout::
596-
Enable "sparse checkout" feature. See section "Sparse checkout" in
597-
linkgit:git-read-tree[1] for more information.
596+
Enable "sparse checkout" feature. See linkgit:git-sparse-checkout[1]
597+
for more information.
598+
599+
core.sparseCheckoutCone::
600+
Enables the "cone mode" of the sparse checkout feature. When the
601+
sparse-checkout file contains a limited set of patterns, then this
602+
mode provides significant performance advantages. See
603+
linkgit:git-sparse-checkout[1] for more information.
598604

599605
core.abbrev::
600606
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: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
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 directories
8+
given by a list of prefixes.
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 directories given by a list of prefixes.
22+
23+
24+
COMMANDS
25+
--------
26+
'list'::
27+
Provide a list of the contents in the sparse-checkout file.
28+
29+
'init'::
30+
Enable the `core.sparseCheckout` setting. If the
31+
sparse-checkout file does not exist, then populate it with
32+
patterns that match every file in the root directory and
33+
no other directories, then will remove all directories tracked
34+
by Git. Add patterns to the sparse-checkout file to
35+
repopulate the working directory.
36+
+
37+
The init subcommand also enables the 'extensions.worktreeConfig' setting
38+
and sets the `core.sparseCheckout` setting in the worktree-specific config
39+
file. This prevents the sparse-checkout feature from interfering with other
40+
worktrees.
41+
42+
'set'::
43+
Write a set of patterns to the sparse-checkout file, as given as
44+
a list of arguments following the 'set' subcommand. Update the
45+
working directory to match the new patterns.
46+
47+
'disable'::
48+
Remove the sparse-checkout file, set `core.sparseCheckout` to
49+
`false`, and restore the working directory to include all files.
50+
51+
SPARSE CHECKOUT
52+
----------------
53+
54+
"Sparse checkout" allows populating the working directory sparsely.
55+
It uses the skip-worktree bit (see linkgit:git-update-index[1]) to tell
56+
Git whether a file in the working directory is worth looking at. If
57+
the skip-worktree bit is set, then the file is ignored in the working
58+
directory. Git will not populate the contents of those files, which
59+
makes a sparse checkout helpful when working in a repository with many
60+
files, but only a few are important to the current user.
61+
62+
The `$GIT_DIR/info/sparse-checkout` file is used to define the
63+
skip-worktree reference bitmap. When Git updates the working
64+
directory, it updates the skip-worktree bits in the index based
65+
ont this file. The files matching the patterns in the file will
66+
appear in the working directory, and the rest will not.
67+
68+
To enable the sparse-checkout feature, run `git sparse-checkout init` to
69+
initialize a simple sparse-checkout file and enable the `core.sparseCheckout`
70+
config setting. Then, run `git sparse-checkout set` to modify the patterns in
71+
the sparse-checkout file.
72+
73+
To repopulate the working directory with all files, use the
74+
`git sparse-checkout disable` command.
75+
76+
## FULL PATTERN SET
77+
78+
By default, the sparse-checkout file uses the same syntax as `.gitignore`
79+
files.
80+
81+
While `$GIT_DIR/info/sparse-checkout` is usually used to specify what
82+
files are included, you can also specify what files are _not_ included,
83+
using negative patterns. For example, to remove the file `unwanted`:
84+
85+
----------------
86+
/*
87+
!unwanted
88+
----------------
89+
90+
91+
## CONE PATTERN SET
92+
93+
The full pattern set allows for arbitrary pattern matches and complicated
94+
inclusion/exclusion rules. These can result in O(N*M) pattern matches when
95+
updating the index, where N is the number of patterns and M is the number
96+
of paths in the index. To combat this performance issue, a more restricted
97+
pattern set is allowed when `core.spareCheckoutCone` is enabled.
98+
99+
The accepted patterns in the cone pattern set are:
100+
101+
1. *Recursive:* All paths inside a directory are included.
102+
103+
2. *Parent:* All files immediately inside a directory are included.
104+
105+
In addition to the above two patterns, we also expect that all files in the
106+
root directory are included. If a recursive pattern is added, then all
107+
leading directories are added as parent patterns.
108+
109+
By default, when running `git sparse-checkout init`, the root directory is
110+
added as a parent pattern. At this point, the sparse-checkout file contains
111+
the following patterns:
112+
113+
```
114+
/*
115+
!/*/
116+
```
117+
118+
This says "include everything in root, but nothing two levels below root."
119+
If we then add the folder `A/B/C` as a recursive pattern, the folders `A` and
120+
`A/B` are added as parent patterns. The resulting sparse-checkout file is
121+
now
122+
123+
```
124+
/*
125+
!/*/
126+
/A/
127+
!/A/*/
128+
/A/B/
129+
!/A/B/*/
130+
/A/B/C/
131+
```
132+
133+
Here, order matters, so the negative patterns are overridden by the positive
134+
patterns that appear lower in the file.
135+
136+
If `core.sparseCheckoutCone=true`, then Git will parse the sparse-checkout file
137+
expecting patterns of these types. Git will warn if the patterns do not match.
138+
If the patterns do match the expected format, then Git will use faster hash-
139+
based algorithms to compute inclusion in the sparse-checkout.
140+
141+
SEE ALSO
142+
--------
143+
144+
linkgit:git-read-tree[1]
145+
linkgit:gitignore[5]
146+
147+
GIT
148+
---
149+
Part of the linkgit:git[1] suite

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1125,6 +1125,7 @@ BUILTIN_OBJS += builtin/shortlog.o
11251125
BUILTIN_OBJS += builtin/show-branch.o
11261126
BUILTIN_OBJS += builtin/show-index.o
11271127
BUILTIN_OBJS += builtin/show-ref.o
1128+
BUILTIN_OBJS += builtin/sparse-checkout.o
11281129
BUILTIN_OBJS += builtin/stash.o
11291130
BUILTIN_OBJS += builtin/stripspace.o
11301131
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;
@@ -1110,6 +1134,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
11101134
if (option_required_reference.nr || option_optional_reference.nr)
11111135
setup_reference();
11121136

1137+
if (option_sparse_checkout && git_sparse_checkout_init(repo))
1138+
return 1;
1139+
11131140
remote = remote_get(option_origin);
11141141

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

builtin/read-tree.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
162162
opts.head_idx = -1;
163163
opts.src_index = &the_index;
164164
opts.dst_index = &the_index;
165+
opts.verbose_update = isatty(2);
165166

166167
git_config(git_read_tree_config, NULL);
167168

@@ -185,7 +186,7 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
185186

186187
if (opts.reset || opts.merge || opts.prefix) {
187188
if (read_cache_unmerged() && (opts.prefix || opts.merge))
188-
die("You need to resolve your current index first");
189+
die(_("You need to resolve your current index first"));
189190
stage = opts.merge = 1;
190191
}
191192
resolve_undo_clear();

0 commit comments

Comments
 (0)