@@ -2,6 +2,7 @@ use crate::{
22 bstr:: { BString , ByteSlice } ,
33 clone:: PrepareFetch ,
44} ;
5+ use gix_ref:: Category ;
56
67/// The error returned by [`PrepareFetch::fetch_only()`].
78#[ derive( Debug , thiserror:: Error ) ]
@@ -49,6 +50,8 @@ pub enum Error {
4950 CommitterOrFallback ( #[ from] crate :: config:: time:: Error ) ,
5051 #[ error( transparent) ]
5152 RefMap ( #[ from] crate :: remote:: ref_map:: Error ) ,
53+ #[ error( transparent) ]
54+ ReferenceName ( #[ from] gix_validate:: reference:: name:: Error ) ,
5255}
5356
5457/// Modification
@@ -107,14 +110,13 @@ impl PrepareFetch {
107110 // For shallow clones without custom configuration, we'll use a single-branch refspec
108111 // to match git's behavior (matching git's single-branch behavior for shallow clones).
109112 let use_single_branch_for_shallow = self . shallow != remote:: fetch:: Shallow :: NoChange
110- && self . configure_remote . is_none ( )
111- && remote . fetch_specs . is_empty ( ) ;
113+ && remote . fetch_specs . is_empty ( )
114+ && self . fetch_options . extra_refspecs . is_empty ( ) ;
112115
113116 let target_ref = if use_single_branch_for_shallow {
114117 // Determine target branch from user-specified ref_name or default branch
115118 if let Some ( ref_name) = & self . ref_name {
116- // User specified a branch, use that
117- Some ( format ! ( "refs/heads/{}" , ref_name. as_ref( ) . as_bstr( ) ) )
119+ Some ( Category :: LocalBranch . to_full_name ( ref_name. as_ref ( ) . as_bstr ( ) ) ?)
118120 } else {
119121 // For shallow clones without a specified ref, we need to determine the default branch.
120122 // We'll connect to get HEAD information. For Protocol V2, we need to explicitly list refs.
@@ -129,7 +131,7 @@ impl PrepareFetch {
129131 refs. iter ( ) . find_map ( |r| match r {
130132 gix_protocol:: handshake:: Ref :: Symbolic {
131133 full_ref_name, target, ..
132- } if full_ref_name == "HEAD" => Some ( target. to_string ( ) ) ,
134+ } if full_ref_name == "HEAD" => gix_ref :: FullName :: try_from ( target) . ok ( ) ,
133135 _ => None ,
134136 } )
135137 } )
@@ -143,9 +145,9 @@ impl PrepareFetch {
143145 repo. config
144146 . resolved
145147 . string ( crate :: config:: tree:: Init :: DEFAULT_BRANCH )
146- . and_then ( |name| name. to_str ( ) . ok ( ) . map ( |s| format ! ( "refs/heads/{}" , s ) ) )
148+ . and_then ( |name| Category :: LocalBranch . to_full_name ( name. as_bstr ( ) ) . ok ( ) )
147149 } )
148- . unwrap_or_else ( || "refs/heads/main" . to_string ( ) ) ;
150+ . unwrap_or_else ( || gix_ref :: FullName :: try_from ( "refs/heads/main" ) . expect ( "known to be valid" ) ) ;
149151
150152 // Drop the connection explicitly to release the borrow on remote
151153 drop ( connection) ;
@@ -156,11 +158,12 @@ impl PrepareFetch {
156158 None
157159 } ;
158160
159- // Set up refspec based on whether we're doing a single-branch shallow clone
161+ // Set up refspec based on whether we're doing a single-branch shallow clone,
162+ // which requires a single ref to match Git unless it's overridden.
160163 if remote. fetch_specs . is_empty ( ) {
161164 if let Some ( target_ref) = & target_ref {
162165 // Single-branch refspec for shallow clones
163- let short_name = target_ref. strip_prefix ( "refs/heads/" ) . unwrap_or ( target_ref . as_str ( ) ) ;
166+ let short_name = target_ref. shorten ( ) ;
164167 remote = remote
165168 . with_refspecs (
166169 Some ( format ! ( "+{target_ref}:refs/remotes/{remote_name}/{short_name}" ) . as_str ( ) ) ,
0 commit comments