Skip to content

Commit 73d6632

Browse files
committed
Merge branch 'nd/sparse'
* nd/sparse: (25 commits) t7002: test for not using external grep on skip-worktree paths t7002: set test prerequisite "external-grep" if supported grep: do not do external grep on skip-worktree entries commit: correctly respect skip-worktree bit ie_match_stat(): do not ignore skip-worktree bit with CE_MATCH_IGNORE_VALID tests: rename duplicate t1009 sparse checkout: inhibit empty worktree Add tests for sparse checkout read-tree: add --no-sparse-checkout to disable sparse checkout support unpack-trees(): ignore worktree check outside checkout area unpack_trees(): apply $GIT_DIR/info/sparse-checkout to the final index unpack-trees(): "enable" sparse checkout and load $GIT_DIR/info/sparse-checkout unpack-trees.c: generalize verify_* functions unpack-trees(): add CE_WT_REMOVE to remove on worktree alone Introduce "sparse checkout" dir.c: export excluded_1() and add_excludes_from_file_1() excluded_1(): support exclude files in index unpack-trees(): carry skip-worktree bit over in merged_entry() Read .gitignore from index if it is skip-worktree Avoid writing to buffer in add_excludes_from_file_1() ... Conflicts: .gitignore Documentation/config.txt Documentation/git-update-index.txt Makefile entry.c t/t7002-grep.sh
2 parents 054d2fa + 8740773 commit 73d6632

33 files changed

+1049
-102
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@
158158
/test-delta
159159
/test-dump-cache-tree
160160
/test-genrandom
161+
/test-index-version
161162
/test-match-trees
162163
/test-parse-options
163164
/test-path-utils

Documentation/config.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,10 @@ notes should be printed.
502502
This setting defaults to "refs/notes/commits", and can be overridden by
503503
the `GIT_NOTES_REF` environment variable.
504504

505+
core.sparseCheckout::
506+
Enable "sparse checkout" feature. See section "Sparse checkout" in
507+
linkgit:git-read-tree[1] for more information.
508+
505509
add.ignore-errors::
506510
Tells 'git-add' to continue adding files when some files cannot be
507511
added due to indexing errors. Equivalent to the '--ignore-errors'

Documentation/git-ls-files.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ OPTIONS
109109
Identify the file status with the following tags (followed by
110110
a space) at the start of each line:
111111
H:: cached
112+
S:: skip-worktree
112113
M:: unmerged
113114
R:: removed/deleted
114115
C:: modified/changed

Documentation/git-read-tree.txt

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ SYNOPSIS
1010
--------
1111
'git read-tree' [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>]
1212
[-u [--exclude-per-directory=<gitignore>] | -i]]
13-
[--index-output=<file>]
13+
[--index-output=<file>] [--no-sparse-checkout]
1414
<tree-ish1> [<tree-ish2> [<tree-ish3>]]
1515

1616

@@ -110,6 +110,10 @@ OPTIONS
110110
directories the index file and index output file are
111111
located in.
112112

113+
--no-sparse-checkout::
114+
Disable sparse checkout support even if `core.sparseCheckout`
115+
is true.
116+
113117
<tree-ish#>::
114118
The id of the tree object(s) to be read/merged.
115119

@@ -360,6 +364,52 @@ middle of doing, and when your working tree is ready (i.e. you
360364
have finished your work-in-progress), attempt the merge again.
361365

362366

