Skip to content

Commit d29907e

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 <[email protected]>
1 parent 180746b commit d29907e

16 files changed

+823
-8
lines changed

Documentation/config/core.txt

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.txt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -751,6 +751,26 @@ and "0" meaning they were not.
751751
Only one parameter should be set to "1" when the hook runs. The hook
752752
running passing "1", "1" should not be possible.
753753

754+
virtualFilesystem
755+
~~~~~~~~~~~~~~~~~~
756+
757+
"Virtual File System" allows populating the working directory sparsely.
758+
The projection data is typically automatically generated by an external
759+
process. Git will limit what files it checks for changes as well as which
760+
directories are checked for untracked files based on the path names given.
761+
Git will also only update those files listed in the projection.
762+
763+
The hook is invoked when the configuration option core.virtualFilesystem
764+
is set. It takes one argument, a version (currently 1).
765+
766+
The hook should output to stdout the list of all files in the working
767+
directory that git should track. The paths are relative to the root
768+
of the working directory and are separated by a single NUL. Full paths
769+
('dir1/a.txt') as well as directories are supported (ie 'dir1/').
770+
771+
The exit status determines whether git will use the data from the
772+
hook. On error, git will abort the command with an error message.
773+
754774
SEE ALSO
755775
--------
756776
linkgit:git-hook[1]

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1207,6 +1207,7 @@ LIB_OBJS += utf8.o
12071207
LIB_OBJS += varint.o
12081208
LIB_OBJS += version.o
12091209
LIB_OBJS += versioncmp.o
1210+
LIB_OBJS += virtualfilesystem.o
12101211
LIB_OBJS += walker.o
12111212
LIB_OBJS += wildmatch.o
12121213
LIB_OBJS += worktree.o

config.c

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1659,7 +1659,11 @@ int git_default_core_config(const char *var, const char *value,
16591659
}
16601660

16611661
if (!strcmp(var, "core.sparsecheckout")) {
1662-
core_apply_sparse_checkout = git_config_bool(var, value);
1662+
/* virtual file system relies on the sparse checkout logic so force it on */
1663+
if (core_virtualfilesystem)
1664+
core_apply_sparse_checkout = 1;
1665+
else
1666+
core_apply_sparse_checkout = git_config_bool(var, value);
16631667
return 0;
16641668
}
16651669

@@ -2813,6 +2817,30 @@ int git_config_get_max_percent_split_change(void)
28132817
return -1; /* default value */
28142818
}
28152819

