Skip to content

Commit 5c9c248

Browse files
benpeartdscho
authored andcommitted
Add virtual file system settings and hook proc
On index load, clear/set the skip worktree bits based on the virtual file system data. Use virtual file system data to update skip-worktree bit in unpack-trees. Use virtual file system data to exclude files and folders not explicitly requested. Update 2022-04-05: disable the "present-despite-SKIP_WORKTREE" file removal behavior when 'core.virtualfilesystem' is enabled. Signed-off-by: Ben Peart <benpeart@microsoft.com>
1 parent 6aa0063 commit 5c9c248

18 files changed

Lines changed: 835 additions & 8 deletions

‎Documentation/config/core.adoc‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,14 @@ Version 2 uses an opaque string so that the monitor can return
111111
something that can be used to determine what files have changed
112112
without race conditions.
113113

114+
core.virtualFilesystem::
115+
If set, the value of this variable is used as a command which
116+
will identify all files and directories that are present in
117+
the working directory. Git will only track and update files
118+
listed in the virtual file system. Using the virtual file system
119+
will supersede the sparse-checkout settings which will be ignored.
120+
See the "virtual file system" section of linkgit:githooks[5].
121+
114122
core.trustctime::
115123
If false, the ctime differences between the index and the
116124
working tree are ignored; useful when the inode change time

‎Documentation/githooks.adoc‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -755,6 +755,26 @@ and "0" meaning they were not.
755755
Only one parameter should be set to "1" when the hook runs. The hook
756756
running passing "1", "1" should not be possible.
757757
758+
virtualFilesystem
759+
~~~~~~~~~~~~~~~~~~
760+
761+
"Virtual File System" allows populating the working directory sparsely.
762+
The projection data is typically automatically generated by an external
763+
process. Git will limit what files it checks for changes as well as which
764+
directories are checked for untracked files based on the path names given.
765+
Git will also only update those files listed in the projection.
766+
767+
The hook is invoked when the configuration option core.virtualFilesystem
768+
is set. It takes one argument, a version (currently 1).
769+
770+
The hook should output to stdout the list of all files in the working
771+
directory that git should track. The paths are relative to the root
772+
of the working directory and are separated by a single NUL. Full paths
773+
('dir1/a.txt') as well as directories are supported (ie 'dir1/').
774+
775+
The exit status determines whether git will use the data from the
776+
hook. On error, git will abort the command with an error message.
777+
758778
SEE ALSO
759779
--------
760780
linkgit:git-hook[1]

‎Makefile‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1355,6 +1355,7 @@ LIB_OBJS += varint.o
13551355
endif
13561356
LIB_OBJS += version.o
13571357
LIB_OBJS += versioncmp.o
1358+
LIB_OBJS += virtualfilesystem.o
13581359
LIB_OBJS += walker.o
13591360
LIB_OBJS += wildmatch.o
13601361
LIB_OBJS += worktree.o

‎config.c‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2480,6 +2480,32 @@ int repo_config_get_max_percent_split_change(struct repository *r)
24802480
return -1; /* default value */
24812481
}
24822482

