You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[package-deps-hash] RepoStateCache misses edits that keep size and mtime when the repo sets core.checkStat=minimal / core.trustctime=false #6143
Versions: @rushstack/package-deps-hash / rush-lib 5.181.0, main @ 9f5a087 (RepoStateCache.ts unchanged since 1e18b16); git 2.51.1, Linux.
Summary
RepoStateCache refreshes a private copy of the index with git status on every snapshot, using PRIVATE_INDEX_STATUS_OPTIONS. Those options don't pin Git's stat checks, so the repository's config applies. Large repos often set core.checkStat=minimal and core.trustctime=false for speed. Then Git compares only the whole-second mtime and the size, so once the private index has recorded a file, an edit that keeps the size and restores the mtime goes unnoticed. Such edits come from touch -d/touch -r, cp -p, tar x and rsync -t. The snapshot then keeps reporting the old blob hash, so the build cache can restore stale outputs and watch mode skips the rebuild. RepoStateCache's own ctime-based FileStamp guards only the files it hashes itself (shrinkwrap files, modified files), not Git's view of tracked files.
Minimal repro (plain git; RepoStateCache runs the same git status on its private index)
git init -q r &&cd r
git config core.checkStat minimal && git config core.trustctime falseecho aaaa > f.txt && touch -d '-1 hour' f.txt && git add f.txt && git commit -qm init
sleep 2
touch -r f.txt ../keep &&echo bbbb > f.txt && touch -r ../keep f.txt
git status --porcelain # prints nothing: the edit is missed
git -c core.checkStat=default -c core.trustctime=true status --porcelain # " M f.txt"
Expected: a modified file is reported, whatever the user's stat settings. Actual: it is reported as unchanged. I reproduced the same with a standalone RepoStateCache: it kept returning the HEAD blob for the file while the file on disk differed.
Code pointer
libraries/package-deps-hash/src/RepoStateCache.ts:75-87 (PRIVATE_INDEX_STATUS_OPTIONS), used at :474-480.
Suggested fix
Add -c core.checkStat=default -c core.trustctime=true to PRIVATE_INDEX_STATUS_OPTIONS. The private index is not the user's, so this doesn't change the user's own Git behavior.
Cost: the first status after the index is copied re-hashes the files whose ctime differs from the copied index. That happens once per copy (about 25 s warm on a ~241k-file repo whose files had all been re-created since the index was written), and later snapshots are unaffected.
Related: the uncached path (getDetailedRepoStateAsync on the real index with --no-optional-locks) has the same gap under these settings, once the user's own Git commands have refreshed the index after the file's mtime. It is just less likely to be triggered.
Filed with help from GitHub Copilot (AI); reviewed by the reporter.
Activity