From 6ac28673550ccd0b85b7fd2b191fa6049bbe481e Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 7 Aug 2024 19:39:47 +0200 Subject: [PATCH] feat: `Reference::remote_name()` now also provides valid remote names for local tracking branches. --- gix/src/reference/remote.rs | 30 ++++++++++++++++-- .../make_remote_config_repos.tar | Bin 348672 -> 406016 bytes .../fixtures/make_remote_config_repos.sh | 10 ++++++ gix/tests/reference/mod.rs | 27 ++++++++++++++++ 4 files changed, 64 insertions(+), 3 deletions(-) diff --git a/gix/src/reference/remote.rs b/gix/src/reference/remote.rs index b3ae0a38c08..f2187e748bd 100644 --- a/gix/src/reference/remote.rs +++ b/gix/src/reference/remote.rs @@ -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 @@ -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> { - self.repo.branch_remote_name(self.name().shorten(), direction) + pub fn remote_name(&self, direction: remote::Direction) -> Option> { + 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. diff --git a/gix/tests/fixtures/generated-archives/make_remote_config_repos.tar b/gix/tests/fixtures/generated-archives/make_remote_config_repos.tar index 604c41d813287477c72ace41d3f9d889ce8292b8..2f2838bbf7c492f8a2706ec8c4d695af27f67e51 100644 GIT binary patch delta 7959 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 H4?X=qZt75% diff --git a/gix/tests/fixtures/make_remote_config_repos.sh b/gix/tests/fixtures/make_remote_config_repos.sh index 0982c21f47a..efd444d1c2d 100755 --- a/gix/tests/fixtures/make_remote_config_repos.sh +++ b/gix/tests/fixtures/make_remote_config_repos.sh @@ -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 +) \ No newline at end of file diff --git a/gix/tests/reference/mod.rs b/gix/tests/reference/mod.rs index 7dd762f097e..4ec74ca85e8 100644 --- a/gix/tests/reference/mod.rs +++ b/gix/tests/reference/mod.rs @@ -1,3 +1,5 @@ +use gix::remote::Direction; + mod log { #[test] @@ -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};