Skip to content

Conversation

tyrielv
Copy link

@tyrielv tyrielv commented Oct 9, 2025

When using virtualfilesystem, Running git restore --staged after git cherry-pick -n or git reset --soft would result in an incorrect state - the modified files would still have their modified contents, but git would no longer recognize them as being modified; and the added files would be deleted from disk instead of just unstaged.

See microsoft/VFSForGit#1855 for more details.

This commit fixes these issues with two changes:

  1. Add a new flag to the index state structure, clear_skip_worktree_for_added_entries. This flag is set during cherry-pick -n before calculating the new index state, and causes newly added entries to have their SKIP_WORKTREE bit cleared. This ensures that newly added files are added to both the index and the worktree in the next step. Otherwise, sparse-checkout would prevent them from being added to the worktree.

  2. Set the existing flag updated_skipworktree on the index when running a checkout index (aka restore --staged) operation. These operations already will clear SKIP_WORKTREE bits for modified files, but without this flag set the virtualfilesystem hook notification does not indicate that they changed, causing the VFS to not update its state correctly.


Thanks for taking the time to contribute to Git!

This fork contains changes specific to monorepo scenarios. If you are an
external contributor, then please detail your reason for submitting to
this fork:

  • This is an early version of work already under review upstream.
  • This change only applies to interactions with Azure DevOps and the
    GVFS Protocol.
  • This change only applies to the virtualization hook and VFS for Git.

When using virtualfilesystem, Running
`git restore --staged` after `git cherry-pick -n`
or `git reset --soft` would result in an incorrect
state - the modified files would still have their
modified contents, but git would no longer
recognize them as being modified; and the added
files would be deleted from disk instead of just
unstaged.

See
microsoft/VFSForGit#1855
for more details.

This commit fixes these issues with two changes:
1) Add a new flag to the index state structure,
`clear_skip_worktree_for_added_entries`. This flag
is set during cherry-pick -n before calculating
the new index state, and causes newly added
entries to have their SKIP_WORKTREE bit cleared.
This ensures that newly added files are added to
both the index and the worktree in the next step.
Otherwise, sparse-checkout would prevent them from
being added to the worktree.

3) Set the existing flag updated_skipworktree on
the index when running a checkout index (aka
`restore --staged`) operation. These operations
already will clear SKIP_WORKTREE bits for modified
files, but without this flag set the
virtualfilesystem hook notification does not
indicate that they changed, causing the VFS to not
update its state correctly.
The failing test `t7113` is due to the change in
`builtin/checkout.c` that now sets the
`updated_skipworktree` flag. The test checked that
this flag was not set, which is no longer valid.
Comment on lines +1855 to +1873

/*
* 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. This is
* used when running with virtualfilesystem to ensure that added entries are
* also checked out in the working tree - otherwise skip_wt_flag will
* prevent that.
*/
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;
istate->updated_skipworktree = 1;
}
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this new loop runs after the previous two loops over the entire index (even clear_ce_flags() contains such a loop).

However, the virtual filesystem is already special-cased in clear_ce_flags(), via the call to `clear_ce_flags_virtualfilesystem.

Which makes me wonder whether it's that clear_ce_flags_virtualfilesystem() function that introduces that bug, and this here patch would only paper over that bug?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll look into that.

Comment on lines -82 to -84
git checkout -- dir1/file1.txt &&
test_path_is_file testsuccess && rm -f testsuccess &&
test_path_is_missing testfailure &&
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's a good idea to remove these lines. Would the test be failing with the changes? That would be more indicative of a bug introduced by the changes, I think; The post-index-change hook is actively used in Office, and they use Scalar instead of VFSforGit, therefore virtual filesystem-specific changes should not affect them, I'd think.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

post-index-change is still called by git checkout, but due to this change it is setting one of the arguments with less discrimination, and this test case is for scenarios where neither of the arguments are set.

I will look into setting the argument more precisely so this test case will pass without change.

@tyrielv
Copy link
Author

tyrielv commented Oct 10, 2025

Withdrawing for now.

@tyrielv tyrielv closed this Oct 10, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants