@@ -2,8 +2,9 @@ use crate::init::walk::RefsById;
22use crate :: init:: { Entrypoint , Overlay } ;
33use but_core:: { RefMetadata , ref_metadata} ;
44use gix:: prelude:: ReferenceExt ;
5+ use gix:: refs:: Target ;
56use std:: borrow:: Cow ;
6- use std:: collections:: BTreeSet ;
7+ use std:: collections:: { BTreeMap , BTreeSet } ;
78
89impl Overlay {
910 /// Serve the given `refs` from memory, as if they would exist.
@@ -16,13 +17,27 @@ impl Overlay {
1617 self
1718 }
1819
20+ /// Serve the given `refs` from memory, which is like creating the reference or as if its value was set,
21+ /// completely overriding the value in the repository.
22+ pub fn with_references ( mut self , refs : impl IntoIterator < Item = gix:: refs:: Reference > ) -> Self {
23+ self . overriding_references . extend ( refs) ;
24+ self
25+ }
26+
1927 /// Override the starting position of the traversal by setting it to `id`,
2028 /// and optionally, by providing the `ref_name` that points to `id`.
2129 pub fn with_entrypoint (
2230 mut self ,
2331 id : gix:: ObjectId ,
2432 ref_name : Option < gix:: refs:: FullName > ,
2533 ) -> Self {
34+ if let Some ( ref_name) = & ref_name {
35+ self . overriding_references . push ( gix:: refs:: Reference {
36+ name : ref_name. to_owned ( ) ,
37+ target : Target :: Object ( id) ,
38+ peeled : Some ( id) ,
39+ } )
40+ }
2641 self . entrypoint = Some ( ( id, ref_name) ) ;
2742 self
2843 }
@@ -59,13 +74,21 @@ impl Overlay {
5974 {
6075 let Overlay {
6176 nonoverriding_references,
77+ overriding_references,
6278 meta_branches,
6379 workspace,
6480 entrypoint,
6581 } = self ;
6682 (
6783 OverlayRepo {
68- nonoverriding_references,
84+ nonoverriding_references : nonoverriding_references
85+ . into_iter ( )
86+ . map ( |r| ( r. name . clone ( ) , r) )
87+ . collect ( ) ,
88+ overriding_references : overriding_references
89+ . into_iter ( )
90+ . map ( |r| ( r. name . clone ( ) , r) )
91+ . collect ( ) ,
6992 inner : repo,
7093 } ,
7194 OverlayMetadata {
@@ -80,7 +103,8 @@ impl Overlay {
80103
81104pub ( crate ) struct OverlayRepo < ' repo > {
82105 inner : & ' repo gix:: Repository ,
83- nonoverriding_references : Vec < gix:: refs:: Reference > ,
106+ nonoverriding_references : BTreeMap < gix:: refs:: FullName , gix:: refs:: Reference > ,
107+ overriding_references : BTreeMap < gix:: refs:: FullName , gix:: refs:: Reference > ,
84108}
85109
86110/// Note that functions with `'repo` in their return value technically leak the bare repo, and it's
@@ -94,13 +118,11 @@ impl<'repo> OverlayRepo<'repo> {
94118 & self ,
95119 ref_name : & gix:: refs:: FullNameRef ,
96120 ) -> anyhow:: Result < Option < gix:: Reference < ' repo > > > {
97- if let Some ( rn) = self . inner . try_find_reference ( ref_name) ? {
121+ if let Some ( r) = self . overriding_references . get ( ref_name) {
122+ Ok ( Some ( r. clone ( ) . attach ( self . inner ) ) )
123+ } else if let Some ( rn) = self . inner . try_find_reference ( ref_name) ? {
98124 Ok ( Some ( rn) )
99- } else if let Some ( r) = self
100- . nonoverriding_references
101- . iter ( )
102- . find ( |r| r. name . as_ref ( ) == ref_name)
103- {
125+ } else if let Some ( r) = self . nonoverriding_references . get ( ref_name) {
104126 Ok ( Some ( r. clone ( ) . attach ( self . inner ) ) )
105127 } else {
106128 Ok ( None )
@@ -111,17 +133,16 @@ impl<'repo> OverlayRepo<'repo> {
111133 & self ,
112134 ref_name : & gix:: refs:: FullNameRef ,
113135 ) -> anyhow:: Result < gix:: Reference < ' repo > > {
136+ if let Some ( r) = self . overriding_references . get ( ref_name) {
137+ return Ok ( r. clone ( ) . attach ( self . inner ) ) ;
138+ }
114139 Ok ( self
115140 . inner
116141 . find_reference ( ref_name)
117142 . or_else ( |err| match err {
118143 gix:: reference:: find:: existing:: Error :: Find ( _) => Err ( err) ,
119144 gix:: reference:: find:: existing:: Error :: NotFound { .. } => {
120- if let Some ( r) = self
121- . nonoverriding_references
122- . iter ( )
123- . find ( |r| r. name . as_ref ( ) == ref_name)
124- {
145+ if let Some ( r) = self . nonoverriding_references . get ( ref_name) {
125146 Ok ( r. clone ( ) . attach ( self . inner ) )
126147 } else {
127148 Err ( err)
@@ -202,6 +223,18 @@ impl<'repo> OverlayRepo<'repo> {
202223 } ;
203224 let mut all_refs_by_id = gix:: hashtable:: HashMap :: < _ , Vec < _ > > :: default ( ) ;
204225 for prefix in prefixes {
226+ // apply overrides - they are seen first and take the spot of everything.
227+ for ( commit_id, git_reference) in self
228+ . overriding_references
229+ . values ( )
230+ . filter ( |rn| rn. name . as_bstr ( ) . starts_with ( prefix. as_bytes ( ) ) )
231+ . filter_map ( |rn| ref_filter ( rn. clone ( ) . attach ( self . inner ) ) )
232+ {
233+ all_refs_by_id
234+ . entry ( commit_id)
235+ . or_default ( )
236+ . push ( git_reference) ;
237+ }
205238 for ( commit_id, git_reference) in self
206239 . inner
207240 . references ( ) ?
@@ -214,10 +247,10 @@ impl<'repo> OverlayRepo<'repo> {
214247 . or_default ( )
215248 . push ( git_reference) ;
216249 }
217- // apply overrides
250+ // apply overrides (new only)
218251 for ( commit_id, git_reference) in self
219252 . nonoverriding_references
220- . iter ( )
253+ . values ( )
221254 . filter ( |rn| rn. name . as_bstr ( ) . starts_with ( prefix. as_bytes ( ) ) )
222255 . filter_map ( |rn| ref_filter ( rn. clone ( ) . attach ( self . inner ) ) )
223256 {
0 commit comments