From 8e1957dae51172ed71f84624340d1140e091327e Mon Sep 17 00:00:00 2001 From: Tyrie Vella Date: Tue, 9 Sep 2025 07:53:06 -0700 Subject: [PATCH 1/2] Set updated_skipworktree on restore --staged --- builtin/checkout.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/builtin/checkout.c b/builtin/checkout.c index c4b4f36a03a022..8384988424c81d 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -641,6 +641,10 @@ static int checkout_paths(const struct checkout_opts *opts, checkout_index = opts->checkout_index; if (checkout_index) { + /* Some scenarios may update skipworktree bits, such as + * `restore --staged` after `cherry-pick -n` or `reset --soft` + */ + 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 { From f60142bf7b233d0877634d6b43b5673770ff69c1 Mon Sep 17 00:00:00 2001 From: Tyrie Vella Date: Tue, 9 Sep 2025 10:48:32 -0700 Subject: [PATCH 2/2] Fix of skip-worktree for cherry-pick --no-commit --- builtin/checkout.c | 7 +++++-- read-cache-ll.h | 3 ++- sequencer.c | 14 +++++++++++++- unpack-trees.c | 15 +++++++++++++++ 4 files changed, 35 insertions(+), 4 deletions(-) diff --git a/builtin/checkout.c b/builtin/checkout.c index 8384988424c81d..18a5cfcc465459 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -641,10 +641,13 @@ static int checkout_paths(const struct checkout_opts *opts, checkout_index = opts->checkout_index; if (checkout_index) { - /* Some scenarios may update skipworktree bits, such as - * `restore --staged` after `cherry-pick -n` or `reset --soft` + /* 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..3972012377d820 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, + clear_skip_worktree_for_added_entries : 0; enum sparse_index_mode sparse_index; struct hashmap name_hash; struct hashmap dir_hash; diff --git a/sequencer.c b/sequencer.c index d47937b3f7b364..038b6c05465084 100644 --- a/sequencer.c +++ b/sequencer.c @@ -753,6 +753,7 @@ static int do_recursive_merge(struct repository *r, int clean, show_output; int i; struct lock_file index_lock = LOCK_INIT; + int flags; if (repo_hold_locked_index(r, &index_lock, LOCK_REPORT_ON_ERROR) < 0) return -1; @@ -787,7 +788,18 @@ 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 because the virtual file + * system only tracks files that are not modified in index. + * Without this, `restore --staged` will delete the new files + * from disk as well as from index. + */ + o.repo->index->clear_skip_worktree_for_added_entries = 1; + } merge_switch_to_result(&o, head_tree, &result, 1, show_output); + o.repo->index->clear_skip_worktree_for_added_entries = 0; + clean = result.clean; if (clean < 0) { rollback_lock_file(&index_lock); @@ -795,7 +807,7 @@ static int do_recursive_merge(struct repository *r, } if (write_locked_index(r->index, &index_lock, - COMMIT_LOCK | SKIP_IF_UNCHANGED)) + COMMIT_LOCK | SKIP_IF_UNCHANGED) < 0) /* * TRANSLATORS: %s will be "revert", "cherry-pick" or * "rebase". diff --git a/unpack-trees.c b/unpack-trees.c index bd63bbc7c6e4b8..8dd2e35ee804f4 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -1852,6 +1852,21 @@ static void mark_new_skip_worktree(struct pattern_list *pl, enable_fscache(istate->cache_nr); clear_ce_flags(istate, select_flag, skip_wt_flag, pl, show_progress); disable_fscache(); + + /* + * 3. If clear_skip_worktree_for_added_entries is set and we are checking for + * added entries, clear skip_wt_flag from all added entries. + */ + if ((select_flag & CE_ADDED) + && istate->clear_skip_worktree_for_added_entries) { + for (i = 0; i < istate->cache_nr; i++) { + struct cache_entry *ce = istate->cache[i]; + if ((ce->ce_flags & (CE_ADDED | skip_wt_flag)) + == (CE_ADDED | skip_wt_flag)) { + ce->ce_flags &= ~skip_wt_flag; + } + } + } } static void populate_from_existing_patterns(struct unpack_trees_options *o,