From c3252d43c3da5420274ddd204f457015c0e0f2e8 Mon Sep 17 00:00:00 2001 From: arookieofc Date: Fri, 30 Oct 2026 19:00:42 +0800 Subject: [PATCH] fix(vcs): hide tracked changes of ignored names from Git status (#408) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Names in Settings › Ignored files and folders were hidden only when untracked; their tracked or staged changes still showed in the change list. They are now filtered too, except conflicts, so a merge can't stall on a hidden file. Co-authored-by: a-rookie-of-C-language <186315048+a-rookie-of-C-language@users.noreply.github.com> --- crates/ide-vcs/src/status.rs | 4 ++++ crates/ide-vcs/tests/repo.rs | 11 +++++++++++ 2 files changed, 15 insertions(+) diff --git a/crates/ide-vcs/src/status.rs b/crates/ide-vcs/src/status.rs index f87ccdf59..9a21ba092 100644 --- a/crates/ide-vcs/src/status.rs +++ b/crates/ide-vcs/src/status.rs @@ -105,6 +105,10 @@ pub(crate) fn status(r: &Repo) -> IdeResult> { Ok(map .into_iter() .filter(|(_, e)| e.staged.is_some() || e.unstaged.is_some()) + // Ignored names mean "the IDE treats these as nonexistent": hide their tracked + // changes too, not just untracked hits above. Conflicts stay visible so merges + // cannot stall on a file the user cannot see. + .filter(|(rel, _)| conflicts.contains(rel) || !ignored.is_ignored_path(rel)) .map(|(rel, mut e)| { if conflicts.contains(&rel) { e.staged = None; diff --git a/crates/ide-vcs/tests/repo.rs b/crates/ide-vcs/tests/repo.rs index 6b97eeadf..a2e97b41f 100644 --- a/crates/ide-vcs/tests/repo.rs +++ b/crates/ide-vcs/tests/repo.rs @@ -175,6 +175,9 @@ fn status_matrix() { fx.write("staged_del.txt", "a\n"); fx.write("rename_me.txt", "some longer content\nthat is stable\nfor rename detection\n"); fx.write("both.txt", "a\n"); + // A committed file the IDE ignores keeps its history but drops out of the change list. + fx.write("tracked.pyc", "a\n"); + fx.git(&["add", "-f", "tracked.pyc"]); fx.commit_all("base"); fx.write("modified.txt", "b\n"); @@ -195,6 +198,10 @@ fn status_matrix() { fx.write(".DS_Store", "junk"); fx.write("dir/.DS_Store", "junk"); fx.write("pkg/__pycache__/m.pyc", "junk"); + fx.write("tracked.pyc", "b\n"); + // Contents differ from `staged_del.txt` so rename detection cannot pair them. + fx.write("staged_ignored.pyc", "cached\nbytecode\n"); + fx.git(&["add", "-f", "staged_ignored.pyc"]); let repo = fx.repo(); repo.set_ignored_names(ide_core::settings::Settings::default().ignored_names()); @@ -217,6 +224,10 @@ fn status_matrix() { assert_eq!(status_of(&st, "renamed.txt").renamed_from.as_deref(), Some("rename_me.txt")); assert!(!st.iter().any(|s| s.rel_path == "rename_me.txt"), "rename source listed: {st:#?}"); assert!(!st.iter().any(|s| s.rel_path.contains("debug.log") || s.rel_path.contains("build"))); + assert!( + !st.iter().any(|s| s.rel_path.contains("tracked.pyc") || s.rel_path.contains("staged_ignored.pyc")), + "{st:#?}" + ); assert!(!st.iter().any(|s| s.rel_path.contains(".DS_Store") || s.rel_path.contains("pkg")), "{st:#?}"); // Sorted by path. let paths: Vec<_> = st.iter().map(|s| s.rel_path.clone()).collect();