Skip to content

Commit 3fb9c4f

Browse files
committed
fix: make sure ordinary capitalized partial names can be found by partial name.
For instance, previously, a ref named `A` could not be found even though `refs/heads/A` existed.
1 parent feef98d commit 3fb9c4f

33 files changed

+93
-28
lines changed

gix-ref/src/name.rs

+9-4
Original file line numberDiff line numberDiff line change
@@ -62,16 +62,21 @@ impl PartialNameRef {
6262
}
6363

6464
impl PartialNameRef {
65-
pub(crate) fn looks_like_full_name(&self) -> bool {
65+
pub(crate) fn looks_like_full_name(&self, consider_pseudo_ref: bool) -> bool {
6666
let name = self.0.as_bstr();
6767
name.starts_with_str("refs/")
6868
|| name.starts_with(Category::MainPseudoRef.prefix())
6969
|| name.starts_with(Category::LinkedPseudoRef { name: "".into() }.prefix())
70-
|| is_pseudo_ref(name)
70+
|| (consider_pseudo_ref && is_pseudo_ref(name))
7171
}
72-
pub(crate) fn construct_full_name_ref<'buf>(&self, inbetween: &str, buf: &'buf mut BString) -> &'buf FullNameRef {
72+
pub(crate) fn construct_full_name_ref<'buf>(
73+
&self,
74+
inbetween: &str,
75+
buf: &'buf mut BString,
76+
consider_pseudo_ref: bool,
77+
) -> &'buf FullNameRef {
7378
buf.clear();
74-
if !self.looks_like_full_name() {
79+
if !self.looks_like_full_name(consider_pseudo_ref) {
7580
buf.push_str("refs/");
7681
}
7782
if !inbetween.is_empty() {

gix-ref/src/store/file/find.rs

+25-7
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use std::{
66

77
pub use error::Error;
88

9+
use crate::name::is_pseudo_ref;
910
use crate::{
1011
file,
1112
store_impl::{file::loose, packed},
@@ -103,13 +104,28 @@ impl file::Store {
103104
let precomposed_partial_name = precomposed_partial_name_storage
104105
.as_ref()
105106
.map(std::convert::AsRef::as_ref);
106-
for inbetween in &["", "tags", "heads", "remotes"] {
107-
match self.find_inner(inbetween, partial_name, precomposed_partial_name, packed, &mut buf) {
108-
Ok(Some(r)) => return Ok(Some(decompose_if(r, precomposed_partial_name.is_some()))),
109-
Ok(None) => {
110-
continue;
107+
for consider_pseudo_ref in [true, false] {
108+
if !consider_pseudo_ref && !is_pseudo_ref(partial_name.as_bstr()) {
109+
break;
110+
}
111+
'try_directories: for inbetween in &["", "tags", "heads", "remotes"] {
112+
match self.find_inner(
113+
inbetween,
114+
partial_name,
115+
precomposed_partial_name,
116+
packed,
117+
&mut buf,
118+
consider_pseudo_ref,
119+
) {
120+
Ok(Some(r)) => return Ok(Some(decompose_if(r, precomposed_partial_name.is_some()))),
121+
Ok(None) => {
122+
if consider_pseudo_ref && is_pseudo_ref(partial_name.as_bstr()) {
123+
break 'try_directories;
124+
}
125+
continue;
126+
}
127+
Err(err) => return Err(err),
111128
}
112-
Err(err) => return Err(err),
113129
}
114130
}
115131
if partial_name.as_bstr() != "HEAD" {
@@ -129,6 +145,7 @@ impl file::Store {
129145
.map(std::convert::AsRef::as_ref),
130146
None,
131147
&mut buf,
148+
true, /* consider-pseudo-ref */
132149
)
133150
.map(|res| res.map(|r| decompose_if(r, precomposed_partial_name_storage.is_some())))
134151
} else {
@@ -143,10 +160,11 @@ impl file::Store {
143160
precomposed_partial_name: Option<&PartialNameRef>,
144161
packed: Option<&packed::Buffer>,
145162
path_buf: &mut BString,
163+
consider_pseudo_ref: bool,
146164
) -> Result<Option<Reference>, Error> {
147165
let full_name = precomposed_partial_name
148166
.unwrap_or(partial_name)
149-
.construct_full_name_ref(inbetween, path_buf);
167+
.construct_full_name_ref(inbetween, path_buf, consider_pseudo_ref);
150168
let content_buf = self.ref_contents(full_name).map_err(|err| Error::ReadFileContents {
151169
source: err,
152170
path: self.reference_path(full_name),

gix-ref/src/store/packed/find.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,15 @@ impl packed::Buffer {
1717
let name = name.try_into()?;
1818
let mut buf = BString::default();
1919
for inbetween in &["", "tags", "heads", "remotes"] {
20-
let (name, was_absolute) = if name.looks_like_full_name() {
20+
let (name, was_absolute) = if name.looks_like_full_name(false) {
2121
let name = FullNameRef::new_unchecked(name.as_bstr());
2222
let name = match transform_full_name_for_lookup(name) {
2323
None => return Ok(None),
2424
Some(name) => name,
2525
};
2626
(name, true)
2727
} else {
28-
let full_name = name.construct_full_name_ref(inbetween, &mut buf);
28+
let full_name = name.construct_full_name_ref(inbetween, &mut buf, false);
2929
(full_name, false)
3030
};
3131
match self.try_find_full_name(name)? {

gix-ref/tests/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ serde = ["gix-ref/serde"]
1717

1818
[[test]]
1919
name = "refs"
20-
path = "refs.rs"
20+
path = "refs/main.rs"
2121

2222
[dev-dependencies]
2323
gix-ref = { path = ".." }
Binary file not shown.
Binary file not shown.

gix-ref/tests/fixtures/make_packed_ref_repository.sh

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ git checkout -q -b main
77
git commit -q --allow-empty -m c1
88
git branch dt1
99
git branch d1
10+
git branch A
1011

1112
mkdir -p .git/refs/remotes/origin
1213

gix-ref/tests/fixtures/make_packed_ref_repository_for_overlay.sh

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ git init -q
66
git checkout -q -b main
77
git commit -q --allow-empty -m c1
88
git branch newer-as-loose
9+
git branch A
910
git tag -m "tag object" tag-object
1011

1112
mkdir -p .git/refs/remotes/origin

gix-ref/tests/fixtures/make_ref_repository.sh

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ git checkout -q -b main
77
git commit -q --allow-empty -m c1
88
git branch dt1
99
git branch d1
10+
git branch A
1011

1112
mkdir -p .git/refs/remotes/origin
1213

File renamed without changes.
File renamed without changes.

gix-ref/tests/file/store/find.rs renamed to gix-ref/tests/refs/file/store/find.rs

+27-6
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,22 @@ mod existing {
22
use crate::{file::store_at, hex_to_id};
33

44
#[test]
5-
fn with_packed_refs() -> crate::Result {
6-
let store = store_at("make_packed_ref_repository_for_overlay.sh")?;
7-
let c1 = hex_to_id("134385f6d781b7e97062102c6a483440bfda2a03");
8-
let r = store.find("main")?;
9-
assert_eq!(r.target.into_id(), c1);
10-
assert_eq!(r.name.as_bstr(), "refs/heads/main");
5+
fn various_repositories() -> crate::Result {
6+
for fixture in [
7+
"make_ref_repository.sh",
8+
"make_packed_ref_repository.sh",
9+
"make_packed_ref_repository_for_overlay.sh",
10+
] {
11+
let store = store_at(fixture)?;
12+
let c1 = hex_to_id("134385f6d781b7e97062102c6a483440bfda2a03");
13+
let r = store.find("main")?;
14+
assert_eq!(r.target.into_id(), c1);
15+
assert_eq!(r.name.as_bstr(), "refs/heads/main");
16+
let r = store
17+
.find("A")
18+
.unwrap_or_else(|_| panic!("{fixture}: should find capitalized refs"));
19+
assert_eq!(r.target.into_id(), c1);
20+
}
1121
Ok(())
1222
}
1323

@@ -98,6 +108,17 @@ mod loose {
98108

99109
use crate::file::store;
100110

111+
#[test]
112+
fn capitalized_branch() -> crate::Result {
113+
let store = store()?;
114+
assert_eq!(
115+
store.find("A")?.name.as_bstr(),
116+
"refs/heads/A",
117+
"capitalized loose refs can be found fine"
118+
);
119+
Ok(())
120+
}
121+
101122
#[test]
102123
fn success_and_failure() -> crate::Result {
103124
let store = store()?;

gix-ref/tests/file/store/iter.rs renamed to gix-ref/tests/refs/file/store/iter.rs

+9-5
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ fn no_packed_available_thus_no_iteration_possible() -> crate::Result {
253253
#[test]
254254
fn packed_file_iter() -> crate::Result {
255255
let store = store_with_packed_refs()?;
256-
assert_eq!(store.open_packed_buffer()?.expect("pack available").iter()?.count(), 8);
256+
assert_eq!(store.open_packed_buffer()?.expect("pack available").iter()?.count(), 9);
257257
Ok(())
258258
}
259259

@@ -262,7 +262,7 @@ fn loose_iter_with_broken_refs() -> crate::Result {
262262
let store = store()?;
263263

264264
let mut actual: Vec<_> = store.loose_iter()?.collect();
265-
assert_eq!(actual.len(), 15);
265+
assert_eq!(actual.len(), 16);
266266
actual.sort_by_key(Result::is_err);
267267
let first_error = actual
268268
.iter()
@@ -271,7 +271,7 @@ fn loose_iter_with_broken_refs() -> crate::Result {
271271
.expect("there is an error");
272272

273273
assert_eq!(
274-
first_error, 14,
274+
first_error, 15,
275275
"there is exactly one invalid item, and it didn't abort the iterator most importantly"
276276
);
277277
#[cfg(not(windows))]
@@ -291,6 +291,7 @@ fn loose_iter_with_broken_refs() -> crate::Result {
291291
ref_paths,
292292
vec![
293293
"d1",
294+
"heads/A",
294295
"heads/d1",
295296
"heads/dt1",
296297
"heads/main",
@@ -343,6 +344,7 @@ fn loose_iter_with_prefix() -> crate::Result {
343344
assert_eq!(
344345
actual,
345346
vec![
347+
"refs/heads/A",
346348
"refs/heads/d1",
347349
"refs/heads/dt1",
348350
"refs/heads/main",
@@ -394,7 +396,8 @@ fn overlay_iter() -> crate::Result {
394396
assert_eq!(
395397
ref_names,
396398
vec![
397-
(b"refs/heads/main".as_bstr().to_owned(), Object(c1)),
399+
(b"refs/heads/A".as_bstr().to_owned(), Object(c1)),
400+
(b"refs/heads/main".into(), Object(c1)),
398401
("refs/heads/newer-as-loose".into(), Object(c2)),
399402
(
400403
"refs/remotes/origin/HEAD".into(),
@@ -440,7 +443,8 @@ fn overlay_prefixed_iter() -> crate::Result {
440443
assert_eq!(
441444
ref_names,
442445
vec![
443-
(b"refs/heads/main".as_bstr().to_owned(), Object(c1)),
446+
(b"refs/heads/A".as_bstr().to_owned(), Object(c1)),
447+
(b"refs/heads/main".into(), Object(c1)),
444448
("refs/heads/newer-as-loose".into(), Object(c2)),
445449
]
446450
);

gix-ref/tests/file/transaction/prepare_and_commit/create_or_update/mod.rs renamed to gix-ref/tests/refs/file/transaction/prepare_and_commit/create_or_update/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -791,7 +791,7 @@ fn packed_refs_creation_with_packed_refs_mode_prune_removes_original_loose_refs(
791791

792792
assert_eq!(
793793
edits.len(),
794-
8,
794+
9,
795795
"there are a certain amount of loose refs that are packed"
796796
);
797797

File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

gix-ref/tests/packed/find.rs renamed to gix-ref/tests/refs/packed/find.rs

+13
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,19 @@ fn a_lock_file_would_not_be_a_valid_partial_name() {
1414
assert_eq!(err.to_string(), "A reference must be a valid tag name as well");
1515
}
1616

17+
#[test]
18+
fn capitalized_branch() -> crate::Result {
19+
let store = store_with_packed_refs()?;
20+
let packed_refs = store.open_packed_buffer()?.expect("packed-refs exist");
21+
22+
assert_eq!(
23+
packed_refs.find("A")?.name.as_bstr(),
24+
"refs/heads/A",
25+
"fully capitalized refs aren't just considered pseudorefs"
26+
);
27+
Ok(())
28+
}
29+
1730
#[test]
1831
fn all_iterable_refs_can_be_found() -> crate::Result {
1932
let store = store_with_packed_refs()?;

gix-ref/tests/packed/iter.rs renamed to gix-ref/tests/refs/packed/iter.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ fn packed_refs_with_header() -> crate::Result {
1818
let dir = gix_testtools::scripted_fixture_read_only_standalone("make_packed_ref_repository.sh")?;
1919
let buf = std::fs::read(dir.join(".git").join("packed-refs"))?;
2020
let iter = packed::Iter::new(&buf)?;
21-
assert_eq!(iter.count(), 8, "it finds the right amount of items");
21+
assert_eq!(iter.count(), 9, "it finds the right amount of items");
2222
Ok(())
2323
}
2424

@@ -31,7 +31,8 @@ fn iter_prefix() -> crate::Result {
3131
.map(|r| r.map(|r| r.name.as_bstr()))
3232
.collect::<Result<Vec<_>, _>>()?,
3333
vec![
34-
"refs/heads/d1".as_bytes().as_bstr(),
34+
"refs/heads/A".as_bytes().as_bstr(),
35+
"refs/heads/d1".into(),
3536
"refs/heads/dt1".into(),
3637
"refs/heads/main".into()
3738
]
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)