@@ -47,6 +47,8 @@ pub enum Error {
4747 } ,
4848 #[ error( transparent) ]
4949 CommitterOrFallback ( #[ from] crate :: config:: time:: Error ) ,
50+ #[ error( transparent) ]
51+ RefMap ( #[ from] crate :: remote:: ref_map:: Error ) ,
5052}
5153
5254/// Modification
@@ -101,14 +103,81 @@ impl PrepareFetch {
101103 } ;
102104
103105 let mut remote = repo. remote_at ( self . url . clone ( ) ) ?;
106+
107+ // For shallow clones without custom configuration, we'll use a single-branch refspec
108+ // to match git's behavior (matching git's single-branch behavior for shallow clones).
109+ let use_single_branch_for_shallow = self . shallow != remote:: fetch:: Shallow :: NoChange
110+ && self . configure_remote . is_none ( )
111+ && remote. fetch_specs . is_empty ( ) ;
112+
113+ let target_ref = if use_single_branch_for_shallow {
114+ // Determine target branch from user-specified ref_name or default branch
115+ 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( ) ) )
118+ } else {
119+ // For shallow clones without a specified ref, we need to determine the default branch.
120+ // We'll connect to get HEAD information. For Protocol V2, we need to explicitly list refs.
121+ let mut connection = remote. connect ( remote:: Direction :: Fetch ) . await ?;
122+
123+ // Perform handshake and try to get HEAD from it (works for Protocol V1)
124+ let _ = connection. ref_map_by_ref ( & mut progress, Default :: default ( ) ) . await ?;
125+
126+ let target = if let Some ( handshake) = & connection. handshake {
127+ // Protocol V1: refs are in handshake
128+ handshake. refs . as_ref ( ) . and_then ( |refs| {
129+ refs. iter ( ) . find_map ( |r| match r {
130+ gix_protocol:: handshake:: Ref :: Symbolic {
131+ full_ref_name, target, ..
132+ } if full_ref_name == "HEAD" => Some ( target. to_string ( ) ) ,
133+ _ => None ,
134+ } )
135+ } )
136+ } else {
137+ None
138+ } ;
139+
140+ // For Protocol V2 or if we couldn't determine HEAD, use the configured default branch
141+ let fallback_branch = target
142+ . or_else ( || {
143+ repo. config
144+ . resolved
145+ . string ( crate :: config:: tree:: Init :: DEFAULT_BRANCH )
146+ . and_then ( |name| name. to_str ( ) . ok ( ) . map ( |s| format ! ( "refs/heads/{}" , s) ) )
147+ } )
148+ . unwrap_or_else ( || "refs/heads/main" . to_string ( ) ) ;
149+
150+ // Drop the connection explicitly to release the borrow on remote
151+ drop ( connection) ;
152+
153+ Some ( fallback_branch)
154+ }
155+ } else {
156+ None
157+ } ;
158+
159+ // Set up refspec based on whether we're doing a single-branch shallow clone
104160 if remote. fetch_specs . is_empty ( ) {
105- remote = remote
106- . with_refspecs (
107- Some ( format ! ( "+refs/heads/*:refs/remotes/{remote_name}/*" ) . as_str ( ) ) ,
108- remote:: Direction :: Fetch ,
109- )
110- . expect ( "valid static spec" ) ;
161+ if let Some ( target_ref) = & target_ref {
162+ // Single-branch refspec for shallow clones
163+ let short_name = target_ref. strip_prefix ( "refs/heads/" ) . unwrap_or ( target_ref. as_str ( ) ) ;
164+ remote = remote
165+ . with_refspecs (
166+ Some ( format ! ( "+{target_ref}:refs/remotes/{remote_name}/{short_name}" ) . as_str ( ) ) ,
167+ remote:: Direction :: Fetch ,
168+ )
169+ . expect ( "valid refspec" ) ;
170+ } else {
171+ // Wildcard refspec for non-shallow clones or when target couldn't be determined
172+ remote = remote
173+ . with_refspecs (
174+ Some ( format ! ( "+refs/heads/*:refs/remotes/{remote_name}/*" ) . as_str ( ) ) ,
175+ remote:: Direction :: Fetch ,
176+ )
177+ . expect ( "valid static spec" ) ;
178+ }
111179 }
180+
112181 let mut clone_fetch_tags = None ;
113182 if let Some ( f) = self . configure_remote . as_mut ( ) {
114183 remote = f ( remote) . map_err ( Error :: RemoteConfiguration ) ?;
@@ -133,6 +202,7 @@ impl PrepareFetch {
133202 . expect ( "valid" )
134203 . to_owned ( ) ;
135204 let pending_pack: remote:: fetch:: Prepare < ' _ , ' _ , _ > = {
205+ // For shallow clones, we already connected once, so we need to connect again
136206 let mut connection = remote. connect ( remote:: Direction :: Fetch ) . await ?;
137207 if let Some ( f) = self . configure_connection . as_mut ( ) {
138208 f ( & mut connection) . map_err ( Error :: RemoteConnection ) ?;
0 commit comments