Skip to content

Commit 6ac2867

Browse files
committed
feat: Reference::remote_name() now also provides valid remote names for local tracking branches.
1 parent c612440 commit 6ac2867

File tree

4 files changed

+64
-3
lines changed

4 files changed

+64
-3
lines changed

gix/src/reference/remote.rs

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
use crate::bstr::ByteSlice;
12
use crate::repository::{branch_remote_ref_name, branch_remote_tracking_ref_name};
23
use crate::{remote, Reference};
3-
use gix_ref::FullNameRef;
4+
use gix_ref::{Category, FullNameRef};
45
use std::borrow::Cow;
56

67
/// Remotes
@@ -9,8 +10,31 @@ impl<'repo> Reference<'repo> {
910
/// Return `None` if no remote is configured.
1011
///
1112
/// See also [`Repository::branch_remote_name()`](crate::Repository::branch_remote_name()) for more details.
12-
pub fn remote_name(&self, direction: remote::Direction) -> Option<remote::Name<'repo>> {
13-
self.repo.branch_remote_name(self.name().shorten(), direction)
13+
pub fn remote_name(&self, direction: remote::Direction) -> Option<remote::Name<'_>> {
14+
let (category, shortname) = self.name().category_and_short_name()?;
15+
match category {
16+
Category::RemoteBranch => {
17+
if shortname.find_iter("/").take(2).count() == 1 {
18+
let slash_pos = shortname.find_byte(b'/').expect("it was just found");
19+
shortname[..slash_pos]
20+
.as_bstr()
21+
.to_str()
22+
.ok()
23+
.map(|n| remote::Name::Symbol(n.into()))
24+
} else {
25+
let remotes = self.repo.remote_names();
26+
for slash_pos in shortname.rfind_iter("/") {
27+
let candidate = shortname[..slash_pos].as_bstr();
28+
if remotes.contains(candidate) {
29+
return candidate.to_str().ok().map(|n| remote::Name::Symbol(n.into()));
30+
}
31+
}
32+
None
33+
}
34+
}
35+
Category::LocalBranch => self.repo.branch_remote_name(shortname, direction),
36+
_ => None,
37+
}
1438
}
1539

1640
/// Find the remote along with all configuration associated with it suitable for handling this reference.
Binary file not shown.

gix/tests/fixtures/make_remote_config_repos.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,3 +131,13 @@ EOF
131131
pushDefault = push-origin
132132
EOF
133133
)
134+
135+
git clone fetch multiple-remotes
136+
(cd multiple-remotes
137+
git remote add other ../fetch && git fetch other
138+
git remote add with/two/slashes ../fetch && git fetch with/two/slashes
139+
git remote add with/two ../fetch && git fetch with/two
140+
141+
git checkout -b main --track origin/main
142+
git checkout -b other-main --track other/main
143+
)

gix/tests/reference/mod.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use gix::remote::Direction;
2+
13
mod log {
24

35
#[test]
@@ -17,6 +19,31 @@ mod log {
1719
);
1820
}
1921
}
22+
23+
#[test]
24+
fn remote_name() -> crate::Result {
25+
let repo = crate::named_subrepo_opts(
26+
"make_remote_config_repos.sh",
27+
"multiple-remotes",
28+
gix::open::Options::isolated(),
29+
)?;
30+
for (ref_name, expected_remote) in [
31+
("main", "origin"),
32+
("other-main", "other"),
33+
("refs/remotes/origin/main", "origin"),
34+
("refs/remotes/other/main", "other"),
35+
("with/two/slashes/main", "with/two/slashes"),
36+
("with/two/main", "with/two"),
37+
] {
38+
let r = repo.find_reference(ref_name)?;
39+
assert_eq!(
40+
r.remote_name(Direction::Fetch).map(|name| name.as_bstr().to_owned()),
41+
Some(expected_remote.into())
42+
);
43+
}
44+
Ok(())
45+
}
46+
2047
mod find {
2148
use gix_ref as refs;
2249
use gix_ref::{FullName, FullNameRef, Target};

0 commit comments

Comments
 (0)