History

Merge branch 'status'

Sebastian Thiel committed 2 years ago

Commit 45edd2e2 parents 52efa90 2e06a0020 files · +136 −58Browse files

Unified · Split

20 files
  1. gitoxide-core/src/index/information.rs +5 −5
  2. gitoxide-core/src/repository/attributes/validate_baseline.rs +7 −0
  3. gitoxide-core/src/repository/index/entries.rs +5 −5
  4. gix-config/src/file/includes/mod.rs +8 −1
  5. gix-config/src/file/includes/types.rs +5 −2
  6. gix-index/src/access/mod.rs +10 −9
  7. gix-index/src/entry/flags.rs +17 −0
  8. gix-index/src/entry/mod.rs +27 −2
  9. gix-index/src/extension/fs_monitor.rs +1 −0
  10. gix-index/src/lib.rs +5 −5
  11. gix-index/tests/index/access.rs +10 −9
  12. gix-status/src/index_as_worktree/function.rs +4 −4
  13. gix-worktree/src/stack/platform.rs +1 −0
  14. gix-worktree/src/stack/state/mod.rs +1 −1
  15. gix/src/attribute_stack.rs +1 −0
  16. gix/src/repository/attributes.rs +1 −0
  17. gix/src/repository/index.rs +5 −0
  18. gix/src/revision/spec/parse/delegate/navigate.rs +14 −8
  19. gix/src/revision/spec/parse/types.rs +1 −1
  20. gix/src/status/index_worktree.rs +8 −6
