Skip to content

fix: don't report a tree of only empty directories as untracked. (#2490)#2673

Open
Amey Pawar (ameyypawar) wants to merge 5 commits into
GitoxideLabs:mainfrom
ameyypawar:fix/2490-empty-dir-collapse
Open

fix: don't report a tree of only empty directories as untracked. (#2490)#2673
Amey Pawar (ameyypawar) wants to merge 5 commits into
GitoxideLabs:mainfrom
ameyypawar:fix/2490-empty-dir-collapse

Conversation

@ameyypawar

Copy link
Copy Markdown
Contributor

What

Fixes #2490. gix status --submodules all reported a submodule as modified when it contained only empty untracked directories — Git treats a tree with no files as clean. The same surfaced as a phantom ? empty-dir/ in plain gix status.

Root cause

gix-dir's worktree walk dropped the EmptyDirectory property when collapsing a directory: a tree of only empty subdirectories collapsed to a plain Untracked directory, which status then surfaced (and a submodule containing it appeared modified).

Fix

In try_collapse (gix-dir/src/walk/readdir.rs), when every collapsed entry is itself an EmptyDirectory, the collapsed directory inherits EmptyDirectory — so callers that skip empty directories by default (like status) behave like Git.

This is scoped to non-deletion walks (for_deletion.is_none()). Deletion has its own handling of empty directories — gix clean always runs with for_deletion: Some(…), so it is unaffected and still sees these directories for removal. The boundary cleanly separates status (read-only, wants empty-only trees skipped) from clean/deletion (wants them visible).

Tests

gix-dir/tests/dir/walk.rs (complex_empty):

  • The collapsed only-dirs (a tree of only empty subdirs) now carries EmptyDirectory.
  • Added a regression: with emit_empty_directories: false + collapse, an empty-only tree is not emitted, matching Git treating it as clean.

Verification

  • All gix-dir tests pass (including the deletion tests, unaffected by the scoping); cargo clippy -p gix-dir --tests and cargo fmt --check clean.
  • End-to-end: gix status --submodules all on the issue's exact repro is now clean (was M config).

Notes

  • Adapts the approach from the self-closed fix(status): ignore nested empty directory trees #2525, adding the deletion scoping it lacked (the unscoped version changed deletion behavior).
  • Whether deletion mode should also tag empty-only trees as EmptyDirectory (a cosmetic " empty" label in gix clean) is left untouched deliberately — happy to extend if you'd prefer.

Amey Pawar (ameyypawar) and others added 3 commits June 23, 2026 16:46
… dirs

When a directory is collapsed during the worktree walk and every collapsed
entry is itself an empty directory, the collapsed directory has no files to
track. Previously the `EmptyDirectory` property was dropped on collapse, so
such a tree was reported as `Untracked` -- which made `gix status` surface
it (and, via a submodule, report the submodule as modified) even though Git
considers a tree of only empty directories clean.

Propagate `EmptyDirectory` to the collapsed directory in that case so callers
that skip empty directories by default (like status) behave like Git.

For GitoxideLabs#2490
Deletion mode has its own handling of empty directories; restrict the
`EmptyDirectory`-on-collapse propagation to status-like walks
(`for_deletion.is_none()`) so deletion behavior is unchanged.
…ideLabs#2490)

Update the collapse expectation for a tree of only empty directories
(now carries the EmptyDirectory property) and add a regression that such
a tree is not emitted when empty directories aren't requested, matching
Git treating it as clean.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 558d947c51

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "Codex (@codex) review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "Codex (@codex) address that feedback".

Comment on lines +378 to +381
let collapsed_property = (opts.for_deletion.is_none()
&& state.on_hold[self.start_index..]
.iter()
.all(|entry| entry.property == Some(entry::Property::EmptyDirectory)))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Restrict empty-directory tagging to untracked collapses

This applies the EmptyDirectory property to ignored collapses as well as untracked ones. In a non-deletion status walk with emit_ignored: Some(CollapseDirectory) (the --ignored default maps to this in gitoxide-core/src/repository/status.rs, and the CLI option is documented to show ignored files/directories in src/plumbing/options/mod.rs), a pathspec can force an ignored empty directory to be recursed; e.g. .gitignore contains ignored/, the worktree has only ignored/sub/, and the user runs gix status --ignored=collapsed ignored. The collapsed ignored entry is then filtered out later by emit_entry because emit_empty_directories is false, so the explicitly requested ignored directory disappears. Please gate this propagation on dir_status == Untracked or otherwise avoid treating ignored collapses as skippable empty directories.

Useful? React with 👍 / 👎.

An explicitly requested ignored directory (e.g. `gix status --ignored=collapsed <pathspec>`)
must remain observable even when it is empty; tagging its collapse as `EmptyDirectory`
caused it to be filtered out when empty directories aren't emitted. Restrict the
propagation to untracked collapses, which is the only case GitoxideLabs#2490 is about.
`some/` (a tree of only empty directories) now collapses to an empty
directory and is skipped when empty directories aren't emitted, matching
Git which treats a tree with no files as clean. See GitoxideLabs#2490.
@Byron

Copy link
Copy Markdown
Member

You are on fire!

And I just noticed this myself, and this PR fixes it.

❯ cargo run --bin gix -- status
    Finished [`dev` profile [unoptimized + debuginfo]](https://doc.rust-lang.org/cargo/reference/profiles.html#default-profiles) target(s) in 0.22s
     Running `target/debug/gix status`
 00:28:35 status done 2.9k files in 0.06s (50.6k files/s)

gitoxide on  fix/2490-empty-dir-collapse [$] is 📦 v0.55.0
❯ gix status
 00:28:36 status done 2.9k files in 0.02s (139.0k files/s)
  ? gix-actor/fuzz/artifacts/
  ? gix-attributes/fuzz/artifacts/
  ? gix-config-value/fuzz/artifacts/
  ? gix-ref/fuzz/artifacts/

I will try to get this merged soon!

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.

"gix status --submodules all" falsely reports submodule as modified with empty dir

2 participants