367+
Sparse checkout
368+
---------------
369+
370+
"Sparse checkout" allows to sparsely populate working directory.
371+
It uses skip-worktree bit (see linkgit:git-update-index[1]) to tell
372+
Git whether a file on working directory is worth looking at.
373+
374+
"git read-tree" and other merge-based commands ("git merge", "git
375+
checkout"...) can help maintaining skip-worktree bitmap and working
376+
directory update. `$GIT_DIR/info/sparse-checkout` is used to
377+
define the skip-worktree reference bitmap. When "git read-tree" needs
378+
to update working directory, it will reset skip-worktree bit in index
379+
based on this file, which uses the same syntax as .gitignore files.
380+
If an entry matches a pattern in this file, skip-worktree will be
381+
set on that entry. Otherwise, skip-worktree will be unset.
382+
383+
Then it compares the new skip-worktree value with the previous one. If
384+
skip-worktree turns from unset to set, it will add the corresponding
385+
file back. If it turns from set to unset, that file will be removed.
386+
387+
While `$GIT_DIR/info/sparse-checkout` is usually used to specify what
388+
files are in. You can also specify what files are _not_ in, using
389+
negate patterns. For example, to remove file "unwanted":
390+
391+
----------------
392+
*
393+
!unwanted
394+
----------------
395+
396+
Another tricky thing is fully repopulating working directory when you
397+
no longer want sparse checkout. You cannot just disable "sparse
398+
checkout" because skip-worktree are still in the index and you working
399+
directory is still sparsely populated. You should re-populate working
400+
directory with the `$GIT_DIR/info/sparse-checkout` file content as
401+
follows:
402+
403+
----------------
404+
*
405+
----------------
406+
407+
Then you can disable sparse checkout. Sparse checkout support in "git
408+
read-tree" and similar commands is disabled by default. You need to
409+
turn `core.sparseCheckout` on in order to have sparse checkout
410+
support.
411+
412+
363413
SEE ALSO
364414
--------
365415
linkgit:git-write-tree[1]; linkgit:git-ls-files[1];

Documentation/git-update-index.txt

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ SYNOPSIS
1515
[--cacheinfo <mode> <object> <file>]\*
1616
[--chmod=(+|-)x]
1717
[--assume-unchanged | --no-assume-unchanged]
18+
[--skip-worktree | --no-skip-worktree]
1819
[--ignore-submodules]
1920
[--really-refresh] [--unresolve] [--again | -g]
2021
[--info-only] [--index-info]
@@ -103,6 +104,13 @@ you will need to handle the situation manually.
103104
Like '--refresh', but checks stat information unconditionally,
104105
without regard to the "assume unchanged" setting.
105106

107+
--skip-worktree::
108+
--no-skip-worktree::
109+
When one of these flags is specified, the object name recorded
110+
for the paths are not updated. Instead, these options
111+
set and unset the "skip-worktree" bit for the paths. See
112+
section "Skip-worktree bit" below for more information.
113+
106114
-g::
107115
--again::
108116
Runs 'git-update-index' itself on the paths whose index
@@ -308,6 +316,27 @@ M foo.c
308316
<9> now it checks with lstat(2) and finds it has been changed.
309317

310318

319+
Skip-worktree bit
320+
-----------------
321+
322+
Skip-worktree bit can be defined in one (long) sentence: When reading
323+
an entry, if it is marked as skip-worktree, then Git pretends its
324+
working directory version is up to date and read the index version
325+
instead.
326+
327+
To elaborate, "reading" means checking for file existence, reading
328+
file attributes or file content. The working directory version may be
329+
present or absent. If present, its content may match against the index
330+
version or not. Writing is not affected by this bit, content safety
331+
is still first priority. Note that Git _can_ update working directory
332+
file, that is marked skip-worktree, if it is safe to do so (i.e.
333+
working directory version matches index version)
334+
335+
Although this bit looks similar to assume-unchanged bit, its goal is
336+
different from assume-unchanged bit's. Skip-worktree also takes
337+
precedence over assume-unchanged bit when both are set.
338+
339+
311340
Configuration
312341
-------------
313342

Documentation/technical/api-directory-listing.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ The result of the enumeration is left in these fields::
5858
Calling sequence
5959
----------------
6060

61+
Note: index may be looked at for .gitignore files that are CE_SKIP_WORKTREE
62+
marked. If you to exclude files, make sure you have loaded index first.
63+
6164
* Prepare `struct dir_struct dir` and clear it with `memset(&dir, 0,
6265
sizeof(dir))`.
6366

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1782,6 +1782,7 @@ TEST_PROGRAMS_NEED_X += test-parse-options
17821782
TEST_PROGRAMS_NEED_X += test-path-utils
17831783
TEST_PROGRAMS_NEED_X += test-sha1
17841784
TEST_PROGRAMS_NEED_X += test-sigchain
1785+
TEST_PROGRAMS_NEED_X += test-index-version
17851786

17861787
TEST_PROGRAMS = $(patsubst %,%$X,$(TEST_PROGRAMS_NEED_X))
17871788

builtin-apply.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2666,7 +2666,7 @@ static int verify_index_match(struct cache_entry *ce, struct stat *st)
26662666
return -1;
26672667
return 0;
26682668
}
2669-
return ce_match_stat(ce, st, CE_MATCH_IGNORE_VALID);
2669+
return ce_match_stat(ce, st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE);
26702670
}
26712671

26722672
static int check_preimage(struct patch *patch, struct cache_entry **ce, struct stat *st)

builtin-clean.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,11 +75,13 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
7575

7676
dir.flags |= DIR_SHOW_OTHER_DIRECTORIES;
7777

78+
if (read_cache() < 0)
79+
die("index file corrupt");
80+
7881
if (!ignored)
7982
setup_standard_excludes(&dir);
8083

8184
pathspec = get_pathspec(prefix, argv);
82-
read_cache();
8385

8486
fill_directory(&dir, pathspec);
8587

builtin-commit.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,11 +183,15 @@ static int list_paths(struct string_list *list, const char *with_tree,
183183

184184
for (i = 0; i < active_nr; i++) {
185185
struct cache_entry *ce = active_cache[i];
186+
struct string_list_item *item;
187+
186188
if (ce->ce_flags & CE_UPDATE)
187189
continue;
188190
if (!match_pathspec(pattern, ce->name, ce_namelen(ce), 0, m))
189191
continue;
190-
string_list_insert(ce->name, list);
192+
item = string_list_insert(ce->name, list);
193+
if (ce_skip_worktree(ce))
194+
item->util = item; /* better a valid pointer than a fake one */
191195
}
192196

193197
return report_path_error(m, pattern, prefix ? strlen(prefix) : 0);
@@ -200,6 +204,10 @@ static void add_remove_files(struct string_list *list)
200204
struct stat st;
201205
struct string_list_item *p = &(list->items[i]);
202206

207+
/* p->util is skip-worktree */
208+
if (p->util)
209+
continue;
210+
203211
if (!lstat(p->string, &st)) {
204212
if (add_to_cache(p->string, &st, 0))
205213
die("updating files failed");

0 commit comments

Comments
 (0)