diff --git a/builtin/checkout.c b/builtin/checkout.c index 5109573aed32e9..750076eb17c045 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -652,6 +652,15 @@ static int checkout_paths(const struct checkout_opts *opts, checkout_index = opts->checkout_index; if (checkout_index) { + if (core_virtualfilesystem) { + /* Some scenarios that checkout the index may update skipworktree bits, + * such as `restore --staged` after `cherry-pick -n` or `reset --soft`, + * so this flag should be set to ensure the correct virtual filesystem + * event is sent. + */ + the_repository->index->updated_skipworktree = 1; + } + if (write_locked_index(the_repository->index, &lock_file, COMMIT_LOCK)) die(_("unable to write new index file")); } else { diff --git a/read-cache-ll.h b/read-cache-ll.h index 84092540a7830b..bcdeca9dacdf66 100644 --- a/read-cache-ll.h +++ b/read-cache-ll.h @@ -176,7 +176,8 @@ struct index_state { drop_cache_tree : 1, updated_workdir : 1, updated_skipworktree : 1, - fsmonitor_has_run_once : 1; + fsmonitor_has_run_once : 1, + vfs_check_added_entries_for_clear_skip_worktree : 1; enum sparse_index_mode sparse_index; struct hashmap name_hash; struct hashmap dir_hash; diff --git a/sequencer.c b/sequencer.c index 05a77977199e3d..36a124c502222e 100644 --- a/sequencer.c +++ b/sequencer.c @@ -787,13 +787,22 @@ static int do_recursive_merge(struct repository *r, * to be replace with the tree the index matched before we * started doing any picks. */ + if (opts->no_commit && core_virtualfilesystem) { + /* When using the virtual file system, staged new files + * should clear SKIP_WORKTREE during this step to ensure the new files + * are properly added to the working tree as well as index - otherwise + * sparse-checkout functionality will prevent them from being added. + */ + o.repo->index->vfs_check_added_entries_for_clear_skip_worktree = 1; + } merge_switch_to_result(&o, head_tree, &result, 1, show_output); + o.repo->index->vfs_check_added_entries_for_clear_skip_worktree = 0; + clean = result.clean; if (clean < 0) { rollback_lock_file(&index_lock); return clean; } - if (write_locked_index(r->index, &index_lock, COMMIT_LOCK | SKIP_IF_UNCHANGED)) /* diff --git a/unpack-trees.c b/unpack-trees.c index 4d897829419a3d..76316d54e18a5b 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -2004,6 +2004,8 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options is_sparse_index_allowed(&o->internal.result, 0)) o->internal.result.sparse_index = 1; + o->internal.result.vfs_check_added_entries_for_clear_skip_worktree = + o->src_index->vfs_check_added_entries_for_clear_skip_worktree; /* * Sparse checkout loop #1: set NEW_SKIP_WORKTREE on existing entries */ diff --git a/virtualfilesystem.c b/virtualfilesystem.c index 269af2de1d969d..7617e87e360d17 100644 --- a/virtualfilesystem.c +++ b/virtualfilesystem.c @@ -337,6 +337,32 @@ static void clear_ce_flags_virtualfilesystem_1(struct index_state *istate, int s entry += len + 1; } } + + /* + * If vfs_check_added_entries_for_clear_skip_worktree is set and we are checking + * for added entries, clear the mask from all added entries even if they + * are not in the virtual filesystem. + * This is used in scenarios like cherry-pick -n, where the added entries + * are not added to the virtual file system but still need to be checked out + * in the working tree. + */ + if ((select_mask & CE_ADDED) + && (clear_mask & CE_SKIP_WORKTREE) + && istate->vfs_check_added_entries_for_clear_skip_worktree) { + for (i = 0; i < istate->cache_nr; i++) { + struct cache_entry *ce = istate->cache[i]; + if (!select_mask || (ce->ce_flags & select_mask)) { + if (ce->ce_flags & clear_mask) { + ce->ce_flags &= ~clear_mask; + /* + * We also signal to VFS that there are updates to skipworktree + * that it needs to react to. + */ + istate->updated_skipworktree = 1; + } + } + } + } } /*