Skip to content

entry: flush fscache after creating directories and writing files#6250

Open
tyrielv wants to merge 1 commit into
git-for-windows:mainfrom
tyrielv:tyrielv/fscache-parallel-checkout-fix-gfw
Open

entry: flush fscache after creating directories and writing files#6250
tyrielv wants to merge 1 commit into
git-for-windows:mainfrom
tyrielv:tyrielv/fscache-parallel-checkout-fix-gfw

Conversation

@tyrielv
Copy link
Copy Markdown

@tyrielv tyrielv commented May 18, 2026

Problem

git checkout <tree> -- <pathspec> with checkout.workers > 1 and core.fscache=true fails when restoring files into directories that do not yet exist on disk. Two failure modes:

  1. fatal: cannot create directory at '...': Directory not empty (exit 128)
  2. error: unable to stat just-written file '...' (exit 255)

100% reproducible when two or more files share a not-yet-created parent directory.

Root Cause

The Windows fscache caches directory listings that become stale when create_directories() creates new parent directories via mkdir() or when write_pc_item() writes new files. With workers=1, write_entry() calls flush_fscache() after each file, keeping the cache in sync. With workers>1, enqueue_checkout() defers the write (and the flush), leaving the cache stale for subsequent entries.

Fix

Add flush_fscache() calls:

  • In create_directories() after each successful mkdir(), so has_dirs_only_path() sees the new directory
  • In write_pc_item() before lstat() of the just-written file

On non-Windows platforms flush_fscache() is a no-op.

Test

Adds a regression test to t2080-parallel-checkout-basics.sh (MINGW prereq) that deterministically reproduces the bug: two files sharing a nested parent directory, deleted in a second commit, then restored via git checkout <tree> -- <pathspec> with workers=2.

When checkout.workers > 1 and core.fscache is enabled on Windows,
'git checkout <tree> -- <pathspec>' fails when restoring files into
directories that do not yet exist on disk. Two failure modes occur:

1. create_directories(): the fscache returns a stale directory listing
   that does not include a just-created directory. has_dirs_only_path()
   reports it as non-existent, triggering the unlink+mkdir recovery
   path which fails with 'cannot create directory: Directory not empty'.

2. write_pc_item(): after writing and closing a file, lstat() cannot
   see it through the stale fscache, failing with 'unable to stat
   just-written file'.

With workers=1, write_entry() calls flush_fscache() after each file,
keeping the cache in sync. With workers>1, enqueue_checkout() defers
the write (and the flush), leaving the cache stale for subsequent
entries.

Fix both by adding flush_fscache() calls after mkdir() in
create_directories() and before lstat() in write_pc_item(). On
non-Windows platforms flush_fscache() is a no-op.

Assisted-by: Claude Opus 4.6
Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
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.

1 participant