Skip to content

Commit

Permalink
feat: add Reference::follow_to_object()
Browse files Browse the repository at this point in the history
It's an equivalent to `git2::Reference::resolve()`.`
  • Loading branch information
Byron committed Aug 21, 2024
1 parent 6c6f946 commit d986b2b
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 1 deletion.
18 changes: 18 additions & 0 deletions gix/src/reference/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,24 @@ pub mod peel {
}
}

///
#[allow(clippy::empty_docs)]
pub mod follow {
///
#[allow(clippy::empty_docs)]
pub mod to_object {
/// The error returned by [`Reference::follow_to_object(…)`](crate::Reference::follow_to_object()).
#[derive(Debug, thiserror::Error)]
#[allow(missing_docs)]
pub enum Error {
#[error(transparent)]
FollowToObject(#[from] gix_ref::peel::to_object::Error),
#[error(transparent)]
PackedRefsOpen(#[from] gix_ref::packed::buffer::open::Error),
}
}
}

///
#[allow(clippy::empty_docs)]
pub mod head_id {
Expand Down
29 changes: 28 additions & 1 deletion gix/src/reference/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub mod iter;
pub mod remote;

mod errors;
pub use errors::{edit, find, head_commit, head_id, head_tree_id, peel};
pub use errors::{edit, find, follow, head_commit, head_id, head_tree_id, peel};

use crate::ext::ObjectIdExt;

Expand Down Expand Up @@ -153,6 +153,33 @@ impl<'repo> Reference<'repo> {
Ok(target.object()?.peel_to_kind(kind)?)
}

/// Follow all symbolic references we point to up to the first object, which is typically (but not always) a tag,
/// returning its id.
/// After this call, this ref will be pointing to an object directly, but may still not consider itself 'peeled' unless
/// a symbolic target ref was looked up from packed-refs.
#[doc(alias = "resolve", alias = "git2")]
pub fn follow_to_object(&mut self) -> Result<Id<'repo>, follow::to_object::Error> {
let packed = self.repo.refs.cached_packed_buffer().map_err(|err| {
follow::to_object::Error::FollowToObject(gix_ref::peel::to_object::Error::Follow(
file::find::existing::Error::Find(file::find::Error::PackedOpen(err)),
))
})?;
self.follow_to_object_packed(packed.as_ref().map(|p| &***p))
}

/// Like [`follow_to_object`](Self::follow_to_object), but can be used for repeated calls as it won't
/// look up `packed` each time, but can reuse it instead.
#[doc(alias = "resolve", alias = "git2")]
pub fn follow_to_object_packed(
&mut self,
packed: Option<&gix_ref::packed::Buffer>,
) -> Result<Id<'repo>, follow::to_object::Error> {
Ok(self
.inner
.follow_to_object_in_place_packed(&self.repo.refs, packed)?
.attach(self.repo))
}

/// Follow this symbolic reference one level and return the ref it refers to.
///
/// Returns `None` if this is not a symbolic reference, hence the leaf of the chain.
Expand Down
18 changes: 18 additions & 0 deletions gix/tests/reference/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,24 @@ mod find {
);
assert_eq!(tag_ref.peel_to_commit()?.id, obj.id);

let mut tag_ref = repo.find_reference("dt3")?;
assert_eq!(
tag_ref.follow_to_object()?,
first_tag_id,
"it's similar to peel_to_kind(), but provides the id instead"
);
assert_eq!(tag_ref.follow_to_object()?, first_tag_id, "it's idempotent");
assert_eq!(
tag_ref.target().id(),
first_tag_id,
"it now points to the first tag as well"
);
assert_eq!(
tag_ref.inner.peeled,
Some(target_commit_id),
"as it was read from a packed-ref, it contains peeling information nonetheless"
);

Ok(())
}

Expand Down

0 comments on commit d986b2b

Please sign in to comment.