Skip to content

fix(explorer): clear dir_status on git refresh so committed files under a new folder don't stay untracked - #2934

Open
OsoRojo wants to merge 1 commit into
folke:mainfrom
OsoRojo:fix/explorer-dir-status-reset
Open

fix(explorer): clear dir_status on git refresh so committed files under a new folder don't stay untracked#2934
OsoRojo wants to merge 1 commit into
folke:mainfrom
OsoRojo:fix/explorer-dir-status-reset

Conversation

@OsoRojo

@OsoRojo OsoRojo commented Aug 15, 2026

Copy link
Copy Markdown

fix(explorer): clear dir_status on git refresh so committed files under a new folder don't stay "untracked"

What

In the explorer, a file added inside a folder git hasn't tracked yet keeps the untracked (?) marker after it has been committed, even though git status reports it clean. The stale marker survives explorer_update (u) and only clears on a full restart.

This is a small state bug and is distinct from the known "explorer doesn't auto-detect external git changes" reports (#1630 / #2030 / discussion #2509) — see Not this bug below. It reproduces with a fully in-editor workflow.

Repro (deterministic)

In any repo with at least one commit:

mkdir newfolder && printf 'x\n' > newfolder/note.md
  1. Open the explorer → note.md shows untracked ?
  2. Stage it (git add, lazygit, …) → shows staged ✅
  3. Commit it → reverts to ? untracked, though git status is clean ❌

It persists through u / refresh and clears only on restart. It does not happen for a file at the repo root, or in a folder that already contains a tracked file — that asymmetry is the tell.

Root cause

git status --porcelain collapses an untracked directory to a single entry, ?? newfolder/ — it never lists newfolder/note.md individually. In lua/snacks/explorer/git.lua, M._update records that on the directory node as n.dir_status = s.status ("??").

The per-refresh reset walk clears each node's status and ignored, but not dir_status:

Tree:walk(node, function(n)
  n.status = nil
  n.ignored = nil
end, { all = true })

Because Tree:child reuses nodes, dir_status sticks for the session, and a file with no status of its own inherits parent.dir_status for display (lua/snacks/picker/source/explorer.lua). Instrumenting the real modules through the lifecycle:

Before (current main):

create  | git=?? newfolder/         | note.md=nil newfolder.dir_status=??  | DISPLAY=?? (inherit)
stage   | git=A  newfolder/note.md  | note.md=A   newfolder.dir_status=??  | DISPLAY=A  (own)
commit  | git=(clean)               | note.md=nil newfolder.dir_status=??  | DISPLAY=?? (inherit)   ← bug

At commit, the file's own status correctly clears, but it falls back to the folder's stale dir_status.

Fix

Clear dir_status in the same reset walk, so it's re-derived from the current git status on each refresh:

 Tree:walk(node, function(n)
   n.status = nil
   n.ignored = nil
+  n.dir_status = nil
 end, { all = true })

After:

create  | git=?? newfolder/         | note.md=nil newfolder.dir_status=??   | DISPLAY=?? (inherit)   ← still correct
stage   | git=A  newfolder/note.md  | note.md=A   newfolder.dir_status=nil  | DISPLAY=A  (own)
commit  | git=(clean)               | note.md=nil newfolder.dir_status=nil  | DISPLAY=(none)         ← fixed

The legitimate untracked-folder display still works (re-derived from the live ?? newfolder/), staging shows staged, and commit correctly shows clean.

Not this bug (to avoid conflation)

This is not the "explorer doesn't update when git state changes outside the explorer" issue (#1630, #2030, discussion #2509). That one is about detecting external changes and is worked around with u / a FocusGained autocmd / the tab-switch refresh (#2348). This bug is a stale field that survives u — which is exactly why several people in #2509 (e.g. @metal3d, @redoxahmii) report that u doesn't help them and only a restart does.

Environment

  • snacks.nvim 882c996 (current main)
  • Neovim v0.12.4, git 2.50.1, macOS 26.6

The _update reset clears each node's status and ignored but not dir_status, so a file committed under a previously-untracked folder keeps inheriting the folder's stale "??" and shows as untracked until restart. Clear dir_status too so it is re-derived from git status on each refresh.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

explorer size/xs Extra small PR (<3 lines changed)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant