Skip to content

Commit bde0f25

Browse files
committed
Merge virtualfilesystem hook
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. The hook was first contributed in private, but was extended via the following pull requests: #15 #27 #33 msysgit#70 Signed-off-by: Ben Peart <[email protected]> Signed-off-by: Derrick Stolee <[email protected]>
2 parents 92b7c0d + 1c7dcc9 commit bde0f25

18 files changed

+887
-7
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
@@ -710,6 +710,26 @@ and "0" meaning they were not.
710710
Only one parameter should be set to "1" when the hook runs. The hook
711711
running passing "1", "1" should not be possible.
712712

713+
virtualFilesystem
714+
~~~~~~~~~~~~~~~~~~
715+
716+
"Virtual File System" allows populating the working directory sparsely.
717+
The projection data is typically automatically generated by an external
718+
process. Git will limit what files it checks for changes as well as which
719+
directories are checked for untracked files based on the path names given.
720+
Git will also only update those files listed in the projection.
721+
722+
The hook is invoked when the configuration option core.virtualFilesystem
723+
is set. It takes one argument, a version (currently 1).
724+
725+
The hook should output to stdout the list of all files in the working
726+
directory that git should track. The paths are relative to the root
727+
of the working directory and are separated by a single NUL. Full paths
728+
('dir1/a.txt') as well as directories are supported (ie 'dir1/').
729+
730+
The exit status determines whether git will use the data from the
731+
hook. On error, git will abort the command with an error message.
732+
713733
SEE ALSO
714734
--------
715735
linkgit:git-hook[1]

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1190,6 +1190,7 @@ LIB_OBJS += utf8.o
11901190
LIB_OBJS += varint.o
11911191
LIB_OBJS += version.o
11921192
LIB_OBJS += versioncmp.o
1193+
LIB_OBJS += virtualfilesystem.o
11931194
LIB_OBJS += walker.o
11941195
LIB_OBJS += wildmatch.o
11951196
LIB_OBJS += worktree.o

cache.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1054,6 +1054,7 @@ enum fsync_method {
10541054

10551055
extern enum fsync_method fsync_method;
10561056
extern int core_preload_index;
1057+
extern const char *core_virtualfilesystem;
10571058
extern int core_gvfs;
10581059
extern int precomposed_unicode;
10591060
extern int protect_hfs;

config.c

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1750,7 +1750,11 @@ int git_default_core_config(const char *var, const char *value, void *cb)
17501750
}
17511751

17521752
if (!strcmp(var, "core.sparsecheckout")) {
1753-
core_apply_sparse_checkout = git_config_bool(var, value);
1753+
/* virtual file system relies on the sparse checkout logic so force it on */
1754+
if (core_virtualfilesystem)
1755+
core_apply_sparse_checkout = 1;
1756+
else
1757+
core_apply_sparse_checkout = git_config_bool(var, value);
17541758
return 0;
17551759
}
17561760

@@ -2800,6 +2804,44 @@ int git_config_get_max_percent_split_change(void)
28002804
return -1; /* default value */
28012805
}
28022806

