@@ -128,8 +128,9 @@ impl PrepareFetch {
128128
129129 // Add HEAD after the remote was written to config, we need it to know what to check out later, and assure
130130 // the ref that HEAD points to is present no matter what.
131+ let head_local_tracking_branch = format ! ( "refs/remotes/{remote_name}/HEAD" ) ;
131132 let head_refspec = gix_refspec:: parse (
132- format ! ( "HEAD:refs/remotes/{remote_name}/HEAD " ) . as_str ( ) . into ( ) ,
133+ format ! ( "HEAD:{head_local_tracking_branch} " ) . as_str ( ) . into ( ) ,
133134 gix_refspec:: parse:: Operation :: Fetch ,
134135 )
135136 . expect ( "valid" )
@@ -139,22 +140,48 @@ impl PrepareFetch {
139140 if let Some ( f) = self . configure_connection . as_mut ( ) {
140141 f ( & mut connection) . map_err ( Error :: RemoteConnection ) ?;
141142 }
142- connection
143- . prepare_fetch ( & mut * progress, {
144- let mut opts = self . fetch_options . clone ( ) ;
145- if !opts. extra_refspecs . contains ( & head_refspec) {
146- opts. extra_refspecs . push ( head_refspec)
147- }
148- if let Some ( ref_name) = & self . ref_name {
149- opts. extra_refspecs . push (
150- gix_refspec:: parse ( ref_name. as_ref ( ) . as_bstr ( ) , gix_refspec:: parse:: Operation :: Fetch )
151- . expect ( "partial names are valid refspecs" )
152- . to_owned ( ) ,
153- ) ;
154- }
155- opts
156- } )
157- . await ?
143+ let mut fetch_opts = {
144+ let mut opts = self . fetch_options . clone ( ) ;
145+ if !opts. extra_refspecs . contains ( & head_refspec) {
146+ opts. extra_refspecs . push ( head_refspec. clone ( ) )
147+ }
148+ if let Some ( ref_name) = & self . ref_name {
149+ opts. extra_refspecs . push (
150+ gix_refspec:: parse ( ref_name. as_ref ( ) . as_bstr ( ) , gix_refspec:: parse:: Operation :: Fetch )
151+ . expect ( "partial names are valid refspecs" )
152+ . to_owned ( ) ,
153+ ) ;
154+ }
155+ opts
156+ } ;
157+ match connection. prepare_fetch ( & mut * progress, fetch_opts. clone ( ) ) . await {
158+ Ok ( prepare) => prepare,
159+ Err ( remote:: fetch:: prepare:: Error :: RefMap ( remote:: ref_map:: Error :: MappingValidation ( err) ) )
160+ if err. issues . len ( ) == 1
161+ && fetch_opts. extra_refspecs . contains ( & head_refspec)
162+ && matches ! (
163+ err. issues. first( ) ,
164+ Some ( gix_refspec:: match_group:: validate:: Issue :: Conflict {
165+ destination_full_ref_name,
166+ ..
167+ } ) if * destination_full_ref_name == head_local_tracking_branch
168+ ) =>
169+ {
170+ let head_refspec_idx = fetch_opts
171+ . extra_refspecs
172+ . iter ( )
173+ . enumerate ( )
174+ . find_map ( |( idx, spec) | ( * spec == head_refspec) . then_some ( idx) )
175+ . expect ( "it's contained" ) ;
176+ // On the very special occasion that we fail as there is a remote `refs/heads/HEAD` reference that clashes
177+ // with our implicit refspec, retry without it. Maybe this tells us that we shouldn't have that implicit
178+ // refspec, as git can do this without connecting twice.
179+ let connection = remote. connect ( remote:: Direction :: Fetch ) . await ?;
180+ fetch_opts. extra_refspecs . remove ( head_refspec_idx) ;
181+ connection. prepare_fetch ( & mut * progress, fetch_opts) . await ?
182+ }
183+ Err ( err) => return Err ( err. into ( ) ) ,
184+ }
158185 } ;
159186
160187 // Assure problems with custom branch names fail early, not after getting the pack or during negotiation.
0 commit comments