fetch: only opportunistically update references based on command line

The old code processed (tags == TAGS_SET) before adding the entries used to opportunistically update references mentioned on the command line. The result was that all tags were also considered candidates for opportunistic updating. This is harmless for two reasons: (a) because it would only add entries if there is a configured refspec that covers tags *and* both --tags and another refspec appear on the command-line; (b) because any extra entries would be deleted later by the call to ref_remove_duplicates() anyway. But, to avoid extra work and extra memory usage, and to make the implementation better match the intention, change the algorithm slightly: compute the opportunistic refspecs based only on the command-line arguments, storing the results into a separate temporary list. Then add the tags (which have to come earlier in the list so that they are not de-duped in favor of an opportunistic entry). Then concatenate the temporary list onto the main list. This change will also make later changes easier. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Michael Haggerty committed Oct 30, 2013 at 06:32 UTC 0281c930f17042473e973f39810c8f7c93955d7d
1 file changed +32 -12
builtin/fetch.c
+32 -12
@@ -272,32 +272,50 @@ static struct ref *get_ref_map(struct transport *transport,
272 const struct ref *remote_refs = transport_get_remote_refs(transport);
273
274 if (refspec_count || tags == TAGS_SET) {
275 - struct ref **old_tail;
275 + /* opportunistically-updated references: */
276 + struct ref *orefs = NULL, **oref_tail = &orefs;
277
278 for (i = 0; i < refspec_count; i++) {
279 get_fetch_map(remote_refs, &refspecs[i], &tail, 0);
280 if (refspecs[i].dst && refspecs[i].dst[0])
281 *autotags = 1;
282 }
282 - /* Merge everything on the command line, but not --tags */
283 + /* Merge everything on the command line (but not --tags) */
284 for (rm = ref_map; rm; rm = rm->next)
285 rm->fetch_head_status = FETCH_HEAD_MERGE;
285 - if (tags == TAGS_SET)
286 - get_fetch_map(remote_refs, tag_refspec, &tail, 0);
286
287 /*
289 - * For any refs that we happen to be fetching via command-line
290 - * arguments, take the opportunity to update their configured
291 - * counterparts. However, we do not want to mention these
292 - * entries in FETCH_HEAD at all, as they would simply be
293 - * duplicates of existing entries.
288 + * For any refs that we happen to be fetching via
289 + * command-line arguments, the destination ref might
290 + * have been missing or have been different than the
291 + * remote-tracking ref that would be derived from the
292 + * configured refspec. In these cases, we want to
293 + * take the opportunity to update their configured
294 + * remote-tracking reference. However, we do not want
295 + * to mention these entries in FETCH_HEAD at all, as
296 + * they would simply be duplicates of existing
297 + * entries, so we set them FETCH_HEAD_IGNORE below.
298 + *
299 + * We compute these entries now, based only on the
300 + * refspecs specified on the command line. But we add
301 + * them to the list following the refspecs resulting
302 + * from the tags option so that one of the latter,
303 + * which has FETCH_HEAD_NOT_FOR_MERGE, is not removed
304 + * by ref_remove_duplicates() in favor of one of these
305 + * opportunistic entries with FETCH_HEAD_IGNORE.
306 */
295 - old_tail = tail;
307 for (i = 0; i < transport->remote->fetch_refspec_nr; i++)
308 get_fetch_map(ref_map, &transport->remote->fetch[i],
298 - &tail, 1);
299 - for (rm = *old_tail; rm; rm = rm->next)
309 + &oref_tail, 1);
310 +
311 + if (tags == TAGS_SET)
312 + get_fetch_map(remote_refs, tag_refspec, &tail, 0);
313 +
314 + *tail = orefs;
315 + for (rm = orefs; rm; rm = rm->next) {
316 rm->fetch_head_status = FETCH_HEAD_IGNORE;
317 + tail = &rm->next;
318 + }
319 } else {
320 /* Use the defaults */
321 struct remote *remote = transport->remote;
@@ -334,8 +352,10 @@ static struct ref *get_ref_map(struct transport *transport,
352 tail = &ref_map->next;
353 }
354 }
355 +
356 if (tags == TAGS_DEFAULT && *autotags)
357 find_non_local_tags(transport, &ref_map, &tail);
358 +
359 ref_remove_duplicates(ref_map);
360
361 return ref_map;