2807+
int git_config_get_virtualfilesystem(void)
2808+
{
2809+
/* Run only once. */
2810+
static int virtual_filesystem_result = -1;
2811+
if (virtual_filesystem_result >= 0)
2812+
return virtual_filesystem_result;
2813+
2814+
if (git_config_get_pathname("core.virtualfilesystem", &core_virtualfilesystem))
2815+
core_virtualfilesystem = getenv("GIT_VIRTUALFILESYSTEM_TEST");
2816+
2817+
if (core_virtualfilesystem && !*core_virtualfilesystem)
2818+
core_virtualfilesystem = NULL;
2819+
2820+
if (core_virtualfilesystem) {
2821+
/*
2822+
* Some git commands spawn helpers and redirect the index to a different
2823+
* location. These include "difftool -d" and the sequencer
2824+
* (i.e. `git rebase -i`, `git cherry-pick` and `git revert`) and others.
2825+
* In those instances we don't want to update their temporary index with
2826+
* our virtualization data.
2827+
*/
2828+
char *default_index_file = xstrfmt("%s/%s", the_repository->gitdir, "index");
2829+
int should_run_hook = !strcmp(default_index_file, the_repository->index_file);
2830+
2831+
free(default_index_file);
2832+
if (should_run_hook) {
2833+
/* virtual file system relies on the sparse checkout logic so force it on */
2834+
core_apply_sparse_checkout = 1;
2835+
virtual_filesystem_result = 1;
2836+
return 1;
2837+
}
2838+
core_virtualfilesystem = NULL;
2839+
}
2840+
2841+
virtual_filesystem_result = 0;
2842+
return 0;
2843+
}
2844+
28032845
int git_config_get_index_threads(int *dest)
28042846
{
28052847
int is_bool, val;

config.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,7 @@ int git_config_get_pathname(const char *key, const char **dest);
606606
int git_config_get_index_threads(int *dest);
607607
int git_config_get_split_index(void);
608608
int git_config_get_max_percent_split_change(void);
609+
int git_config_get_virtualfilesystem(void);
609610

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

dir.c

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
* Junio Hamano, 2005-2006
77
*/
88
#include "cache.h"
9+
#include "virtualfilesystem.h"
910
#include "config.h"
1011
#include "dir.h"
1112
#include "object-store.h"
@@ -1419,6 +1420,17 @@ enum pattern_match_result path_matches_pattern_list(
14191420
int result = NOT_MATCHED;
14201421
size_t slash_pos;
14211422

1423+
/*
1424+
* The virtual file system data is used to prevent git from traversing
1425+
* any part of the tree that is not in the virtual file system. Return
1426+
* 1 to exclude the entry if it is not found in the virtual file system,
1427+
* else fall through to the regular excludes logic as it may further exclude.
1428+
*/
1429+
if (*dtype == DT_UNKNOWN)
1430+
*dtype = resolve_dtype(DT_UNKNOWN, istate, pathname, pathlen);
1431+
if (is_excluded_from_virtualfilesystem(pathname, pathlen, *dtype) > 0)
1432+
return 1;
1433+
14221434
if (!pl->use_cone_patterns) {
14231435
pattern = last_matching_pattern_from_list(pathname, pathlen, basename,
14241436
dtype, pl, istate);
@@ -1762,8 +1774,20 @@ struct path_pattern *last_matching_pattern(struct dir_struct *dir,
17621774
int is_excluded(struct dir_struct *dir, struct index_state *istate,
17631775
const char *pathname, int *dtype_p)
17641776
{
1765-
struct path_pattern *pattern =
1766-
last_matching_pattern(dir, istate, pathname, dtype_p);
1777+
struct path_pattern *pattern;
1778+
1779+
/*
1780+
* The virtual file system data is used to prevent git from traversing
1781+
* any part of the tree that is not in the virtual file system. Return
1782+
* 1 to exclude the entry if it is not found in the virtual file system,
1783+
* else fall through to the regular excludes logic as it may further exclude.
1784+
*/
1785+
if (*dtype_p == DT_UNKNOWN)
1786+
*dtype_p = resolve_dtype(DT_UNKNOWN, istate, pathname, strlen(pathname));
1787+
if (is_excluded_from_virtualfilesystem(pathname, strlen(pathname), *dtype_p) > 0)
1788+
return 1;
1789+
1790+
pattern = last_matching_pattern(dir, istate, pathname, dtype_p);
17671791
if (pattern)
17681792
return pattern->flags & PATTERN_FLAG_NEGATIVE ? 0 : 1;
17691793
return 0;
@@ -2349,6 +2373,8 @@ static enum path_treatment treat_path(struct dir_struct *dir,
23492373
ignore_case);
23502374
if (dtype != DT_DIR && has_path_in_index)
23512375
return path_none;
2376+
if (is_excluded_from_virtualfilesystem(path->buf, path->len, dtype) > 0)
2377+
return path_excluded;
23522378

23532379
/*
23542380
* When we are looking at a directory P in the working tree,
@@ -2553,6 +2579,8 @@ static void add_path_to_appropriate_result_list(struct dir_struct *dir,
25532579
/* add the path to the appropriate result list */
25542580
switch (state) {
25552581
case path_excluded:
2582+
if (is_excluded_from_virtualfilesystem(path->buf, path->len, DT_DIR) > 0)
2583+
break;
25562584
if (dir->flags & DIR_SHOW_IGNORED)
25572585
dir_add_name(dir, istate, path->buf, path->len);
25582586
else if ((dir->flags & DIR_SHOW_IGNORED_TOO) ||

environment.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ int core_apply_sparse_checkout;
7373
int core_sparse_checkout_cone;
7474
int sparse_expect_files_outside_of_patterns;
7575
int core_gvfs;
76+
const char *core_virtualfilesystem;
7677
int merge_log_config = -1;
7778
int precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */
7879
unsigned long pack_size_limit_cfg;

hook.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ int run_hooks_opt(const char *hook_name, struct run_hooks_opt *options)
178178
.hook_name = hook_name,
179179
.options = options,
180180
};
181-
const char *const hook_path = find_hook(hook_name);
181+
const char *hook_path = find_hook(hook_name);
182182
int ret = 0;
183183
const struct run_process_parallel_opts opts = {
184184
.tr2_category = "hook",
@@ -194,6 +194,18 @@ int run_hooks_opt(const char *hook_name, struct run_hooks_opt *options)
194194
.data = &cb_data,
195195
};
196196

197+
/*
198+
* Backwards compatibility hack in VFS for Git: when originally
199+
* introduced (and used!), it was called `post-indexchanged`, but this
200+
* name was changed during the review on the Git mailing list.
201+
*
202+
* Therefore, when the `post-index-change` hook is not found, let's
203+
* look for a hook with the old name (which would be found in case of
204+
* already-existing checkouts).
205+
*/
206+
if (!hook_path && !strcmp(hook_name, "post-index-change"))
207+
hook_path = find_hook("post-indexchanged");
208+
197209
if (!options)
198210
BUG("a struct run_hooks_opt must be provided to run_hooks");
199211

read-cache.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* Copyright (C) Linus Torvalds, 2005
55
*/
66
#include "cache.h"
7+
#include "virtualfilesystem.h"
78
#include "config.h"
89
#include "diff.h"
910
#include "diffcore.h"
@@ -2078,6 +2079,7 @@ static void post_read_index_from(struct index_state *istate)
20782079
tweak_untracked_cache(istate);
20792080
tweak_split_index(istate);
20802081
tweak_fsmonitor(istate);
2082+
apply_virtualfilesystem(istate);
20812083
}
20822084

20832085
static size_t estimate_cache_size_from_compressed(unsigned int entries)

sparse-index.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,7 @@ void clear_skip_worktree_from_present_files(struct index_state *istate)
493493
int restarted = 0;
494494

495495
if (!core_apply_sparse_checkout ||
496+
core_virtualfilesystem ||
496497
sparse_expect_files_outside_of_patterns)
497498
return;
498499

t/t1090-sparse-checkout-scope.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,9 @@ test_expect_success 'in partial clone, sparse checkout only fetches needed blobs
107107
'
108108

109109
test_expect_success 'checkout does not delete items outside the sparse checkout file' '
110-
# The "sparse.expectfilesoutsideofpatterns" config will prevent the
110+
# The "core.virtualfilesystem" config will prevent the
111111
# SKIP_WORKTREE flag from being dropped on files present on-disk.
112-
test_config sparse.expectfilesoutsideofpatterns true &&
112+
test_config core.virtualfilesystem true &&
113113
114114
test_config core.gvfs 8 &&
115115
git checkout -b outside &&

0 commit comments

Comments
 (0)