Skip to content

Commit ecc7c88

Browse files
newrengitster
authored andcommitted
repo_read_index: add config to expect files outside sparse patterns
Typically with sparse checkouts, we expect files outside the sparsity patterns to be marked as SKIP_WORKTREE and be missing from the working tree. Sometimes this expectation would be violated however; including in cases such as: * users grabbing files from elsewhere and writing them to the worktree (perhaps by editing a cached copy in an editor, copying/renaming, or even untarring) * various git commands having incomplete or no support for the SKIP_WORKTREE bit[1,2] * users attempting to "abort" a sparse-checkout operation with a not-so-early Ctrl+C (updating $GIT_DIR/info/sparse-checkout and the working tree is not atomic)[3]. When the SKIP_WORKTREE bit in the index did not reflect the presence of the file in the working tree, it traditionally caused confusion and was difficult to detect and recover from. So, in a sparse checkout, since af6a518 (repo_read_index: clear SKIP_WORKTREE bit from files present in worktree, 2022-01-14), Git automatically clears the SKIP_WORKTREE bit at index read time for entries corresponding to files that are present in the working tree. There is another workflow, however, where it is expected that paths outside the sparsity patterns appear to exist in the working tree and that they do not lose the SKIP_WORKTREE bit, at least until they get modified. A Git-aware virtual file system[4] takes advantage of its position as a file system driver to expose all files in the working tree, fetch them on demand using partial clone on access, and tell Git to pay attention to them on demand by updating the sparse checkout pattern on writes. This means that commands like "git status" only have to examine files that have potentially been modified, whereas commands like "ls" are able to show the entire codebase without requiring manual updates to the sparse checkout pattern. Thus since af6a518, Git with such Git-aware virtual file systems unsets the SKIP_WORKTREE bit for all files and commands like "git status" have to fetch and examine them all. Introduce a configuration setting sparse.expectFilesOutsideOfPatterns to allow limiting the tracked set of files to a small set once again. A Git-aware virtual file system or other application that wants to maintain files outside of the sparse checkout can set this in a repository to instruct Git not to check for the presence of SKIP_WORKTREE files. The setting defaults to false, so most users of sparse checkout will still get the benefit of an automatically updating index to recover from the variety of difficult issues detailed in af6a518 for paths with SKIP_WORKTREE set despite the path being present. [1] https://lore.kernel.org/git/[email protected]/ [2] The three long paragraphs in the middle of https://lore.kernel.org/git/CABPp-BH9tju7WVm=QZDOvaMDdZbpNXrVWQdN-jmfN8wC6YVhmw@mail.gmail.com/ [3] https://lore.kernel.org/git/CABPp-BFnFpzwGC11TLoLs8YK5yiisA5D5-fFjXnJsbESVDwZsA@mail.gmail.com/ [4] such as the vfsd described in https://lore.kernel.org/git/[email protected]/ Signed-off-by: Jonathan Nieder <[email protected]> Signed-off-by: Elijah Newren <[email protected]> Reviewed-by: Jonathan Nieder <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent d79d299 commit ecc7c88

File tree

7 files changed

+66
-1
lines changed

7 files changed

+66
-1
lines changed

Documentation/config.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,8 @@ include::config/sequencer.txt[]
468468

469469
include::config/showbranch.txt[]
470470

471+
include::config/sparse.txt[]
472+
471473
include::config/splitindex.txt[]
472474

473475
include::config/ssh.txt[]