2820+
int git_config_get_virtualfilesystem(void)
2821+
{
2822+
/* Run only once. */
2823+
static int virtual_filesystem_result = -1;
2824+
if (virtual_filesystem_result >= 0)
2825+
return virtual_filesystem_result;
2826+
2827+
if (git_config_get_pathname("core.virtualfilesystem", &core_virtualfilesystem))
2828+
core_virtualfilesystem = getenv("GIT_VIRTUALFILESYSTEM_TEST");
2829+
2830+
if (core_virtualfilesystem && !*core_virtualfilesystem)
2831+
core_virtualfilesystem = NULL;
2832+
2833+
/* virtual file system relies on the sparse checkout logic so force it on */
2834+
if (core_virtualfilesystem) {
2835+
core_apply_sparse_checkout = 1;
2836+
virtual_filesystem_result = 1;
2837+
return 1;
2838+
}
2839+
2840+
virtual_filesystem_result = 0;
2841+
return 0;
2842+
}
2843+
28162844
int git_config_get_index_threads(int *dest)
28172845
{
28182846
int is_bool, val;

config.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -694,6 +694,7 @@ int git_config_get_pathname(const char *key, const char **dest);
694694
int git_config_get_index_threads(int *dest);
695695
int git_config_get_split_index(void);
696696
int git_config_get_max_percent_split_change(void);
697+
int git_config_get_virtualfilesystem(void);
697698

698699
/* This dies if the configured or default date is in the future */
699700
int git_config_get_expiry(const char *key, const char **output);

dir.c

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
*/
88
#include "git-compat-util.h"
99
#include "abspath.h"
10+
#include "virtualfilesystem.h"
1011
#include "config.h"
1112
#include "convert.h"
1213
#include "dir.h"
@@ -1443,6 +1444,19 @@ enum pattern_match_result path_matches_pattern_list(
14431444
int result = NOT_MATCHED;
14441445
size_t slash_pos;
14451446

1447+
if (core_virtualfilesystem) {
1448+
/*
1449+
* The virtual file system data is used to prevent git from traversing
1450+
* any part of the tree that is not in the virtual file system. Return
1451+
* 1 to exclude the entry if it is not found in the virtual file system,
1452+
* else fall through to the regular excludes logic as it may further exclude.
1453+
*/
1454+
if (*dtype == DT_UNKNOWN)
1455+
*dtype = resolve_dtype(DT_UNKNOWN, istate, pathname, pathlen);
1456+
if (is_excluded_from_virtualfilesystem(pathname, pathlen, *dtype) > 0)
1457+
return 1;
1458+
}
1459+
14461460
if (!pl->use_cone_patterns) {
14471461
pattern = last_matching_pattern_from_list(pathname, pathlen, basename,
14481462
dtype, pl, istate);
@@ -1787,8 +1801,22 @@ struct path_pattern *last_matching_pattern(struct dir_struct *dir,
17871801
int is_excluded(struct dir_struct *dir, struct index_state *istate,
17881802
const char *pathname, int *dtype_p)
17891803
{
1790-
struct path_pattern *pattern =
1791-
last_matching_pattern(dir, istate, pathname, dtype_p);
1804+
struct path_pattern *pattern;
1805+
1806+
if (core_virtualfilesystem) {
1807+
/*
1808+
* The virtual file system data is used to prevent git from traversing
1809+
* any part of the tree that is not in the virtual file system. Return
1810+
* 1 to exclude the entry if it is not found in the virtual file system,
1811+
* else fall through to the regular excludes logic as it may further exclude.
1812+
*/
1813+
if (*dtype_p == DT_UNKNOWN)
1814+
*dtype_p = resolve_dtype(DT_UNKNOWN, istate, pathname, strlen(pathname));
1815+
if (is_excluded_from_virtualfilesystem(pathname, strlen(pathname), *dtype_p) > 0)
1816+
return 1;
1817+
}
1818+
1819+
pattern = last_matching_pattern(dir, istate, pathname, dtype_p);
17921820
if (pattern)
17931821
return pattern->flags & PATTERN_FLAG_NEGATIVE ? 0 : 1;
17941822
return 0;
@@ -2408,6 +2436,8 @@ static enum path_treatment treat_path(struct dir_struct *dir,
24082436
ignore_case);
24092437
if (dtype != DT_DIR && has_path_in_index)
24102438
return path_none;
2439+
if (is_excluded_from_virtualfilesystem(path->buf, path->len, dtype) > 0)
2440+
return path_excluded;
24112441

24122442
/*
24132443
* When we are looking at a directory P in the working tree,
@@ -2612,6 +2642,8 @@ static void add_path_to_appropriate_result_list(struct dir_struct *dir,
26122642
/* add the path to the appropriate result list */
26132643
switch (state) {
26142644
case path_excluded:
2645+
if (is_excluded_from_virtualfilesystem(path->buf, path->len, DT_DIR) > 0)
2646+
break;
26152647
if (dir->flags & DIR_SHOW_IGNORED)
26162648
dir_add_name(dir, istate, path->buf, path->len);
26172649
else if ((dir->flags & DIR_SHOW_IGNORED_TOO) ||

environment.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ int core_apply_sparse_checkout;
7878
int core_sparse_checkout_cone;
7979
int sparse_expect_files_outside_of_patterns;
8080
int core_gvfs;
81+
const char *core_virtualfilesystem;
8182
int merge_log_config = -1;
8283
int precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */
8384
unsigned long pack_size_limit_cfg;

environment.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ int get_shared_repository(void);
148148
void reset_shared_repository(void);
149149

150150
extern int core_preload_index;
151+
extern const char *core_virtualfilesystem;
151152
extern int core_gvfs;
152153
extern int precomposed_unicode;
153154
extern int protect_hfs;

read-cache.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*/
66
#include "git-compat-util.h"
77
#include "bulk-checkin.h"
8+
#include "virtualfilesystem.h"
89
#include "config.h"
910
#include "date.h"
1011
#include "diff.h"
@@ -1973,6 +1974,7 @@ static void post_read_index_from(struct index_state *istate)
19731974
tweak_untracked_cache(istate);
19741975
tweak_split_index(istate);
19751976
tweak_fsmonitor(istate);
1977+
apply_virtualfilesystem(istate);
19761978
}
19771979

19781980
static size_t estimate_cache_size_from_compressed(unsigned int entries)

sparse-index.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ static int add_path_to_index(const struct object_id *oid,
242242
size_t len = base->len;
243243

244244
if (S_ISDIR(mode)) {
245-
int dtype;
245+
int dtype = DT_DIR;
246246
size_t baselen = base->len;
247247
if (!ctx->pl)
248248
return READ_TREE_RECURSIVE;
@@ -360,7 +360,7 @@ void expand_index(struct index_state *istate, struct pattern_list *pl)
360360
struct cache_entry *ce = istate->cache[i];
361361
struct tree *tree;
362362
struct pathspec ps;
363-
int dtype;
363+
int dtype = DT_UNKNOWN;
364364

365365
if (!S_ISSPARSEDIR(ce->ce_mode)) {
366366
set_index_entry(full, full->cache_nr++, ce);
@@ -497,6 +497,7 @@ void clear_skip_worktree_from_present_files(struct index_state *istate)
497497
int restarted = 0;
498498

499499
if (!core_apply_sparse_checkout ||
500+
core_virtualfilesystem ||
500501
sparse_expect_files_outside_of_patterns)
501502
return;
502503

0 commit comments

Comments
 (0)