Skip to content

Commit 5f289aa

Browse files
Tyrie VellaCopilot
andcommitted
worktree: conditionally allow worktree on VFS-enabled repos
Add GVFS_SUPPORTS_WORKTREES flag (1<<8) to core.gvfs bitmask. When set, allow git worktree commands to run on VFS-enabled repos instead of blocking them with BLOCK_ON_VFS_ENABLED. Force --no-checkout during worktree add when VFS is active so ProjFS can be mounted before files are projected. Support skip-clean-check marker file in worktree gitdir: if .git/worktrees/<name>/skip-clean-check exists, skip the cleanliness check during worktree remove. This allows VFSForGit's pre-command hook to unmount ProjFS after its own status check, then let git proceed without re-checking (which would fail without the virtual filesystem). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent bea18f5 commit 5f289aa

File tree

4 files changed

+69
-3
lines changed

4 files changed

+69
-3
lines changed

builtin/worktree.c

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -838,6 +838,14 @@ static int add(int ac, const char **av, const char *prefix,
838838
if (ac < 1 || ac > 2)
839839
usage_with_options(git_worktree_add_usage, options);
840840

841+
/*
842+
* When the virtual file system is active, skip checkout during
843+
* worktree creation. The VFS layer will handle the checkout
844+
* after the worktree structure is set up.
845+
*/
846+
if (gvfs_config_is_set(the_repository, GVFS_USE_VIRTUAL_FILESYSTEM))
847+
opts.checkout = 0;
848+
841849
path = prefix_filename(prefix, av[0]);
842850
branch = ac < 2 ? "HEAD" : av[1];
843851
used_new_branch_options = new_branch || new_branch_force;
@@ -1358,6 +1366,21 @@ static int delete_git_work_tree(struct worktree *wt)
13581366
return ret;
13591367
}
13601368

1369+
/*
1370+
* Check if a pre-command hook has already verified worktree cleanliness
1371+
* and written a marker file to skip git's own check. VFSForGit uses this
1372+
* to unmount ProjFS after its own status check; without it, git's status
1373+
* call would fail because the virtual filesystem is no longer available.
1374+
*/
1375+
static int should_skip_clean_check(struct worktree *wt)
1376+
{
1377+
char *path = repo_common_path(the_repository,
1378+
"worktrees/%s/skip-clean-check", wt->id);
1379+
int skip = file_exists(path);
1380+
free(path);
1381+
return skip;
1382+
}
1383+
13611384
static int remove_worktree(int ac, const char **av, const char *prefix,
13621385
struct repository *repo UNUSED)
13631386
{
@@ -1397,7 +1420,7 @@ static int remove_worktree(int ac, const char **av, const char *prefix,
13971420
strbuf_release(&errmsg);
13981421

13991422
if (file_exists(wt->path)) {
1400-
if (!force)
1423+
if (!force && !(core_virtualfilesystem && should_skip_clean_check(wt)))
14011424
check_clean_worktree(wt, av[0]);
14021425

14031426
ret |= delete_git_work_tree(wt);
@@ -1469,6 +1492,14 @@ int cmd_worktree(int ac,
14691492

14701493
ac = parse_options(ac, av, prefix, options, git_worktree_usage, 0);
14711494

1495+
/*
1496+
* Block worktree commands when VFS is active unless the VFS layer
1497+
* has signaled worktree support via GVFS_SUPPORTS_WORKTREES.
1498+
*/
1499+
if (gvfs_config_is_set(the_repository, GVFS_USE_VIRTUAL_FILESYSTEM) &&
1500+
!gvfs_config_is_set(the_repository, GVFS_SUPPORTS_WORKTREES))
1501+
die("'git worktree' is not supported when using the virtual file system");
1502+
14721503
prepare_repo_settings(the_repository);
14731504
the_repository->settings.command_requires_full_index = 0;
14741505

git.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -761,7 +761,7 @@ static struct cmd_struct commands[] = {
761761
#ifndef WITH_BREAKING_CHANGES
762762
{ "whatchanged", cmd_whatchanged, RUN_SETUP | DEPRECATED },
763763
#endif
764-
{ "worktree", cmd_worktree, RUN_SETUP | BLOCK_ON_VFS_ENABLED },
764+
{ "worktree", cmd_worktree, RUN_SETUP },
765765
{ "write-tree", cmd_write_tree, RUN_SETUP },
766766
};
767767

gvfs.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,17 @@ struct repository;
2727
#define GVFS_USE_VIRTUAL_FILESYSTEM (1 << 3)
2828

2929
#define GVFS_FETCH_SKIP_REACHABILITY_AND_UPLOADPACK (1 << 4)
30+
/* Bit 5 was GVFS_LOWER_DEFAULT_SLOP, removed in 2018 (unused). */
3031
#define GVFS_BLOCK_FILTERS_AND_EOL_CONVERSIONS (1 << 6)
3132
#define GVFS_PREFETCH_DURING_FETCH (1 << 7)
3233

34+
/*
35+
* When set, this flag indicates that the VFS layer supports
36+
* git worktrees. This allows `git worktree add/remove` to
37+
* operate on VFS-enabled repositories.
38+
*/
39+
#define GVFS_SUPPORTS_WORKTREES (1 << 8)
40+
3341
#define GVFS_ANY_MASK 0xFFFFFFFF
3442

3543
int gvfs_config_is_set(struct repository *r, int mask);

t/t0402-block-command-on-gvfs.sh

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,34 @@ not_with_gvfs update-index --index-version 2
2727
not_with_gvfs update-index --skip-worktree
2828
not_with_gvfs update-index --no-skip-worktree
2929
not_with_gvfs update-index --split-index
30-
not_with_gvfs worktree list
30+
31+
# worktree is conditionally allowed: blocked when VFS enabled without
32+
# GVFS_SUPPORTS_WORKTREES.
33+
test_expect_success 'worktree blocked with VFS but without SUPPORTS_WORKTREES' '
34+
test_config core.gvfs $((0xffff & ~(1<<8))) && # all bits except GVFS_SUPPORTS_WORKTREES
35+
test_must_fail git worktree list 2>err &&
36+
test_grep "not supported when using the virtual file system" err
37+
'
38+
39+
test_expect_success 'worktree operations work when SUPPORTS_WORKTREES is set' '
40+
test_commit initial &&
41+
42+
# Use core.gvfs=true which sets all bits including SUPPORTS_WORKTREES.
43+
test_config core.gvfs true &&
44+
45+
# add: succeeds, forces --no-checkout (no initial.t on disk)
46+
git worktree add ../vfs-wt &&
47+
test_path_exists ../vfs-wt/.git &&
48+
! test_path_exists ../vfs-wt/initial.t &&
49+
50+
# list: shows the worktree
51+
git worktree list >out &&
52+
grep "vfs-wt" out &&
53+
54+
# remove: cleans up
55+
git worktree remove --force ../vfs-wt &&
56+
! test_path_exists ../vfs-wt
57+
'
3158

3259
test_expect_success 'test gc --auto succeeds when disabled via config' '
3360
test_config core.gvfs true &&

0 commit comments

Comments
 (0)