gitoxide-core/src/index/information.rs+5−5
@@ -6,6 +6,7 @@ pub struct Options { · 5 unmodified lines
66
77 #[cfg(feature = "serde")]
88 mod serde_only {
9+ use gix::index::entry::Stage;
910
1011 mod ext {
1112 #[derive(serde::Serialize)]
@@ -115,11 +116,10 @@ mod serde_only { · 103 unmodified lines
115116 let (mut intent_to_add, mut skip_worktree) = (0, 0);
116117 for entry in f.entries() {
117118 match entry.flags.stage() {
118− 0 => stage_0_merged += 1,
119− 1 => stage_1_base += 1,
120− 2 => stage_2_ours += 1,
121− 3 => stage_3_theirs += 1,
122− invalid => anyhow::bail!("Invalid stage {} encountered", invalid),
119+ Stage::Unconflicted => stage_0_merged += 1,
120+ Stage::Base => stage_1_base += 1,
121+ Stage::Ours => stage_2_ours += 1,
122+ Stage::Theirs => stage_3_theirs += 1,
123123 }
124124 match entry.mode {
125125 gix::index::entry::Mode::DIR => dir += 1,
gitoxide-core/src/repository/attributes/validate_baseline.rs+7−0
@@ -262,6 +262,8 @@ pub(crate) mod function { · 261 unmodified lines
262262 }
263263
264264 #[derive(Debug)]
265+ // See note on `Mismatch`
266+ #[allow(dead_code)]
265267 pub struct ExcludeLocation {
266268 pub line: usize,
267269 pub rela_source_file: String,
@@ -269,6 +271,9 @@ pub(crate) mod function { · 1 unmodified line
269271 }
270272
271273 #[derive(Debug)]
274+ // We debug-print this structure, which makes all fields 'used', but it doesn't count.
275+ // TODO: find a way to not have to do more work, but make the warning go away.
276+ #[allow(dead_code)]
272277 pub enum Mismatch {
273278 Attributes {
274279 actual: Vec<gix::attrs::Assignment>,
@@ -281,6 +286,8 @@ pub(crate) mod function { · 6 unmodified lines
281286 }
282287
283288 #[derive(Debug)]
289+ // See note on `Mismatch`
290+ #[allow(dead_code)]
284291 pub struct ExcludeMatch {
285292 pub pattern: gix::glob::Pattern,
286293 pub source: Option<PathBuf>,
gitoxide-core/src/repository/index/entries.rs+5−5
@@ -23,6 +23,7 @@ pub(crate) mod function { · 22 unmodified lines
2323 io::{BufWriter, Write},
2424 };
2525
26+ use gix::index::entry::Stage;
2627 use gix::{
2728 bstr::{BStr, BString},
2829 worktree::IndexPersistedOrInMemory,
@@ -392,11 +393,10 @@ pub(crate) mod function { · 363 unmodified lines
392393 out,
393394 "{} {}{:?} {} {}{}{}",
394395 match entry.flags.stage() {
395− 0 => " ",
396− 1 => "BASE ",
397− 2 => "OURS ",
398− 3 => "THEIRS ",
399− _ => "UNKNOWN",
396+ Stage::Unconflicted => " ",
397+ Stage::Base => "BASE ",
398+ Stage::Ours => "OURS ",
399+ Stage::Theirs => "THEIRS ",
400400 },
401401 if entry.flags.is_empty() {
402402 "".to_string()
gix-config/src/file/includes/mod.rs+8−1
@@ -99,7 +99,14 @@ fn append_followed_includes_recursively( · 98 unmodified lines
9999 }
100100
101101 buf.clear();
102− std::io::copy(&mut std::fs::File::open(&config_path)?, buf)?;
102+ std::io::copy(
103+ &mut std::fs::File::open(&config_path).map_err(|err| Error::Io {
104+ source: err,
105+ path: config_path.to_owned(),
106+ })?,
107+ buf,
108+ )
109+ .map_err(Error::CopyBuffer)?;
103110 let config_meta = Metadata {
104111 path: Some(config_path),
105112 trust: meta.trust,
gix-config/src/file/includes/types.rs+5−2
@@ -1,11 +1,14 @@
11 use crate::{parse, path::interpolate};
2+use std::path::PathBuf;
23
34 /// The error returned when following includes.
45 #[derive(Debug, thiserror::Error)]
56 #[allow(missing_docs)]
67 pub enum Error {
7− #[error(transparent)]
8− Io(#[from] std::io::Error),
8+ #[error("Failed to copy configuration file into buffer")]
9+ CopyBuffer(#[source] std::io::Error),
10+ #[error("Could not read included configuration file at '{}'", path.display())]
11+ Io { path: PathBuf, source: std::io::Error },
912 #[error(transparent)]
1013 Parse(#[from] parse::Error),
1114 #[error(transparent)]
gix-index/src/access/mod.rs+10−9
@@ -3,6 +3,7 @@ use std::{cmp::Ordering, ops::Range}; · 2 unmodified lines
33 use bstr::{BStr, ByteSlice, ByteVec};
44 use filetime::FileTime;
55
6+use crate::entry::{Stage, StageRaw};
67 use crate::{entry, extension, AccelerateLookup, Entry, PathStorage, PathStorageRef, State, Version};
78
89 // TODO: integrate this somehow, somewhere, depending on later usage.
@@ -81,7 +82,7 @@ impl State { · 72 unmodified lines
8182 res
8283 })
8384 .ok()?;
84− self.entry_index_by_idx_and_stage(path, idx, stage, stage_cmp)
85+ self.entry_index_by_idx_and_stage(path, idx, stage as StageRaw, stage_cmp)
8586 }
8687
8788 /// Walk as far in `direction` as possible, with [`Ordering::Greater`] towards higher stages, and [`Ordering::Less`]
@@ -112,7 +113,7 @@ impl State { · 24 unmodified lines
112113 &self,
113114 path: &BStr,
114115 idx: usize,
115− wanted_stage: entry::Stage,
116+ wanted_stage: entry::StageRaw,
116117 stage_cmp: Ordering,
117118 ) -> Option<usize> {
118119 match stage_cmp {
@@ -121,7 +122,7 @@ impl State { · 2 unmodified lines
121122 .enumerate()
122123 .rev()
123124 .take_while(|(_, e)| e.path(self) == path)
124− .find_map(|(idx, e)| (e.stage() == wanted_stage).then_some(idx)),
125+ .find_map(|(idx, e)| (e.stage_raw() == wanted_stage).then_some(idx)),
125126 Ordering::Equal => Some(idx),
126127 Ordering::Less => self
127128 .entries
@@ -129,7 +130,7 @@ impl State { · 1 unmodified line
129130 .iter()
130131 .enumerate()
131132 .take_while(|(_, e)| e.path(self) == path)
132− .find_map(|(ofs, e)| (e.stage() == wanted_stage).then_some(idx + ofs + 1)),
133+ .find_map(|(ofs, e)| (e.stage_raw() == wanted_stage).then_some(idx + ofs + 1)),
133134 }
134135 }
135136
@@ -291,7 +292,7 @@ impl State { · 155 unmodified lines
291292 .binary_search_by(|e| {
292293 let res = e.path(self).cmp(path);
293294 if res.is_eq() {
294− stage_at_index = e.stage();
295+ stage_at_index = e.stage_raw();
295296 }
296297 res
297298 })
@@ -299,7 +300,7 @@ impl State { · 1 unmodified line
299300 let idx = if stage_at_index == 0 || stage_at_index == 2 {
300301 idx
301302 } else {
302− self.entry_index_by_idx_and_stage(path, idx, 2, stage_at_index.cmp(&2))?
303+ self.entry_index_by_idx_and_stage(path, idx, Stage::Ours as StageRaw, stage_at_index.cmp(&2))?
303304 };
304305 Some(&self.entries[idx])
305306 }
@@ -334,13 +335,13 @@ impl State { · 28 unmodified lines
334335 + self.entries[low..].partition_point(|e| e.path(self).get(..prefix_len).map_or(false, |p| p <= prefix));
335336
336337 let low_entry = &self.entries.get(low)?;
337− if low_entry.stage() != 0 {
338+ if low_entry.stage_raw() != 0 {
338339 low = self
339340 .walk_entry_stages(low_entry.path(self), low, Ordering::Less)
340341 .unwrap_or(low);
341342 }
342343 if let Some(high_entry) = self.entries.get(high) {
343− if high_entry.stage() != 0 {
344+ if high_entry.stage_raw() != 0 {
344345 high = self
345346 .walk_entry_stages(high_entry.path(self), high, Ordering::Less)
346347 .unwrap_or(high);
@@ -374,7 +375,7 @@ impl State { · 27 unmodified lines
374375 .binary_search_by(|e| {
375376 let res = e.path(self).cmp(path);
376377 if res.is_eq() {
377− stage_at_index = e.stage();
378+ stage_at_index = e.stage_raw();
378379 }
379380 res
380381 })
gix-index/src/entry/flags.rs+17−0
@@ -62,6 +62,23 @@ bitflags! { · 61 unmodified lines
6262 impl Flags {
6363 /// Return the stage as extracted from the bits of this instance.
6464 pub fn stage(&self) -> Stage {
65+ match self.stage_raw() {
66+ 0 => Stage::Unconflicted,
67+ 1 => Stage::Base,
68+ 2 => Stage::Ours,
69+ 3 => Stage::Theirs,
70+ _ => unreachable!("BUG: Flags::STAGE_MASK is two bits, whose 4 possible values we have covered"),
71+ }
72+ }
73+
74+ /// Return an entry's stage as raw number between 0 and 4.
75+ /// Possible values are:
76+ ///
77+ /// * 0 = no conflict,
78+ /// * 1 = base,
79+ /// * 2 = ours,
80+ /// * 3 = theirs
81+ pub fn stage_raw(&self) -> u32 {
6582 (*self & Flags::STAGE_MASK).bits() >> 12
6683 }
6784
gix-index/src/entry/mod.rs+27−2
@@ -1,9 +1,23 @@
1−/// The stage of an entry, one of…
1+/// The stage of an entry.
2+#[derive(Default, Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)]
3+pub enum Stage {
4+ /// This is the default, and most entries are in this stage.
5+ #[default]
6+ Unconflicted = 0,
7+ /// The entry is the common base between 'our' change and 'their' change, for comparison.
8+ Base = 1,
9+ /// The entry represents our change.
10+ Ours = 2,
11+ /// The entry represents their change.
12+ Theirs = 3,
13+}
14+
15+// The stage of an entry, one of…
216 /// * 0 = no conflict,
317 /// * 1 = base,
418 /// * 2 = ours,
519 /// * 3 = theirs
6−pub type Stage = u32;
20+pub type StageRaw = u32;
721
822 ///
923 #[allow(clippy::empty_docs)]
@@ -78,6 +92,17 @@ mod access { · 68 unmodified lines
7892 pub fn stage(&self) -> entry::Stage {
7993 self.flags.stage()
8094 }
95+
96+ /// Return an entry's stage as raw number between 0 and 4.
97+ /// Possible values are:
98+ ///
99+ /// * 0 = no conflict,
100+ /// * 1 = base,
101+ /// * 2 = ours,
102+ /// * 3 = theirs
103+ pub fn stage_raw(&self) -> u32 {
104+ self.flags.stage_raw()
105+ }
81106 }
82107 }
83108
gix-index/src/extension/fs_monitor.rs+1−0
@@ -6,6 +6,7 @@ use crate::{ · 5 unmodified lines
66 };
77
88 #[derive(Clone)]
9+#[allow(dead_code)]
910 pub enum Token {
1011 V1 { nanos_since_1970: u64 },
1112 V2 { token: BString },
gix-index/src/lib.rs+5−5
@@ -144,6 +144,7 @@ pub struct State { · 143 unmodified lines
144144 }
145145
146146 mod impls {
147+ use crate::entry::Stage;
147148 use std::fmt::{Debug, Formatter};
148149
149150 use crate::State;
@@ -155,11 +156,10 @@ mod impls { · 5 unmodified lines
155156 f,
156157 "{} {}{:?} {} {}",
157158 match entry.flags.stage() {
158− 0 => " ",
159− 1 => "BASE ",
160− 2 => "OURS ",
161− 3 => "THEIRS ",
162− _ => "UNKNOWN",
159+ Stage::Unconflicted => " ",
160+ Stage::Base => "BASE ",
161+ Stage::Ours => "OURS ",
162+ Stage::Theirs => "THEIRS ",
163163 },
164164 if entry.flags.is_empty() {
165165 "".to_string()
gix-index/tests/index/access.rs+10−9
@@ -1,5 +1,6 @@
11 use crate::index::Fixture;
22 use bstr::{BString, ByteSlice};
3+use gix_index::entry::Stage;
34
45 fn icase_fixture() -> gix_index::File {
56 Fixture::Generated("v2_icase_name_clashes").open()
@@ -11,7 +12,7 @@ fn entry_by_path() { · 5 unmodified lines
1112 for entry in file.entries() {
1213 let path = entry.path(&file);
1314 assert_eq!(file.entry_by_path(path), Some(entry));
14− assert_eq!(file.entry_by_path_and_stage(path, 0), Some(entry));
15+ assert_eq!(file.entry_by_path_and_stage(path, Stage::Unconflicted), Some(entry));
1516 }
1617 }
1718
@@ -140,27 +141,27 @@ fn entry_by_path_and_stage() { · 122 unmodified lines
140141 for entry in file.entries() {
141142 let path = entry.path(&file);
142143 assert_eq!(
143− file.entry_index_by_path_and_stage(path, 0)
144+ file.entry_index_by_path_and_stage(path, Stage::Unconflicted)
144145 .map(|idx| &file.entries()[idx]),
145146 Some(entry)
146147 );
147− assert_eq!(file.entry_by_path_and_stage(path, 0), Some(entry));
148+ assert_eq!(file.entry_by_path_and_stage(path, Stage::Unconflicted), Some(entry));
148149 }
149150 }
150151
151152 #[test]
152153 fn entry_by_path_with_conflicting_file() {
153154 let file = Fixture::Loose("conflicting-file").open();
154− for expected_stage in [1 /* common ancestor */, 2 /* ours */, 3 /* theirs */] {
155+ for expected_stage in [Stage::Base, Stage::Ours, Stage::Theirs] {
155156 assert!(
156157 file.entry_by_path_and_stage("file".into(), expected_stage).is_some(),
157− "we have no stage 0 during a conflict, but all other ones. Missed {expected_stage}"
158+ "we have no stage 0 during a conflict, but all other ones. Missed {expected_stage:?}"
158159 );
159160 }
160161
161162 assert_eq!(
162163 file.entry_by_path("file".into()).expect("found").stage(),
163− 2,
164+ Stage::Ours,
164165 "we always find our stage while in a merge"
165166 );
166167 }
@@ -226,13 +227,13 @@ fn sort_entries() { · 59 unmodified lines
226227
227228 for (idx, entry) in file.entries()[..valid_entries].iter().enumerate() {
228229 assert_eq!(
229− file.entry_index_by_path_and_stage_bounded(entry.path(&file), 0, valid_entries),
230+ file.entry_index_by_path_and_stage_bounded(entry.path(&file), Stage::Unconflicted, valid_entries),
230231 Some(idx),
231232 "we can still find entries in the correctly sorted region"
232233 );
233234 }
234235 assert_eq!(
235− file.entry_by_path_and_stage(new_entry_path, 0),
236+ file.entry_by_path_and_stage(new_entry_path, Stage::Unconflicted),
236237 None,
237238 "new entry can't be found due to incorrect order"
238239 );
@@ -241,7 +242,7 @@ fn sort_entries() { · 2 unmodified lines
241242 assert!(file.verify_entries().is_ok(), "sorting of entries restores invariants");
242243
243244 assert_eq!(
244− file.entry_by_path_and_stage(new_entry_path, 0)
245+ file.entry_by_path_and_stage(new_entry_path, Stage::Unconflicted)
245246 .expect("can be found")
246247 .path(&file),
247248 new_entry_path,
gix-status/src/index_as_worktree/function.rs+4−4
@@ -157,11 +157,11 @@ where · 156 unmodified lines
157157 let mut idx = 0;
158158 while let Some(entry) = chunk_entries.get(idx) {
159159 let absolute_entry_index = entry_offset + idx;
160− if idx == 0 && entry.stage() != 0 {
160+ if idx == 0 && entry.stage_raw() != 0 {
161161 let offset = entry_offset.checked_sub(1).and_then(|prev_idx| {
162162 let prev_entry = &all_entries[prev_idx];
163163 let entry_path = entry.path_in(state.path_backing);
164− if prev_entry.stage() == 0 || prev_entry.path_in(state.path_backing) != entry_path {
164+ if prev_entry.stage_raw() == 0 || prev_entry.path_in(state.path_backing) != entry_path {
165165 // prev_entry (in previous chunk) does not belong to our conflict
166166 return None;
167167 }
@@ -286,7 +286,7 @@ impl<'index> State<'_, 'index> { · 118 unmodified lines
286286 self.skipped_by_pathspec.fetch_add(1, Ordering::Relaxed);
287287 return None;
288288 }
289− let status = if entry.stage() != 0 {
289+ let status = if entry.stage_raw() != 0 {
290290 Ok(
291291 Conflict::try_from_entry(entries, self.path_backing, entry_index, path).map(|(conflict, offset)| {
292292 *outer_entry_index += offset; // let out loop skip over entries related to the conflict
@@ -604,7 +604,7 @@ impl Conflict { · 311 unmodified lines
604604 let mut count = 0_usize;
605605 for stage in (start_index..(start_index + 3).min(entries.len())).filter_map(|idx| {
606606 let entry = &entries[idx];
607− let stage = entry.stage();
607+ let stage = entry.stage_raw();
608608 (stage > 0 && entry.path_in(path_backing) == entry_path).then_some(stage)
609609 }) {
610610 // This could be `1 << (stage - 1)` but let's be specific.
gix-worktree/src/stack/platform.rs+1−0
@@ -20,6 +20,7 @@ impl<'a> Platform<'a> { · 19 unmodified lines
2020 /// # Panics
2121 ///
2222 /// If the cache was configured without exclude patterns.
23+ #[doc(alias = "is_path_ignored", alias = "git2")]
2324 pub fn is_excluded(&self) -> bool {
2425 self.matching_exclude_pattern()
2526 .map_or(false, |m| !m.pattern.is_negative())
gix-worktree/src/stack/state/mod.rs+1−1
@@ -131,7 +131,7 @@ impl State { · 130 unmodified lines
131131
132132 // Stage 0 means there is no merge going on, stage 2 means it's 'our' side of the merge, but then
133133 // there won't be a stage 0.
134− if entry.mode == gix_index::entry::Mode::FILE && (entry.stage() == 0 || entry.stage() == 2) {
134+ if entry.mode == gix_index::entry::Mode::FILE && (entry.stage_raw() == 0 || entry.stage_raw() == 2) {
135135 let basename = path.rfind_byte(b'/').map_or(path, |pos| path[pos + 1..].as_bstr());
136136 let ignore_source = names.iter().find_map(|t| {
137137 match case {
gix/src/attribute_stack.rs+1−0
@@ -39,6 +39,7 @@ impl<'repo> AttributeStack<'repo> { · 38 unmodified lines
3939 /// path is created as directory. If it's not known it is assumed to be a file.
4040 ///
4141 /// Provide access to cached information for that `relative` path via the returned platform.
42+ #[doc(alias = "is_path_ignored", alias = "git2")]
4243 pub fn at_path(
4344 &mut self,
4445 relative: impl AsRef<std::path::Path>,
gix/src/repository/attributes.rs+1−0
@@ -106,6 +106,7 @@ impl Repository { · 105 unmodified lines
106106 /// When only excludes are desired, this is the most efficient way to obtain them. Otherwise use
107107 /// [`Repository::attributes()`] for accessing both attributes and excludes.
108108 // TODO: test
109+ #[doc(alias = "is_path_ignored", alias = "git2")]
109110 #[cfg(feature = "excludes")]
110111 pub fn excludes(
111112 &self,
gix/src/repository/index.rs+5−0
@@ -40,6 +40,11 @@ impl crate::Repository { · 39 unmodified lines
4040 /// Return a shared worktree index which is updated automatically if the in-memory snapshot has become stale as the underlying file
4141 /// on disk has changed.
4242 ///
43+ /// ### Notes
44+ ///
45+ /// * This will fail if the file doesn't exist, like in a newly initialized repository. If that is the case, use
46+ /// [index_or_empty()](Self::index_or_empty) or [try_index()](Self::try_index) instead.
47+ ///
4348 /// The index file is shared across all clones of this repository.
4449 pub fn index(&self) -> Result<worktree::Index, worktree::open_index::Error> {
4550 self.try_index().and_then(|opt| match opt {
gix/src/revision/spec/parse/delegate/navigate.rs+14−8
@@ -1,6 +1,7 @@
11 use std::collections::HashSet;
22
33 use gix_hash::ObjectId;
4+use gix_index::entry::Stage;
45 use gix_revision::spec::parse::{
56 delegate,
67 delegate::{PeelTo, Traversal},
@@ -305,9 +306,18 @@ impl<'repo> delegate::Navigate for Delegate<'repo> { · 298 unmodified lines
305306 }
306307
307308 fn index_lookup(&mut self, path: &BStr, stage: u8) -> Option<()> {
309+ let stage = match stage {
310+ 0 => Stage::Unconflicted,
311+ 1 => Stage::Base,
312+ 2 => Stage::Ours,
313+ 3 => Stage::Theirs,
314+ _ => unreachable!(
315+ "BUG: driver will not pass invalid stages (and it uses integer to avoid gix-index as dependency)"
316+ ),
317+ };
308318 self.unset_disambiguate_call();
309319 match self.repo.index() {
310− Ok(index) => match index.entry_by_path_and_stage(path, stage.into()) {
320+ Ok(index) => match index.entry_by_path_and_stage(path, stage) {
311321 Some(entry) => {
312322 self.objs[self.idx]
313323 .get_or_insert_with(HashSet::default)
@@ -323,21 +333,17 @@ impl<'repo> delegate::Navigate for Delegate<'repo> { · 9 unmodified lines
323333 Some(())
324334 }
325335 None => {
326− let stage_hint = [0, 1, 2]
336+ let stage_hint = [Stage::Unconflicted, Stage::Base, Stage::Ours]
327337 .iter()
328338 .filter(|our_stage| **our_stage != stage)
329− .find_map(|stage| {
330− index
331− .entry_index_by_path_and_stage(path, (*stage).into())
332− .map(|_| (*stage).into())
333− });
339+ .find_map(|stage| index.entry_index_by_path_and_stage(path, *stage).map(|_| *stage));
334340 let exists = self
335341 .repo
336342 .work_dir()
337343 .map_or(false, |root| root.join(gix_path::from_bstr(path)).exists());
338344 self.err.push(Error::IndexLookup {
339345 desired_path: path.into(),
340− desired_stage: stage.into(),
346+ desired_stage: stage,
341347 exists,
342348 stage_hint,
343349 });
gix/src/revision/spec/parse/types.rs+1−1
@@ -98,7 +98,7 @@ pub enum Error { · 97 unmodified lines
9898 desired: usize,
9999 available: usize,
100100 },
101− #[error("Path {desired_path:?} did not exist in index at stage {desired_stage}{}{}", stage_hint.map(|actual|format!(". It does exist at stage {actual}")).unwrap_or_default(), exists.then(|| ". It exists on disk").unwrap_or(". It does not exist on disk"))]
101+ #[error("Path {desired_path:?} did not exist in index at stage {}{}{}", *desired_stage as u8, stage_hint.map(|actual|format!(". It does exist at stage {}", actual as u8)).unwrap_or_default(), exists.then(|| ". It exists on disk").unwrap_or(". It does not exist on disk"))]
102102 IndexLookup {
103103 desired_path: BString,
104104 desired_stage: gix_index::entry::Stage,
gix/src/status/index_worktree.rs+8−6
@@ -199,10 +199,7 @@ mod submodule_status { · 198 unmodified lines
199199 let local_repo = repo.to_thread_local();
200200 let submodule_paths = match local_repo.submodules()? {
201201 Some(sm) => {
202− let mut v: Vec<_> = sm
203− .filter(|sm| sm.is_active().unwrap_or_default())
204− .filter_map(|sm| sm.path().ok().map(Cow::into_owned))
205− .collect();
202+ let mut v: Vec<_> = sm.filter_map(|sm| sm.path().ok().map(Cow::into_owned)).collect();
206203 v.sort();
207204 v
208205 }
@@ -271,7 +268,8 @@ mod submodule_status { · 62 unmodified lines
271268 ///
272269 /// ### Submodules
273270 ///
274−/// Note that submodules can be set to 'inactive' which automatically excludes them from the status operation.
271+/// Note that submodules can be set to 'inactive', which will not exclude them from the status operation, similar to
272+/// how `git status` includes them.
275273 ///
276274 /// ### Index Changes
277275 ///
@@ -613,7 +611,10 @@ pub mod iter { · 335 unmodified lines
613611 ///
614612 /// * `patterns`
615613 /// - Optional patterns to use to limit the paths to look at. If empty, all paths are considered.
616− pub fn into_index_worktree_iter(self, patterns: Vec<BString>) -> Result<index_worktree::Iter, Error> {
614+ pub fn into_index_worktree_iter(
615+ self,
616+ patterns: impl IntoIterator<Item = BString>,
617+ ) -> Result<index_worktree::Iter, Error> {
617618 let index = match self.index {
618619 None => IndexPersistedOrInMemory::Persisted(self.repo.index_or_empty()?),
619620 Some(index) => index,
@@ -634,6 +635,7 @@ pub mod iter { · 14 unmodified lines
634635 {
635636 let (tx, rx) = std::sync::mpsc::channel();
636637 let mut collect = Collect { tx };
638+ let patterns: Vec<_> = patterns.into_iter().collect();
637639 let join = std::thread::Builder::new()
638640 .name("gix::status::index_worktree::iter::producer".into())
639641 .spawn({