Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion gix/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ max-control = ["parallel", "pack-cache-lru-static", "pack-cache-lru-dynamic"]
## on some platforms.
## Note that this configuration still uses a pure Rust zlib implementation which isn't the fastest compared to its C-alternatives.
## No C toolchain is involved.
max-performance-safe = ["max-control", "parallel-walkdir"]
max-performance-safe = ["max-control"]

## If set, walkdir iterators will be multi-threaded which affects the listing of loose objects and references.
## Note, however, that this will use `rayon` under the hood and spawn threads for each traversal to avoid a global rayon thread pool.
Expand Down
14 changes: 14 additions & 0 deletions gix/src/reference/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,20 @@ impl<'repo> Reference<'repo> {
Ok(Id::from_id(oid, self.repo))
}

/// Follow all symbolic targets this reference might point to and peel the underlying object
/// to the end of the chain, and return it, reusing the `packed` buffer if available.
///
/// This is useful to learn where this reference is ultimately pointing to.
pub fn peel_to_id_in_place_packed(
&mut self,
packed: Option<&gix_ref::packed::Buffer>,
) -> Result<Id<'repo>, peel::Error> {
let oid = self
.inner
.peel_to_id_in_place_packed(&self.repo.refs, &self.repo.objects, packed)?;
Ok(Id::from_id(oid, self.repo))
}

/// Similar to [`peel_to_id_in_place()`][Reference::peel_to_id_in_place()], but consumes this instance.
pub fn into_fully_peeled_id(mut self) -> Result<Id<'repo>, peel::Error> {
self.peel_to_id_in_place()
Expand Down
30 changes: 27 additions & 3 deletions gix/src/reference/remote.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::bstr::ByteSlice;
use crate::repository::{branch_remote_ref_name, branch_remote_tracking_ref_name};
use crate::{remote, Reference};
use gix_ref::FullNameRef;
use gix_ref::{Category, FullNameRef};
use std::borrow::Cow;

/// Remotes
Expand All @@ -9,8 +10,31 @@ impl<'repo> Reference<'repo> {
/// Return `None` if no remote is configured.
///
/// See also [`Repository::branch_remote_name()`](crate::Repository::branch_remote_name()) for more details.
pub fn remote_name(&self, direction: remote::Direction) -> Option<remote::Name<'repo>> {
self.repo.branch_remote_name(self.name().shorten(), direction)
pub fn remote_name(&self, direction: remote::Direction) -> Option<remote::Name<'_>> {
let (category, shortname) = self.name().category_and_short_name()?;
match category {
Category::RemoteBranch => {
if shortname.find_iter("/").take(2).count() == 1 {
let slash_pos = shortname.find_byte(b'/').expect("it was just found");
shortname[..slash_pos]
.as_bstr()
.to_str()
.ok()
.map(|n| remote::Name::Symbol(n.into()))
} else {
let remotes = self.repo.remote_names();
for slash_pos in shortname.rfind_iter("/") {
let candidate = shortname[..slash_pos].as_bstr();
if remotes.contains(candidate) {
return candidate.to_str().ok().map(|n| remote::Name::Symbol(n.into()));
}
}
None
}
}
Category::LocalBranch => self.repo.branch_remote_name(shortname, direction),
_ => None,
}
}

/// Find the remote along with all configuration associated with it suitable for handling this reference.
Expand Down
7 changes: 5 additions & 2 deletions gix/src/remote/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::borrow::Cow;

use crate::bstr::BStr;
use std::borrow::Cow;
use std::collections::BTreeSet;

/// The direction of an operation carried out (or to be carried out) through a remote.
#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)]
Expand Down Expand Up @@ -31,6 +31,9 @@ pub enum Name<'repo> {
Url(Cow<'repo, BStr>),
}

/// A type-definition for a sorted list of unvalidated remote names - they have been read straight from the configuration.
pub type Names<'a> = BTreeSet<Cow<'a, BStr>>;

///
#[allow(clippy::empty_docs)]
pub mod name;
Expand Down
4 changes: 2 additions & 2 deletions gix/src/repository/config/remote.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::bstr::BStr;
use std::{borrow::Cow, collections::BTreeSet};
use std::borrow::Cow;

use crate::config::tree::{Remote, Section};
use crate::remote;
Expand All @@ -8,7 +8,7 @@ use crate::remote;
impl crate::Repository {
/// Returns a sorted list unique of symbolic names of remotes that
/// we deem [trustworthy][crate::open::Options::filter_config_section()].
pub fn remote_names(&self) -> BTreeSet<Cow<'_, BStr>> {
pub fn remote_names(&self) -> remote::Names<'_> {
self.config
.resolved
.sections_by_name(Remote.name())
Expand Down
Binary file not shown.
10 changes: 10 additions & 0 deletions gix/tests/fixtures/make_remote_config_repos.sh
Original file line number Diff line number Diff line change
Expand Up @@ -131,3 +131,13 @@ EOF
pushDefault = push-origin
EOF
)

git clone fetch multiple-remotes
(cd multiple-remotes
git remote add other ../fetch && git fetch other
git remote add with/two/slashes ../fetch && git fetch with/two/slashes
git remote add with/two ../fetch && git fetch with/two

git checkout -b main --track origin/main
git checkout -b other-main --track other/main
)
27 changes: 27 additions & 0 deletions gix/tests/reference/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use gix::remote::Direction;

mod log {

#[test]
Expand All @@ -17,6 +19,31 @@ mod log {
);
}
}

#[test]
fn remote_name() -> crate::Result {
let repo = crate::named_subrepo_opts(
"make_remote_config_repos.sh",
"multiple-remotes",
gix::open::Options::isolated(),
)?;
for (ref_name, expected_remote) in [
("main", "origin"),
("other-main", "other"),
("refs/remotes/origin/main", "origin"),
("refs/remotes/other/main", "other"),
("with/two/slashes/main", "with/two/slashes"),
("with/two/main", "with/two"),
] {
let r = repo.find_reference(ref_name)?;
assert_eq!(
r.remote_name(Direction::Fetch).map(|name| name.as_bstr().to_owned()),
Some(expected_remote.into())
);
}
Ok(())
}

mod find {
use gix_ref as refs;
use gix_ref::{FullName, FullNameRef, Target};
Expand Down