Merge branch 'ph/fetch-prune-optim'

"git fetch --prune" used to be O(n^2) expensive when there are many
refs, which has been corrected.

* ph/fetch-prune-optim:
  clean up interface for refs_warn_dangling_symrefs
  refs: remove old refs_warn_dangling_symref
  fetch-prune: optimize dangling-ref reporting
This commit is contained in:
Junio C Hamano 2025-07-16 09:42:26 -07:00
commit 7b625c2a35
4 changed files with 23 additions and 40 deletions

View File

@ -1340,9 +1340,10 @@ static int prune_refs(struct display_state *display_state,
int result = 0; int result = 0;
struct ref *ref, *stale_refs = get_stale_heads(rs, ref_map); struct ref *ref, *stale_refs = get_stale_heads(rs, ref_map);
struct strbuf err = STRBUF_INIT; struct strbuf err = STRBUF_INIT;
const char *dangling_msg = dry_run struct string_list refnames = STRING_LIST_INIT_NODUP;
? _(" (%s will become dangling)")
: _(" (%s has become dangling)"); for (ref = stale_refs; ref; ref = ref->next)
string_list_append(&refnames, ref->name);
if (!dry_run) { if (!dry_run) {
if (transaction) { if (transaction) {
@ -1353,15 +1354,9 @@ static int prune_refs(struct display_state *display_state,
goto cleanup; goto cleanup;
} }
} else { } else {
struct string_list refnames = STRING_LIST_INIT_NODUP;
for (ref = stale_refs; ref; ref = ref->next)
string_list_append(&refnames, ref->name);
result = refs_delete_refs(get_main_ref_store(the_repository), result = refs_delete_refs(get_main_ref_store(the_repository),
"fetch: prune", &refnames, "fetch: prune", &refnames,
0); 0);
string_list_clear(&refnames, 0);
} }
} }
@ -1373,12 +1368,14 @@ static int prune_refs(struct display_state *display_state,
_("(none)"), ref->name, _("(none)"), ref->name,
&ref->new_oid, &ref->old_oid, &ref->new_oid, &ref->old_oid,
summary_width); summary_width);
refs_warn_dangling_symref(get_main_ref_store(the_repository),
stderr, dangling_msg, ref->name);
} }
string_list_sort(&refnames);
refs_warn_dangling_symrefs(get_main_ref_store(the_repository),
stderr, " ", dry_run, &refnames);
} }
cleanup: cleanup:
string_list_clear(&refnames, 0);
strbuf_release(&err); strbuf_release(&err);
free_refs(stale_refs); free_refs(stale_refs);
return result; return result;

View File

@ -1521,9 +1521,6 @@ static int prune_remote(const char *remote, int dry_run)
struct ref_states states = REF_STATES_INIT; struct ref_states states = REF_STATES_INIT;
struct string_list refs_to_prune = STRING_LIST_INIT_NODUP; struct string_list refs_to_prune = STRING_LIST_INIT_NODUP;
struct string_list_item *item; struct string_list_item *item;
const char *dangling_msg = dry_run
? _(" %s will become dangling!")
: _(" %s has become dangling!");
get_remote_ref_states(remote, &states, GET_REF_STATES); get_remote_ref_states(remote, &states, GET_REF_STATES);
@ -1555,7 +1552,7 @@ static int prune_remote(const char *remote, int dry_run)
} }
refs_warn_dangling_symrefs(get_main_ref_store(the_repository), refs_warn_dangling_symrefs(get_main_ref_store(the_repository),
stdout, dangling_msg, &refs_to_prune); stdout, " ", dry_run, &refs_to_prune);
string_list_clear(&refs_to_prune, 0); string_list_clear(&refs_to_prune, 0);
free_remote_ref_states(&states); free_remote_ref_states(&states);

34
refs.c
View File

@ -439,9 +439,9 @@ static int for_each_filter_refs(const char *refname, const char *referent,
struct warn_if_dangling_data { struct warn_if_dangling_data {
struct ref_store *refs; struct ref_store *refs;
FILE *fp; FILE *fp;
const char *refname;
const struct string_list *refnames; const struct string_list *refnames;
const char *msg_fmt; const char *indent;
int dry_run;
}; };
static int warn_if_dangling_symref(const char *refname, const char *referent UNUSED, static int warn_if_dangling_symref(const char *refname, const char *referent UNUSED,
@ -449,44 +449,34 @@ static int warn_if_dangling_symref(const char *refname, const char *referent UNU
int flags, void *cb_data) int flags, void *cb_data)
{ {
struct warn_if_dangling_data *d = cb_data; struct warn_if_dangling_data *d = cb_data;
const char *resolves_to; const char *resolves_to, *msg;
if (!(flags & REF_ISSYMREF)) if (!(flags & REF_ISSYMREF))
return 0; return 0;
resolves_to = refs_resolve_ref_unsafe(d->refs, refname, 0, NULL, NULL); resolves_to = refs_resolve_ref_unsafe(d->refs, refname, 0, NULL, NULL);
if (!resolves_to if (!resolves_to
|| (d->refname || !string_list_has_string(d->refnames, resolves_to)) {
? strcmp(resolves_to, d->refname)
: !string_list_has_string(d->refnames, resolves_to))) {
return 0; return 0;
} }
fprintf(d->fp, d->msg_fmt, refname); msg = d->dry_run
fputc('\n', d->fp); ? _("%s%s will become dangling after %s is deleted\n")
: _("%s%s has become dangling after %s was deleted\n");
fprintf(d->fp, msg, d->indent, refname, resolves_to);
return 0; return 0;
} }
void refs_warn_dangling_symref(struct ref_store *refs, FILE *fp,
const char *msg_fmt, const char *refname)
{
struct warn_if_dangling_data data = {
.refs = refs,
.fp = fp,
.refname = refname,
.msg_fmt = msg_fmt,
};
refs_for_each_rawref(refs, warn_if_dangling_symref, &data);
}
void refs_warn_dangling_symrefs(struct ref_store *refs, FILE *fp, void refs_warn_dangling_symrefs(struct ref_store *refs, FILE *fp,
const char *msg_fmt, const struct string_list *refnames) const char *indent, int dry_run,
const struct string_list *refnames)
{ {
struct warn_if_dangling_data data = { struct warn_if_dangling_data data = {
.refs = refs, .refs = refs,
.fp = fp, .fp = fp,
.refnames = refnames, .refnames = refnames,
.msg_fmt = msg_fmt, .indent = indent,
.dry_run = dry_run,
}; };
refs_for_each_rawref(refs, warn_if_dangling_symref, &data); refs_for_each_rawref(refs, warn_if_dangling_symref, &data);
} }

5
refs.h
View File

@ -452,10 +452,9 @@ static inline const char *has_glob_specials(const char *pattern)
return strpbrk(pattern, "?*["); return strpbrk(pattern, "?*[");
} }
void refs_warn_dangling_symref(struct ref_store *refs, FILE *fp,
const char *msg_fmt, const char *refname);
void refs_warn_dangling_symrefs(struct ref_store *refs, FILE *fp, void refs_warn_dangling_symrefs(struct ref_store *refs, FILE *fp,
const char *msg_fmt, const struct string_list *refnames); const char *indent, int dry_run,
const struct string_list *refnames);
/* /*
* Flags for controlling behaviour of pack_refs() * Flags for controlling behaviour of pack_refs()