lore-revision: discard reverted unstaged adds when a scanned folder vanishes - #1
Open
jochenhz wants to merge 2 commits into
Open
lore-revision: discard reverted unstaged adds when a scanned folder vanishes#1jochenhz wants to merge 2 commits into
jochenhz wants to merge 2 commits into
Conversation
…anishes A folder created and deleted again without ever being committed left phantom Delete entries in `status --scan`: the missing-directory subtree walk marked every staged node DirtyDelete and reported Delete regardless of whether the node exists in the current revision. The file-level walk already discarded such reverted adds; directory subtrees (and path-scoped scans whose root vanished) did not, and because the DirtyDelete flags are persisted in the staged state, every subsequent scan re-reported the phantom subtree forever. The missing-subtree delete walk now resolves each node's counterpart in the current revision (find_subnode by name hash) and, during a scan, queues unstaged nodes without a counterpart for discard instead of marking and reporting them. Directories are discarded post-order after their children, and only when every child was visited and discarded — a staged descendant or filter-excluded child keeps the ancestor chain alive, so no node is orphaned. A committed directory whose staged-tree children were all discarded still reports its own deletion. apply_pending_discards now applies in insertion order with a seen-set dedup: node ids are not monotonic with tree depth, and a directory can only be unlinked after its children are gone. The membership check (rather than a DirtyAdd flag check) also heals staged states already wedged by the old behavior: their nodes were re-marked DirtyDelete by node_mark_dirty's latest-wins replacement and are discarded by the first scan running this code. Regression tests cover the untracked-folder revert, committed-folder deletes, and the mixed case (committed folder containing an untracked file), including staged-state cleanliness on repeat scans. AP2-162
A never-committed empty directory deleted from disk must not be reported by later scans, independent of whether the scan registered a node for it.
jochenhz
pushed a commit
that referenced
this pull request
Jul 17, 2026
Fixed typo in documentation: `lore-revision/README-PROTOCOLS.md` ``` Imported-PR: #1 Imported-From: 3bb4abe Imported-Base: 4bffa76 Imported-Merge: fc2725e Imported-Author: Duncan Grist (duncangrist) Signed-off-by: Duncan Grist <duncan.grist@epicgames.com> GH-URL: EpicGames#1 ``` Lore-RevId: 302 Lore-Signature: 1450b41da6fd8e46246b1869d8b8f10b1c9e33fef6b568a695c40753af025f16
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
Adding a folder with files to a repository (untracked, never committed) and then deleting the folder from disk leaves permanent phantom
Dentries inlore status --scan— reproduced on a revision-0 repository reportingDfor paths no revision ever contained. The scan persistsDirtyDeleteon the staged nodes, so every later scan re-reports the phantom subtree.The missing-file case already handles this (reverted-add discard in
diff_filesystem_directory_walk); the missing-directory subtree walk (emit_filesystem_subtree_deletes) and the path-scoped missing-root case (diff_filesystem_missing) did not check membership in the current revision at all.Change
emit_filesystem_subtree_deletesresolves each node's counterpart in the current revision (find_subnodeby name hash). During a scan, an unstaged node with no counterpart is a reverted add: files/links are queued for discard; a directory is queued post-order after its children and only when every child was visited and discarded (staged descendants and filter-excluded children keep the ancestor chain alive — no orphaned nodes). A committed directory whose staged-tree children were all discarded still reports its own deletion.apply_pending_discardsapplies in insertion order with a seen-set dedup instead of sorting by node id — ids are not monotonic with tree depth, and a directory can only be unlinked after its children.diff_filesystem_missingapplies the same membership rule viacollect_revertible_subtree(aborts to the legacy delete report if the subtree contains a staged node).DirtyAddflag) is the discriminator, so staged states already wedged by the old behavior — nodes re-markedDirtyDeletebynode_mark_dirty's latest-wins replacement — self-heal on their first scan with this fix.Test Plan
New
lore/tests/scan_reverted_add.rs(offline on-disk globals, staged state persisted across status calls):scan_forgets_deleted_untracked_folder— failed before the fix (phantomDfor the vanished folder), passes now, including a second scan proving no lingering nodes/flags.scan_reports_deletes_for_committed_folder— guards real deletes; passed before and after.scan_mixed_folder_reports_only_committed_deletes— failed before the fix; committed content still reportsD, the untracked file vanishes from the report.Also green:
lore-revisionlib tests (130),state/dirty/stage/reset/commit/clone/unstageintegration suites, alllorecrate tests,cargo clippy -p lore-revisionwarning-free,cargo fmt.