@@ -68,6 +68,7 @@ pub(crate) fn mark_complete_and_common_ref(
68
68
graph : & mut gix_negotiate:: Graph < ' _ > ,
69
69
ref_map : & fetch:: RefMap ,
70
70
shallow : & fetch:: Shallow ,
71
+ mapping_is_ignored : impl Fn ( & fetch:: Mapping ) -> bool ,
71
72
) -> Result < Action , Error > {
72
73
if let fetch:: Shallow :: Deepen ( 0 ) = shallow {
73
74
// Avoid deepening (relative) with zero as it seems to upset the server. Git also doesn't actually
@@ -98,9 +99,11 @@ pub(crate) fn mark_complete_and_common_ref(
98
99
r. target ( ) . try_id ( ) . map ( ToOwned :: to_owned)
99
100
} ) ;
100
101
101
- // Like git, we don't let known unchanged mappings participate in the tree traversal
102
- if want_id. zip ( have_id) . map_or ( true , |( want, have) | want != have) {
103
- num_mappings_with_change += 1 ;
102
+ if !mapping_is_ignored ( mapping) {
103
+ // Like git, we don't let known unchanged mappings participate in the tree traversal
104
+ if want_id. zip ( have_id) . map_or ( true , |( want, have) | want != have) {
105
+ num_mappings_with_change += 1 ;
106
+ }
104
107
}
105
108
106
109
if let Some ( commit) = want_id
@@ -114,7 +117,6 @@ pub(crate) fn mark_complete_and_common_ref(
114
117
}
115
118
}
116
119
117
- // If any kind of shallowing operation is desired, the server may still create a pack for us.
118
120
if matches ! ( shallow, Shallow :: NoChange ) {
119
121
if num_mappings_with_change == 0 {
120
122
return Ok ( Action :: NoChange ) ;
@@ -167,40 +169,50 @@ pub(crate) fn mark_complete_and_common_ref(
167
169
} )
168
170
}
169
171
170
- /// Add all `wants` to `arguments`, which is the unpeeled direct target that the advertised remote ref points to.
171
- pub ( crate ) fn add_wants (
172
- repo : & crate :: Repository ,
173
- arguments : & mut gix_protocol:: fetch:: Arguments ,
174
- ref_map : & fetch:: RefMap ,
175
- mapping_known : & [ bool ] ,
176
- shallow : & fetch:: Shallow ,
172
+ /// Create a predicate that checks if a refspec mapping should be ignored.
173
+ ///
174
+ /// We want to ignore mappings during negotiation if they would be handled implicitly by the server, which is the case
175
+ /// when tags would be sent implicitly due to `Tags::Included`.
176
+ pub ( crate ) fn make_refmapping_ignore_predicate (
177
177
fetch_tags : fetch:: Tags ,
178
- ) {
178
+ ref_map : & fetch:: RefMap ,
179
+ ) -> impl Fn ( & fetch:: Mapping ) -> bool + ' _ {
179
180
// With included tags, we have to keep mappings of tags to handle them later when updating refs, but we don't want to
180
181
// explicitly `want` them as the server will determine by itself which tags are pointing to a commit it wants to send.
181
182
// If we would not exclude implicit tag mappings like this, we would get too much of the graph.
182
183
let tag_refspec_to_ignore = matches ! ( fetch_tags, crate :: remote:: fetch:: Tags :: Included )
183
184
. then ( || fetch_tags. to_refspec ( ) )
184
185
. flatten ( ) ;
186
+ move |mapping| {
187
+ tag_refspec_to_ignore. map_or ( false , |tag_spec| {
188
+ mapping
189
+ . spec_index
190
+ . implicit_index ( )
191
+ . and_then ( |idx| ref_map. extra_refspecs . get ( idx) )
192
+ . map_or ( false , |spec| spec. to_ref ( ) == tag_spec)
193
+ } )
194
+ }
195
+ }
185
196
197
+ /// Add all `wants` to `arguments`, which is the unpeeled direct target that the advertised remote ref points to.
198
+ pub ( crate ) fn add_wants (
199
+ repo : & crate :: Repository ,
200
+ arguments : & mut gix_protocol:: fetch:: Arguments ,
201
+ ref_map : & fetch:: RefMap ,
202
+ mapping_known : & [ bool ] ,
203
+ shallow : & fetch:: Shallow ,
204
+ mapping_is_ignored : impl Fn ( & fetch:: Mapping ) -> bool ,
205
+ ) {
186
206
// When using shallow, we can't exclude `wants` as the remote won't send anything then. Thus we have to resend everything
187
207
// we have as want instead to get exactly the same graph, but possibly deepened.
188
208
let is_shallow = !matches ! ( shallow, fetch:: Shallow :: NoChange ) ;
189
209
let wants = ref_map
190
210
. mappings
191
211
. iter ( )
192
212
. zip ( mapping_known)
193
- . filter_map ( |( m, known) | ( is_shallow || !* known) . then_some ( m) ) ;
213
+ . filter_map ( |( m, known) | ( is_shallow || !* known) . then_some ( m) )
214
+ . filter ( |m| !mapping_is_ignored ( m) ) ;
194
215
for want in wants {
195
- // Here we ignore implicit tag mappings if needed.
196
- if tag_refspec_to_ignore. map_or ( false , |tag_spec| {
197
- want. spec_index
198
- . implicit_index ( )
199
- . and_then ( |idx| ref_map. extra_refspecs . get ( idx) )
200
- . map_or ( false , |spec| spec. to_ref ( ) == tag_spec)
201
- } ) {
202
- continue ;
203
- }
204
216
let id_on_remote = want. remote . as_id ( ) ;
205
217
if !arguments. can_use_ref_in_want ( ) || matches ! ( want. remote, fetch:: Source :: ObjectId ( _) ) {
206
218
if let Some ( id) = id_on_remote {
0 commit comments