From cd8fabf583e75f59feda7a78b8710f26a8200cbb Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 16 Jan 2025 10:01:48 +0100 Subject: [PATCH] fix: `Repository::status()` detects files added to the index in an unborn repository. (#1770) Previously it wouldn't show them. --- gix/src/repository/impls.rs | 17 ++++++++++++ gix/src/repository/index.rs | 2 +- gix/src/status/iter/mod.rs | 2 +- .../generated-archives/make_status_repos.tar | Bin 216576 -> 262656 bytes gix/tests/fixtures/make_status_repos.sh | 8 +++++- gix/tests/gix/repository/object.rs | 26 ++++++++++++++++++ gix/tests/gix/status.rs | 23 ++++++++++++++++ 7 files changed, 75 insertions(+), 3 deletions(-) diff --git a/gix/src/repository/impls.rs b/gix/src/repository/impls.rs index f528cda2860..cbf0d64ef61 100644 --- a/gix/src/repository/impls.rs +++ b/gix/src/repository/impls.rs @@ -1,3 +1,4 @@ +use gix_hash::ObjectId; use gix_object::Exists; use std::ops::DerefMut; @@ -129,6 +130,12 @@ impl gix_object::Write for crate::Repository { impl gix_object::FindHeader for crate::Repository { fn try_header(&self, id: &gix_hash::oid) -> Result, gix_object::find::Error> { + if id == ObjectId::empty_tree(self.object_hash()) { + return Ok(Some(gix_object::Header { + kind: gix_object::Kind::Tree, + size: 0, + })); + } self.objects.try_header(id) } } @@ -139,12 +146,22 @@ impl gix_object::Find for crate::Repository { id: &gix_hash::oid, buffer: &'a mut Vec, ) -> Result>, gix_object::find::Error> { + if id == ObjectId::empty_tree(self.object_hash()) { + buffer.clear(); + return Ok(Some(gix_object::Data { + kind: gix_object::Kind::Tree, + data: &[], + })); + } self.objects.try_find(id, buffer) } } impl gix_object::Exists for crate::Repository { fn exists(&self, id: &gix_hash::oid) -> bool { + if id == ObjectId::empty_tree(self.object_hash()) { + return true; + } self.objects.exists(id) } } diff --git a/gix/src/repository/index.rs b/gix/src/repository/index.rs index 092882d0631..cfd319b985b 100644 --- a/gix/src/repository/index.rs +++ b/gix/src/repository/index.rs @@ -140,7 +140,7 @@ impl crate::Repository { /// Note that this is an expensive operation as it requires recursively traversing the entire tree to unpack it into the index. pub fn index_from_tree(&self, tree: &gix_hash::oid) -> Result { Ok(gix_index::File::from_state( - gix_index::State::from_tree(tree, &self.objects, self.config.protect_options()?).map_err(|err| { + gix_index::State::from_tree(tree, self, self.config.protect_options()?).map_err(|err| { super::index_from_tree::Error::IndexFromTree { id: tree.into(), source: err, diff --git a/gix/src/status/iter/mod.rs b/gix/src/status/iter/mod.rs index f4d58b2a7af..971297f6ee7 100644 --- a/gix/src/status/iter/mod.rs +++ b/gix/src/status/iter/mod.rs @@ -53,7 +53,7 @@ where crate::head::peel::to_object::Error::Unborn { .. }, ), ), - )) => None, + )) => Some(gix_hash::ObjectId::empty_tree(self.repo.object_hash())), Err(err) => return Err(err.into()), }, Some(Some(tree_id)) => Some(tree_id), diff --git a/gix/tests/fixtures/generated-archives/make_status_repos.tar b/gix/tests/fixtures/generated-archives/make_status_repos.tar index e8789ea33c06d4b544f067b5dbb6c7c8cecc77c7..7cdb86119ddaee839fb179c059270436e1263219 100644 GIT binary patch delta 1687 zcmZvdZ)jUp7{>2=ZqhbclHIsSJE&o-r8qX1bMD`!jDln9I*qQ*t_s@Cw)b}Fl-56) z3_o?#RVnx(MjFw9pkXTr(k(T&j8UgBQKqv)Kj=W2bKo4AZgT}cIO;w3-gBGk{g52U z{hjAL&wJkcX8c%m{54@F8fkpvtI1HcC9~gMf#U>}xOKkJ8tF_dPCfDSgz(;9O+}x6;+wdb_^RdZjbb_U8xFFMs)U7aYpR`#*kr zTmRri+1+|Iybv7Fbwe+Fmf7>xbfA!J!a*WoPO*N_P51;t-~dIT0=I9WHSkEOH!|us#hx z?(4Yt$R9%;2jAQ*#UJ~<=chGSZ*Yz+>oLbAbJre!uG(Te-O>5#ly>Har^ZHl%z;h( zJ1{j1Vdj61`4@0d^N)DiL5kS}hy+yCC!%nMA*TTctx$f3b+n8v3ANEKGwQNsiYVd=wJT7^)UGk^7{WnG^5k|r3})s! z%zJlTWnh*1Q<$O&Hz33_wVMnoS!ya{%CIX1CcX`qJheLvyhH5~uL~9-RL{izVayB_ z!)^o99Mu-;kQ_lNKsnD8hHd8hTT(@Iu6QS|HS z-Asx0y`(69Oz#TDs(H;6xz`>usm=RGa;dSw1IAG9rIen|$G2NkrYQ4&_YJcbByX-v8e6sO> z15hHWyOCaZ{m|HG&KS*=A8h{=^6NS(vk*N+=XgVV*Nb!_($)P7c)i# zLu+*(9xdjE(ew92j!sptSI+kZTLyofj#Zxg?zkB*K^Q7oG;ygo(aa0=M3z*ycd3Kb ZL`iE3meaEMz`@axLtgaV$GiB3e*w1NE;axF delta 257 zcmZo@5onmhyMdQSy#2>9)5zm~=}?-HfkA*tsQve36&^bgmD88M-P`Z3u)Nv%%gjS3 zJ}IOJP28^7!`Q{RiI4XRNUKG!oi9i$h=yqGFrTdQ$WG)?i<)Qk{hS38mQMNp|M7wS zMhoXng=&4mbzwVK1{3opkO9UeS5|-w0MSspcTQK4VzvZJhCba4mITsJ$?eliq?ijt zv_zSMm-cdgerZ~oTRC|N%SX>SVw(^8a4>F@VQ#y{Xu7?92XiGOuaSkBk(s5jk#1>T SW(COl`-~G6M3((x<^TY7d1added + git add added +) diff --git a/gix/tests/gix/repository/object.rs b/gix/tests/gix/repository/object.rs index 87b5a0bf72e..177c75beabe 100644 --- a/gix/tests/gix/repository/object.rs +++ b/gix/tests/gix/repository/object.rs @@ -1,6 +1,32 @@ use crate::util::named_subrepo_opts; use gix_testtools::tempfile; +mod object_database_impl { + use gix_object::{Exists, Find, FindHeader}; + + #[test] + fn empty_tree_is_always_present() -> crate::Result { + let repo = crate::named_subrepo_opts("make_basic_repo.sh", "unborn", gix::open::Options::isolated())?; + let empty_tree = gix::ObjectId::empty_tree(repo.object_hash()); + assert!(repo.exists(&empty_tree)); + assert_eq!( + repo.try_header(&empty_tree)?.expect("tree present"), + gix_object::Header { + kind: gix_object::Kind::Tree, + size: 0 + } + ); + let mut buf = repo.empty_reusable_buffer(); + buf.push(42); + assert_eq!( + repo.try_find(&empty_tree, &mut buf)?.expect("tree present").kind, + gix_object::Kind::Tree + ); + assert_eq!(buf.len(), 0, "the data in the buffer matches the empty tree"); + Ok(()) + } +} + #[cfg(feature = "tree-editor")] mod edit_tree { use crate::util::hex_to_id; diff --git a/gix/tests/gix/status.rs b/gix/tests/gix/status.rs index be32c667382..e8352323a17 100644 --- a/gix/tests/gix/status.rs +++ b/gix/tests/gix/status.rs @@ -113,6 +113,29 @@ mod into_iter { Ok(()) } + #[test] + fn untracked_added() -> crate::Result { + let repo = repo("untracked-added")?; + let mut status = repo.status(gix::progress::Discard)?.into_iter(None)?; + let mut items: Vec<_> = status.by_ref().filter_map(Result::ok).collect(); + items.sort_by(|a, b| a.location().cmp(b.location())); + insta::assert_debug_snapshot!(items, @r#" + [ + TreeIndex( + Addition { + location: "added", + index: 0, + entry_mode: Mode( + FILE, + ), + id: Sha1(d95f3ad14dee633a758d2e331151e950dd13e4ed), + }, + ), + ] + "#); + Ok(()) + } + #[test] fn error_during_tree_traversal_causes_failure() -> crate::Result { let repo = repo("untracked-only")?;