Documentation/config/sparse.txt

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
sparse.expectFilesOutsideOfPatterns::
2+
Typically with sparse checkouts, files not matching any
3+
sparsity patterns are marked with a SKIP_WORKTREE bit in the
4+
index and are missing from the working tree. Accordingly, Git
5+
will ordinarily check whether files with the SKIP_WORKTREE bit
6+
are in fact present in the working tree contrary to
7+
expectations. If Git finds any, it marks those paths as
8+
present by clearing the relevant SKIP_WORKTREE bits. This
9+
option can be used to tell Git that such
10+
present-despite-skipped files are expected and to stop
11+
checking for them.
12+
+
13+
The default is `false`, which allows Git to automatically recover
14+
from the list of files in the index and working tree falling out of
15+
sync.
16+
+
17+
Set this to `true` if you are in a setup where some external factor
18+
relieves Git of the responsibility for maintaining the consistency
19+
between the presence of working tree files and sparsity patterns. For
20+
example, if you have a Git-aware virtual file system that has a robust
21+
mechanism for keeping the working tree and the sparsity patterns up to
22+
date based on access patterns.
23+
+
24+
Regardless of this setting, Git does not check for
25+
present-despite-skipped files unless sparse checkout is enabled, so
26+
this config option has no effect unless `core.sparseCheckout` is
27+
`true`.

cache.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,6 +1003,7 @@ extern const char *core_fsmonitor;
10031003

10041004
extern int core_apply_sparse_checkout;
10051005
extern int core_sparse_checkout_cone;
1006+
extern int sparse_expect_files_outside_of_patterns;
10061007

10071008
/*
10081009
* Returns the boolean value of $GIT_OPTIONAL_LOCKS (or the default value).

config.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1544,6 +1544,17 @@ static int git_default_core_config(const char *var, const char *value, void *cb)
15441544
return platform_core_config(var, value, cb);
15451545
}
15461546

1547+
static int git_default_sparse_config(const char *var, const char *value)
1548+
{
1549+
if (!strcmp(var, "sparse.expectfilesoutsideofpatterns")) {
1550+
sparse_expect_files_outside_of_patterns = git_config_bool(var, value);
1551+
return 0;
1552+
}
1553+
1554+
/* Add other config variables here and to Documentation/config/sparse.txt. */
1555+
return 0;
1556+
}
1557+
15471558
static int git_default_i18n_config(const char *var, const char *value)
15481559
{
15491560
if (!strcmp(var, "i18n.commitencoding"))
@@ -1675,6 +1686,9 @@ int git_default_config(const char *var, const char *value, void *cb)
16751686
return 0;
16761687
}
16771688

1689+
if (starts_with(var, "sparse."))
1690+
return git_default_sparse_config(var, value);
1691+
16781692
/* Add other config variables here and to Documentation/config.txt. */
16791693
return 0;
16801694
}

environment.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ char *notes_ref_name;
7070
int grafts_replace_parents = 1;
7171
int core_apply_sparse_checkout;
7272
int core_sparse_checkout_cone;
73+
int sparse_expect_files_outside_of_patterns;
7374
int merge_log_config = -1;
7475
int precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */
7576
unsigned long pack_size_limit_cfg;

sparse-index.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -396,7 +396,8 @@ void clear_skip_worktree_from_present_files(struct index_state *istate)
396396

397397
int i;
398398

399-
if (!core_apply_sparse_checkout)
399+
if (!core_apply_sparse_checkout ||
400+
sparse_expect_files_outside_of_patterns)
400401
return;
401402

402403
restart:

t/t1090-sparse-checkout-scope.sh

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,25 @@ test_expect_success 'return to full checkout of main' '
5252
test "$(cat b)" = "modified"
5353
'
5454

55+
test_expect_success 'skip-worktree on files outside sparse patterns' '
56+
git sparse-checkout disable &&
57+
git sparse-checkout set --no-cone "a*" &&
58+
git checkout-index --all --ignore-skip-worktree-bits &&
59+
60+
git ls-files -t >output &&
61+
! grep ^S output >actual &&
62+
test_must_be_empty actual &&
63+
64+
test_config sparse.expectFilesOutsideOfPatterns true &&
65+
cat <<-\EOF >expect &&
66+
S b
67+
S c
68+
EOF
69+
git ls-files -t >output &&
70+
grep ^S output >actual &&
71+
test_cmp expect actual
72+
'
73+
5574
test_expect_success 'in partial clone, sparse checkout only fetches needed blobs' '
5675
test_create_repo server &&
5776
git clone "file://$(pwd)/server" client &&

0 commit comments

Comments
 (0)