Skip to content

Commit cc7dc40

Browse files
phordgitster
authored andcommitted
fetch-prune: optimize dangling-ref reporting
When pruning during `git fetch` we check each pruned ref against the ref_store one at a time to decide whether to report it as dangling. This causes every local ref to be scanned for each ref being pruned. If there are N refs in the repo and M refs being pruned, this code is O(M*N). However, `git remote prune` uses a very similar function that is only O(N*log(M)). Remove the wasteful ref scanning for each pruned ref and use the faster version already available in refs_warn_dangling_symrefs. Change the message to include the original refname since the message is no longer printed immediately after the line that did just print the refname. In a repo with 126,000 refs, where I was pruning 28,000 refs, this code made about 3.6 billion calls to strcmp and consumed 410 seconds of CPU. (Invariably in that time, my remote would timeout and the fetch would fail anyway.) After this change, the same operation completes in under a second. Signed-off-by: Phil Hord <[email protected]> Reviewed-by: Jacob Keller <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent f93ff17 commit cc7dc40

File tree

3 files changed

+13
-13
lines changed

3 files changed

+13
-13
lines changed

builtin/fetch.c

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1384,9 +1384,13 @@ static int prune_refs(struct display_state *display_state,
13841384
int result = 0;
13851385
struct ref *ref, *stale_refs = get_stale_heads(rs, ref_map);
13861386
struct strbuf err = STRBUF_INIT;
1387+
struct string_list refnames = STRING_LIST_INIT_NODUP;
13871388
const char *dangling_msg = dry_run
1388-
? _(" (%s will become dangling)")
1389-
: _(" (%s has become dangling)");
1389+
? _(" %s will become dangling after %s is deleted")
1390+
: _(" %s has become dangling after %s was deleted");
1391+
1392+
for (ref = stale_refs; ref; ref = ref->next)
1393+
string_list_append(&refnames, ref->name);
13901394

13911395
if (!dry_run) {
13921396
if (transaction) {
@@ -1397,15 +1401,9 @@ static int prune_refs(struct display_state *display_state,
13971401
goto cleanup;
13981402
}
13991403
} else {
1400-
struct string_list refnames = STRING_LIST_INIT_NODUP;
1401-
1402-
for (ref = stale_refs; ref; ref = ref->next)
1403-
string_list_append(&refnames, ref->name);
1404-
14051404
result = refs_delete_refs(get_main_ref_store(the_repository),
14061405
"fetch: prune", &refnames,
14071406
0);
1408-
string_list_clear(&refnames, 0);
14091407
}
14101408
}
14111409

@@ -1417,12 +1415,14 @@ static int prune_refs(struct display_state *display_state,
14171415
_("(none)"), ref->name,
14181416
&ref->new_oid, &ref->old_oid,
14191417
summary_width);
1420-
refs_warn_dangling_symref(get_main_ref_store(the_repository),
1421-
stderr, dangling_msg, ref->name);
14221418
}
1419+
string_list_sort(&refnames);
1420+
refs_warn_dangling_symrefs(get_main_ref_store(the_repository),
1421+
stderr, dangling_msg, &refnames);
14231422
}
14241423

14251424
cleanup:
1425+
string_list_clear(&refnames, 0);
14261426
strbuf_release(&err);
14271427
free_refs(stale_refs);
14281428
return result;

builtin/remote.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1516,8 +1516,8 @@ static int prune_remote(const char *remote, int dry_run)
15161516
struct string_list refs_to_prune = STRING_LIST_INIT_NODUP;
15171517
struct string_list_item *item;
15181518
const char *dangling_msg = dry_run
1519-
? _(" %s will become dangling!")
1520-
: _(" %s has become dangling!");
1519+
? _(" %s will become dangling after %s is deleted!")
1520+
: _(" %s has become dangling after %s was deleted!");
15211521

15221522
get_remote_ref_states(remote, &states, GET_REF_STATES);
15231523

refs.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,7 @@ static int warn_if_dangling_symref(const char *refname, const char *referent UNU
461461
return 0;
462462
}
463463

464-
fprintf(d->fp, d->msg_fmt, refname);
464+
fprintf(d->fp, d->msg_fmt, refname, resolves_to);
465465
fputc('\n', d->fp);
466466
return 0;
467467
}

0 commit comments

Comments
 (0)