#963)
This is a companion of #935, porting the changes from vfs-2.54.0 to
vfs-2.55.0.
## Problem
In virtual filesystem (VFS/GVFS) mode, `reset --mixed` fails to report
hydrated files as modified.
A **hydrated file** is one that has been read (e.g., via `blame` or
`cat-file`) and materialized on disk by ProjFS, but not modified — so it
is not in GVFS's ModifiedPaths database and retains the `skip-worktree`
bit in the index.
### Reproduction
1. `gvfs clone` a repo
2. `git blame Readme.md` — hydrates the file (ProjFS materializes
content on disk)
3. `git reset --mixed HEAD~1` (where `Readme.md` differs between HEAD
and HEAD~1)
4. **Expected:** `Readme.md` appears in reset output and `git status`
shows it as modified
5. **Actual:** `Readme.md` is missing from output; `git status` reports
clean
### Root cause
The VFS-specific code in `update_index_from_diff()` uses `file_exists()`
to decide whether to clear `skip-worktree`:
- **Files NOT on disk** (virtual/placeholder): `file_exists()` returns
false → `skip-worktree` cleared, pre-reset content written to disk via
`checkout_entry()` → correctly reported as modified ✓
- **Files on disk** (hydrated): `file_exists()` returns true →
`skip-worktree` left set → `refresh_index()` skips the entry → invisible
to status ✗
The original code assumed that if a file exists on disk, it must already
be tracked properly. But hydrated-but-not-modified files exist on disk
with stale content and are NOT in ModifiedPaths.
## Fix
Always clear `skip-worktree` (`respect_skip_worktree = 0`) for all
entries processed by `update_index_from_diff()` when VFS mode is active.
The `file_exists()` check now only controls whether pre-reset content
needs to be written to disk — it no longer gates the skip-worktree
decision.
After the reset, GVFS's `GitIndexParser` detects the cleared
skip-worktree bits via the `post-index-change` hook and adds affected
paths to ModifiedPaths, so subsequent git commands also see them
correctly.
### Before (buggy)
```c
if (core_virtualfilesystem && !file_exists(two->path))
{
respect_skip_worktree = 0; // only for missing files
// ... write content to disk ...
}
```
### After (fixed)
```c
if (core_virtualfilesystem)
{
respect_skip_worktree = 0; // for ALL changed entries
if (!file_exists(two->path)) // only write content for missing files
{
// ... write content to disk ...
}
}
```
## Testing
- 3 new tests in `t1093-virtualfilesystem.sh`:
- **Hydrated file**: file exists on disk, should appear in reset output
- **Non-hydrated file**: file missing from disk, should be written and
appear in output
- **Partial reset**: unchanged files retain skip-worktree
- Verified manually against a real GVFS enlistment: GVFS and control
repo now produce identical output (224 modified files including
`Readme.md`)
- All 25 existing `t1093` tests pass
Problem
In virtual filesystem (VFS/GVFS) mode, reset --mixed fails to report hydrated files as modified.
A hydrated file is one that has been read (e.g., via blame or cat-file) and materialized on disk by ProjFS, but not modified — so it is not in GVFS's ModifiedPaths database and retains the skip-worktree bit in the index.
Reproduction
Root cause
The VFS-specific code in update_index_from_diff() uses file_exists() to decide whether to clear skip-worktree:
The original code assumed that if a file exists on disk, it must already be tracked properly. But hydrated-but-not-modified files exist on disk with stale content and are NOT in ModifiedPaths.
Fix
Always clear skip-worktree (respect_skip_worktree = 0) for all entries processed by update_index_from_diff() when VFS mode is active. The file_exists() check now only controls whether pre-reset content needs to be written to disk — it no longer gates the skip-worktree decision.
After the reset, GVFS's GitIndexParser detects the cleared skip-worktree bits via the post-index-change hook and adds affected paths to ModifiedPaths, so subsequent git commands also see them correctly.
Before (buggy)
After (fixed)
Testing