2483+
int repo_config_get_virtualfilesystem(struct repository *r)
2484+
{
2485+
/* Run only once. */
2486+
static int virtual_filesystem_result = -1;
2487+
extern char *core_virtualfilesystem;
2488+
extern int core_apply_sparse_checkout;
2489+
if (virtual_filesystem_result >= 0)
2490+
return virtual_filesystem_result;
2491+
2492+
if (repo_config_get_pathname(r, "core.virtualfilesystem", &core_virtualfilesystem))
2493+
core_virtualfilesystem = xstrdup_or_null(getenv("GIT_VIRTUALFILESYSTEM_TEST"));
2494+
2495+
if (core_virtualfilesystem && !*core_virtualfilesystem)
2496+
FREE_AND_NULL(core_virtualfilesystem);
2497+
2498+
/* virtual file system relies on the sparse checkout logic so force it on */
2499+
if (core_virtualfilesystem) {
2500+
core_apply_sparse_checkout = 1;
2501+
virtual_filesystem_result = 1;
2502+
return 1;
2503+
}
2504+
2505+
virtual_filesystem_result = 0;
2506+
return 0;
2507+
}
2508+
24832509
int repo_config_get_index_threads(struct repository *r, int *dest)
24842510
{
24852511
int is_bool, val;

‎config.h‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,8 @@ int repo_config_get_index_threads(struct repository *r, int *dest);
685685
int repo_config_get_split_index(struct repository *r);
686686
int repo_config_get_max_percent_split_change(struct repository *r);
687687

688+
int repo_config_get_virtualfilesystem(struct repository *r);
689+
688690
/* This dies if the configured or default date is in the future */
689691
int repo_config_get_expiry(struct repository *r, const char *key, char **output);
690692

‎dir.c‎

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include "git-compat-util.h"
1313
#include "abspath.h"
14+
#include "virtualfilesystem.h"
1415
#include "config.h"
1516
#include "convert.h"
1617
#include "dir.h"
@@ -1533,6 +1534,19 @@ enum pattern_match_result path_matches_pattern_list(
15331534
int result = NOT_MATCHED;
15341535
size_t slash_pos;
15351536

1537+
if (core_virtualfilesystem) {
1538+
/*
1539+
* The virtual file system data is used to prevent git from traversing
1540+
* any part of the tree that is not in the virtual file system. Return
1541+
* 1 to exclude the entry if it is not found in the virtual file system,
1542+
* else fall through to the regular excludes logic as it may further exclude.
1543+
*/
1544+
if (*dtype == DT_UNKNOWN)
1545+
*dtype = resolve_dtype(DT_UNKNOWN, istate, pathname, pathlen);
1546+
if (is_excluded_from_virtualfilesystem(pathname, pathlen, *dtype) > 0)
1547+
return 1;
1548+
}
1549+
15361550
if (!pl->use_cone_patterns) {
15371551
pattern = last_matching_pattern_from_list(pathname, pathlen, basename,
15381552
dtype, pl, istate);
@@ -1622,6 +1636,13 @@ static int path_in_sparse_checkout_1(const char *path,
16221636
enum pattern_match_result match = UNDECIDED;
16231637
const char *end, *slash;
16241638

1639+
/*
1640+
* When using a virtual filesystem, there aren't really patterns
1641+
* to follow, but be extra careful to skip this check.
1642+
*/
1643+
if (core_virtualfilesystem)
1644+
return 1;
1645+
16251646
/*
16261647
* We default to accepting a path if the path is empty, there are no
16271648
* patterns, or the patterns are of the wrong type.
@@ -1877,8 +1898,22 @@ struct path_pattern *last_matching_pattern(struct dir_struct *dir,
18771898
int is_excluded(struct dir_struct *dir, struct index_state *istate,
18781899
const char *pathname, int *dtype_p)
18791900
{
1880-
struct path_pattern *pattern =
1881-
last_matching_pattern(dir, istate, pathname, dtype_p);
1901+
struct path_pattern *pattern;
1902+
1903+
if (core_virtualfilesystem) {
1904+
/*
1905+
* The virtual file system data is used to prevent git from traversing
1906+
* any part of the tree that is not in the virtual file system. Return
1907+
* 1 to exclude the entry if it is not found in the virtual file system,
1908+
* else fall through to the regular excludes logic as it may further exclude.
1909+
*/
1910+
if (*dtype_p == DT_UNKNOWN)
1911+
*dtype_p = resolve_dtype(DT_UNKNOWN, istate, pathname, strlen(pathname));
1912+
if (is_excluded_from_virtualfilesystem(pathname, strlen(pathname), *dtype_p) > 0)
1913+
return 1;
1914+
}
1915+
1916+
pattern = last_matching_pattern(dir, istate, pathname, dtype_p);
18821917
if (pattern)
18831918
return pattern->flags & PATTERN_FLAG_NEGATIVE ? 0 : 1;
18841919
return 0;
@@ -2496,6 +2531,8 @@ static enum path_treatment treat_path(struct dir_struct *dir,
24962531
ignore_case);
24972532
if (dtype != DT_DIR && has_path_in_index)
24982533
return path_none;
2534+
if (is_excluded_from_virtualfilesystem(path->buf, path->len, dtype) > 0)
2535+
return path_excluded;
24992536

25002537
/*
25012538
* When we are looking at a directory P in the working tree,
@@ -2700,6 +2737,8 @@ static void add_path_to_appropriate_result_list(struct dir_struct *dir,
27002737
/* add the path to the appropriate result list */
27012738
switch (state) {
27022739
case path_excluded:
2740+
if (is_excluded_from_virtualfilesystem(path->buf, path->len, DT_DIR) > 0)
2741+
break;
27032742
if (dir->flags & DIR_SHOW_IGNORED)
27042743
dir_add_name(dir, istate, path->buf, path->len);
27052744
else if ((dir->flags & DIR_SHOW_IGNORED_TOO) ||

‎environment.c‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ int grafts_keep_true_parents;
7878
int core_apply_sparse_checkout;
7979
int core_sparse_checkout_cone;
8080
int sparse_expect_files_outside_of_patterns;
81+
char *core_virtualfilesystem;
8182
int precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */
8283
unsigned long pack_size_limit_cfg;
8384
int core_virtualize_objects;
@@ -552,7 +553,11 @@ int git_default_core_config(const char *var, const char *value,
552553
}
553554

554555
if (!strcmp(var, "core.sparsecheckout")) {
555-
core_apply_sparse_checkout = git_config_bool(var, value);
556+
/* virtual file system relies on the sparse checkout logic so force it on */
557+
if (core_virtualfilesystem)
558+
core_apply_sparse_checkout = 1;
559+
else
560+
core_apply_sparse_checkout = git_config_bool(var, value);
556561
return 0;
557562
}
558563

‎environment.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ extern int pack_compression_level;
160160
extern unsigned long pack_size_limit_cfg;
161161
extern int max_allowed_tree_depth;
162162

163+
extern char *core_virtualfilesystem;
163164
extern int precomposed_unicode;
164165
extern int protect_hfs;
165166
extern int protect_ntfs;

‎meson.build‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,7 @@ libgit_sources = [
532532
'utf8.c',
533533
'version.c',
534534
'versioncmp.c',
535+
'virtualfilesystem.c',
535536
'walker.c',
536537
'wildmatch.c',
537538
'worktree.c',

‎read-cache.c‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#define DISABLE_SIGN_COMPARE_WARNINGS
99

1010
#include "git-compat-util.h"
11+
#include "virtualfilesystem.h"
1112
#include "config.h"
1213
#include "date.h"
1314
#include "diff.h"
@@ -1949,6 +1950,7 @@ static void post_read_index_from(struct index_state *istate)
19491950
tweak_untracked_cache(istate);
19501951
tweak_split_index(istate);
19511952
tweak_fsmonitor(istate);
1953+
apply_virtualfilesystem(istate);
19521954
}
19531955

19541956
static size_t estimate_cache_size_from_compressed(unsigned int entries)

0 commit comments

Comments
 (0)