Skip to content

Commit

Permalink
fix: rev-spec parsing can now handle the empty tree as full hex hash. (
Browse files Browse the repository at this point in the history
…#470)

Even though the empty-tree object can be found when searched via
`Repository::find_object()`, previously it was not locatable when
used during rev-spec parsing.
  • Loading branch information
Byron committed Sep 19, 2022
1 parent 9d01fb4 commit ae38660
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 11 deletions.
11 changes: 10 additions & 1 deletion git-repository/src/revision/spec/parse/delegate/revision.rs
Expand Up @@ -40,7 +40,16 @@ impl<'repo> delegate::Revision for Delegate<'repo> {
self.last_call_was_disambiguate_prefix[self.idx] = true;
let mut candidates = Some(HashSet::default());
self.prefix[self.idx] = Some(prefix);
match self.repo.objects.lookup_prefix(prefix, candidates.as_mut()) {

let empty_tree_id = git_hash::ObjectId::empty_tree(prefix.as_oid().kind());
let res = if prefix.as_oid() == empty_tree_id {
candidates.as_mut().expect("set").insert(empty_tree_id);
Ok(Some(Err(())))
} else {
self.repo.objects.lookup_prefix(prefix, candidates.as_mut())
};

match res {
Err(err) => {
self.err.push(object::find::existing::Error::Find(err).into());
None
Expand Down
Git LFS file not shown
Git LFS file not shown
18 changes: 18 additions & 0 deletions git-repository/tests/fixtures/make_diff_repo.sh
@@ -0,0 +1,18 @@
#!/bin/bash
set -eu -o pipefail

git init -q

git checkout -b main
mkdir dir
touch a b dir/c
git add .
git commit -q -m c1

echo a >> a
echo b >> b
echo dir/c >> dir/c
git commit -q -am c2

echo a1 >> a
git commit -q -am c3
1 change: 1 addition & 0 deletions git-repository/tests/fixtures/make_rev_spec_parse_repos.sh
Expand Up @@ -389,6 +389,7 @@ git init complex_graph

baseline "@^{tree}"
baseline "@:"
baseline "4b825dc642cb6eb9a060e54bf8d69288fbee4904"
)

git init new
Expand Down
27 changes: 19 additions & 8 deletions git-repository/tests/object/tree.rs
@@ -1,5 +1,5 @@
mod diff {
use crate::remote;
use crate::named_repo;
use git_object::bstr::ByteSlice;
use git_object::tree::EntryMode;
use git_repository as git;
Expand All @@ -8,9 +8,9 @@ mod diff {

#[test]
fn changes_against_tree_modified() {
let repo = remote::repo("base");
let from = tree_named(&repo, "g");
let to = tree_named(&repo, "h");
let repo = named_repo("make_diff_repo.sh").unwrap();
let from = tree_named(&repo, "@^{/c3}~1");
let to = tree_named(&repo, ":/c3");
from.changes()
.for_each_to_obtain_tree(&to, |change| -> Result<_, Infallible> {
assert_eq!(change.location, "", "without configuration the location field is empty");
Expand All @@ -23,22 +23,33 @@ mod diff {
} => {
assert_eq!(previous_entry_mode, EntryMode::Blob);
assert_eq!(entry_mode, EntryMode::Blob);
assert_eq!(previous_id.object().unwrap().data.as_bstr(), "g\n");
assert_eq!(id.object().unwrap().data.as_bstr(), "h\n");
assert_eq!(previous_id.object().unwrap().data.as_bstr(), "a\n");
assert_eq!(id.object().unwrap().data.as_bstr(), "a\na1\n");
Ok(Default::default())
}
Event::Deletion { .. } | Event::Addition { .. } => unreachable!("only modification is expected"),
}
})
.unwrap();
}
#[test]
fn changes_against_tree_with_filename_tracking() {
let repo = named_repo("make_diff_repo.sh").unwrap();
let from = tree_named(
&repo,
&git::hash::ObjectId::empty_tree(git::hash::Kind::Sha1).to_string(),
);
let to = tree_named(&repo, ":/c1");

let mut expected = vec!["a", "b", "c"];
from.changes()
.track_filename()
.for_each_to_obtain_tree(&to, |change| -> Result<_, Infallible> {
assert_eq!(change.location, "file");
Ok(git::object::tree::diff::Action::Continue)
expected.retain(|name| name != change.location);
Ok(Default::default())
})
.unwrap();
assert_eq!(expected, Vec::<&str>::new(), "all paths should have been seen")
}

fn tree_named<'repo>(repo: &'repo git::Repository, rev_spec: &str) -> git::Tree<'repo> {
Expand Down
9 changes: 9 additions & 0 deletions git-repository/tests/revision/spec/from_bytes/mod.rs
Expand Up @@ -123,3 +123,12 @@ fn access_blob_through_tree() {
"Could not find path \"missing\" in tree 0000000000c of parent object 0000000000c"
);
}

#[test]
fn empty_tree_as_full_name() {
let repo = repo("complex_graph").unwrap();
assert_eq!(
parse_spec("4b825dc642cb6eb9a060e54bf8d69288fbee4904", &repo).unwrap(),
Spec::from_id(hex_to_id("4b825dc642cb6eb9a060e54bf8d69288fbee4904").attach(&repo))
);
}

0 comments on commit ae38660

Please sign in to comment.