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
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;
struct ref *ref, *stale_refs = get_stale_heads(rs, ref_map);
struct strbuf err = STRBUF_INIT;
const char *dangling_msg = dry_run
? _(" (%s will become dangling)")
: _(" (%s has become dangling)");
struct string_list refnames = STRING_LIST_INIT_NODUP;
for (ref = stale_refs; ref; ref = ref->next)
string_list_append(&refnames, ref->name);
if (!dry_run) {
if (transaction) {
@@ -1353,15 +1354,9 @@ static int prune_refs(struct display_state *display_state,
goto cleanup;
}
} 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),
"fetch: prune", &refnames,
0);
string_list_clear(&refnames, 0);
}
}
@@ -1373,12 +1368,14 @@ static int prune_refs(struct display_state *display_state,
_("(none)"), ref->name,
&ref->new_oid, &ref->old_oid,
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:
string_list_clear(&refnames, 0);
strbuf_release(&err);
free_refs(stale_refs);
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 string_list refs_to_prune = STRING_LIST_INIT_NODUP;
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);
@@ -1555,7 +1552,7 @@ static int prune_remote(const char *remote, int dry_run)
}
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);
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 ref_store *refs;
FILE *fp;
const char *refname;
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,
@@ -449,44 +449,34 @@ static int warn_if_dangling_symref(const char *refname, const char *referent UNU
int flags, void *cb_data)
{
struct warn_if_dangling_data *d = cb_data;
const char *resolves_to;
const char *resolves_to, *msg;
if (!(flags & REF_ISSYMREF))
return 0;
resolves_to = refs_resolve_ref_unsafe(d->refs, refname, 0, NULL, NULL);
if (!resolves_to
|| (d->refname
? strcmp(resolves_to, d->refname)
: !string_list_has_string(d->refnames, resolves_to))) {
|| !string_list_has_string(d->refnames, resolves_to)) {
return 0;
}
fprintf(d->fp, d->msg_fmt, refname);
fputc('\n', d->fp);
msg = d->dry_run
? _("%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;
}
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,
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 = {
.refs = refs,
.fp = fp,
.refnames = refnames,
.msg_fmt = msg_fmt,
.indent = indent,
.dry_run = dry_run,
};
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, "?*[");
}
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,
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()