Skip to content

Commit 39476e3

Browse files
committed
feat: gix status now shows untracked files as well.
1 parent ff4b95c commit 39476e3

File tree

2 files changed

+65
-19
lines changed

2 files changed

+65
-19
lines changed

gitoxide-core/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ serde = ["gix/serde", "dep:serde_json", "dep:serde", "bytesize/serde"]
4747

4848
[dependencies]
4949
# deselect everything else (like "performance") as this should be controllable by the parent application.
50-
gix = { version = "^0.59.0", path = "../gix", default-features = false, features = ["blob-diff", "revision", "mailmap", "excludes", "attributes", "worktree-mutation", "credentials", "interrupt", "status"] }
50+
gix = { version = "^0.59.0", path = "../gix", default-features = false, features = ["blob-diff", "revision", "mailmap", "excludes", "attributes", "worktree-mutation", "credentials", "interrupt", "status", "dirwalk"] }
5151
gix-pack-for-configuration-only = { package = "gix-pack", version = "^0.48.0", path = "../gix-pack", default-features = false, features = ["pack-cache-lru-dynamic", "pack-cache-lru-static", "generate", "streaming-input"] }
5252
gix-transport-configuration-only = { package = "gix-transport", version = "^0.41.0", path = "../gix-transport", default-features = false }
5353
gix-archive-for-configuration-only = { package = "gix-archive", version = "^0.9.0", path = "../gix-archive", optional = true, features = ["tar", "tar_gz"] }

gitoxide-core/src/repository/status.rs

Lines changed: 64 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use anyhow::{bail, Context};
2+
use gix::bstr::ByteSlice;
23
use gix::{
34
bstr::{BStr, BString},
45
index::Entry,
@@ -46,7 +47,7 @@ pub fn show(
4647
let mut index = repo.index_or_empty()?;
4748
let index = gix::threading::make_mut(&mut index);
4849
let pathspec = repo.pathspec(
49-
pathspecs,
50+
pathspecs.iter().map(|p| p.as_bstr()),
5051
true,
5152
index,
5253
gix::worktree::stack::state::attributes::Source::WorktreeThenIdMapping,
@@ -74,23 +75,67 @@ pub fn show(
7475
out,
7576
changes: Vec::new(),
7677
};
77-
let outcome = gix_status::index_as_worktree(
78-
index,
79-
repo.work_dir()
80-
.context("This operation cannot be run on a bare repository")?,
81-
&mut printer,
82-
FastEq,
83-
Submodule,
84-
repo.objects.clone().into_arc()?,
85-
&mut progress,
86-
pathspec.detach()?,
87-
repo.filter_pipeline(Some(gix::hash::ObjectId::empty_tree(repo.object_hash())))?
88-
.0
89-
.into_parts()
90-
.0,
91-
&gix::interrupt::IS_INTERRUPTED,
92-
options,
93-
)?;
78+
let filter_pipeline = repo
79+
.filter_pipeline(Some(gix::hash::ObjectId::empty_tree(repo.object_hash())))?
80+
.0
81+
.into_parts()
82+
.0;
83+
84+
let mut collect = gix::dir::walk::delegate::Collect::default();
85+
let (outcome, walk_outcome) = gix::features::parallel::threads(|scope| -> anyhow::Result<_> {
86+
// TODO: it's either this, or not running both in parallel and setting UPTODATE flags whereever
87+
// there is no modification. This can save disk queries as dirwalk can then trust what's in
88+
// the index regarding the type.
89+
// NOTE: collect here as rename-tracking needs that anyway.
90+
let walk_outcome = gix::features::parallel::build_thread()
91+
.name("gix status::dirwalk".into())
92+
.spawn_scoped(scope, {
93+
let repo = repo.clone().into_sync();
94+
let index = &index;
95+
let collect = &mut collect;
96+
move || {
97+
let repo = repo.to_thread_local();
98+
repo.dirwalk(
99+
index,
100+
pathspecs,
101+
repo.dirwalk_options()?
102+
.emit_untracked(gix::dir::walk::EmissionMode::CollapseDirectory),
103+
collect,
104+
)
105+
}
106+
})?;
107+
108+
let outcome = gix_status::index_as_worktree(
109+
index,
110+
repo.work_dir()
111+
.context("This operation cannot be run on a bare repository")?,
112+
&mut printer,
113+
FastEq,
114+
Submodule,
115+
repo.objects.clone().into_arc()?,
116+
&mut progress,
117+
pathspec.detach()?,
118+
filter_pipeline,
119+
&gix::interrupt::IS_INTERRUPTED,
120+
options,
121+
)?;
122+
123+
let walk_outcome = walk_outcome.join().expect("no panic")?;
124+
Ok((outcome, walk_outcome))
125+
})?;
126+
127+
for entry in collect
128+
.into_entries_by_path()
129+
.into_iter()
130+
.filter_map(|(entry, dir_status)| dir_status.is_none().then_some(entry))
131+
{
132+
writeln!(
133+
printer.out,
134+
"{status: >3} {rela_path}",
135+
status = "?",
136+
rela_path = entry.rela_path
137+
)?;
138+
}
94139

95140
if outcome.entries_to_update != 0 && allow_write {
96141
{
@@ -115,6 +160,7 @@ pub fn show(
115160

116161
if statistics {
117162
writeln!(err, "{outcome:#?}").ok();
163+
writeln!(err, "{walk_outcome:#?}").ok();
118164
}
119165

120166
writeln!(err, "\nhead -> index and untracked files aren't implemented yet")?;

0 commit comments

Comments
 (0)