Skip to content

Commit 3af94f9

Browse files
authored
Merge pull request #1736 from GitoxideLabs/fix-status
handle status when dir is replaced with file
2 parents 8fd53bc + f3b76d0 commit 3af94f9

File tree

5 files changed

+58
-4
lines changed

5 files changed

+58
-4
lines changed

gix-fs/src/lib.rs

+12
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,18 @@ pub fn is_executable(metadata: &std::fs::Metadata) -> bool {
8383
(metadata.mode() & 0o100) != 0
8484
}
8585

86+
/// Classifiers for IO-errors.
87+
pub mod io_err {
88+
use std::io::ErrorKind;
89+
90+
/// Return `true` if `err` indicates that the entry doesn't exist on disk. `raw` is used as well
91+
/// for additional checks while the variants are outside the MSRV.
92+
pub fn is_not_found(err: ErrorKind, raw_err: Option<i32>) -> bool {
93+
// TODO: use variant once MSRV is 1.83
94+
err == ErrorKind::NotFound || raw_err == Some(20)
95+
}
96+
}
97+
8698
#[cfg(not(unix))]
8799
/// Returns whether a a file has the executable permission set.
88100
pub fn is_executable(_metadata: &std::fs::Metadata) -> bool {

gix-status/src/index_as_worktree/function.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -356,8 +356,10 @@ impl<'index> State<'_, 'index> {
356356
{
357357
let worktree_path = match self.path_stack.verified_path(gix_path::from_bstr(rela_path).as_ref()) {
358358
Ok(path) => path,
359-
Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(Some(Change::Removed.into())),
360-
Err(err) => return Err(Error::Io(err)),
359+
Err(err) if gix_fs::io_err::is_not_found(err.kind(), err.raw_os_error()) => {
360+
return Ok(Some(Change::Removed.into()))
361+
}
362+
Err(err) => return Err(err.into()),
361363
};
362364
self.symlink_metadata_calls.fetch_add(1, Ordering::Relaxed);
363365
let metadata = match gix_index::fs::Metadata::from_path_no_follow(worktree_path) {
@@ -379,7 +381,9 @@ impl<'index> State<'_, 'index> {
379381
}
380382
}
381383
Ok(metadata) => metadata,
382-
Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(Some(Change::Removed.into())),
384+
Err(err) if gix_fs::io_err::is_not_found(err.kind(), err.raw_os_error()) => {
385+
return Ok(Some(Change::Removed.into()))
386+
}
383387
Err(err) => {
384388
return Err(err.into());
385389
}
@@ -539,7 +543,7 @@ where
539543
// conversion to bstr can never fail because symlinks are only used
540544
// on unix (by git) so no reason to use the try version here
541545
let symlink_path =
542-
gix_path::to_unix_separators_on_windows(gix_path::into_bstr(std::fs::read_link(self.path)?));
546+
gix_path::to_unix_separators_on_windows(gix_path::into_bstr(std::fs::read_link(self.path).unwrap()));
543547
self.buf.extend_from_slice(&symlink_path);
544548
self.worktree_bytes.fetch_add(self.buf.len() as u64, Ordering::Relaxed);
545549
Stream {
Binary file not shown.

gix-status/tests/fixtures/status_many.sh

+13
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,16 @@ cp -R changed-and-untracked changed-and-untracked-and-renamed
3939
echo change >> content-with-rewrite
4040

4141
)
42+
43+
cp -R changed-and-untracked replace-dir-with-file
44+
(cd replace-dir-with-file
45+
git checkout executable
46+
rm untracked dir/untracked
47+
48+
mkdir dir/sub
49+
touch dir/sub/nested
50+
git add dir && git commit -m "add file in sub-directory"
51+
52+
rm -Rf dir/
53+
touch dir
54+
)

gix-status/tests/status/index_as_worktree.rs

+25
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,31 @@ fn removed() {
243243
);
244244
}
245245

246+
#[test]
247+
fn replace_dir_with_file() {
248+
let out = fixture_filtered_detailed(
249+
"status_many",
250+
"replace-dir-with-file",
251+
&[],
252+
&[
253+
(BStr::new(b"dir/content"), 0, status_removed()),
254+
(BStr::new(b"dir/content2"), 1, status_removed()),
255+
(BStr::new(b"dir/sub/nested"), 2, status_removed()),
256+
],
257+
|_| {},
258+
false,
259+
);
260+
assert_eq!(
261+
out,
262+
Outcome {
263+
entries_to_process: 5,
264+
entries_processed: 5,
265+
symlink_metadata_calls: if cfg!(windows) { 5 } else { 4 },
266+
..Default::default()
267+
}
268+
);
269+
}
270+
246271
#[test]
247272
fn subomdule_nochange() {
248273
assert_eq!(

0 commit comments

Comments
 (0)