diff --git a/gix-ref/Cargo.toml b/gix-ref/Cargo.toml
index 0ef687cccf0..c2c3dde9a69 100644
--- a/gix-ref/Cargo.toml
+++ b/gix-ref/Cargo.toml
@@ -26,7 +26,7 @@ serde = ["dep:serde", "gix-hash/serde", "gix-actor/serde", "gix-object/serde"]
parallel = ["gix-features/parallel"]
[dependencies]
-gix-features = { version = "^0.48.0", path = "../gix-features", features = ["walkdir"] }
+gix-features = { version = "^0.48.0", path = "../gix-features", features = ["walkdir", "once_cell"] }
gix-fs = { version = "^0.21.1", path = "../gix-fs" }
gix-path = { version = "^0.12.0", path = "../gix-path" }
gix-hash = { version = "^0.25.0", path = "../gix-hash" }
diff --git a/gix-ref/src/store/packed/buffer.rs b/gix-ref/src/store/packed/buffer.rs
index 9c1a757c7fc..b2839fdd62e 100644
--- a/gix-ref/src/store/packed/buffer.rs
+++ b/gix-ref/src/store/packed/buffer.rs
@@ -67,6 +67,8 @@ pub mod open {
data: backing,
path,
object_hash,
+ lookup_count: std::sync::atomic::AtomicUsize::new(0),
+ name_index: gix_features::threading::OnceCell::new(),
})
}
diff --git a/gix-ref/src/store/packed/find.rs b/gix-ref/src/store/packed/find.rs
index 915e725029a..1e12c594f21 100644
--- a/gix-ref/src/store/packed/find.rs
+++ b/gix-ref/src/store/packed/find.rs
@@ -1,7 +1,16 @@
+use std::sync::atomic::Ordering;
+
use gix_object::bstr::{BStr, BString, ByteSlice};
use crate::{FullNameRef, PartialNameRef, store_impl::packed};
+/// Number of `try_find_full_name` calls served by binary search before
+/// the next call eagerly builds a name → offset index for the rest of the
+/// buffer's lifetime. The threshold trades a small one-time build cost
+/// against `log₂(n)`-per-call binary searches; below it, single-shot
+/// lookups (typical CLI commands) pay nothing extra.
+pub(super) const INDEX_BUILD_AFTER_LOOKUPS: usize = 8;
+
/// packed-refs specific functionality
impl packed::Buffer {
/// Find a reference with the given `name` and return it.
@@ -37,6 +46,23 @@ impl packed::Buffer {
}
pub(crate) fn try_find_full_name(&self, name: &FullNameRef) -> Result