Skip to content

Commit e6bea66

Browse files
opera-jlgitster
authored andcommitted
remote prune: optimize "dangling symref" check/warning
When 'git remote prune' was used to delete many refs in a repository with many refs, a lot of time was spent checking for (now) dangling symbolic refs pointing to the deleted ref, since warn_dangling_symref() was once per deleted ref to check all other refs in the repository. Avoid this using the new warn_dangling_symrefs() function which makes one pass over all refs and checks for all the deleted refs in one go, after they have all been deleted. Signed-off-by: Jens Lindström <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent c9e768b commit e6bea66

File tree

3 files changed

+25
-2
lines changed

3 files changed

+25
-2
lines changed

builtin/remote.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1313,6 +1313,7 @@ static int prune_remote(const char *remote, int dry_run)
13131313
{
13141314
int result = 0, i;
13151315
struct ref_states states;
1316+
struct string_list delete_refs_list = STRING_LIST_INIT_NODUP;
13161317
const char **delete_refs;
13171318
const char *dangling_msg = dry_run
13181319
? _(" %s will become dangling!")
@@ -1339,6 +1340,8 @@ static int prune_remote(const char *remote, int dry_run)
13391340
for (i = 0; i < states.stale.nr; i++) {
13401341
const char *refname = states.stale.items[i].util;
13411342

1343+
string_list_insert(&delete_refs_list, refname);
1344+
13421345
if (!dry_run)
13431346
result |= delete_ref(refname, NULL, 0);
13441347

@@ -1348,9 +1351,11 @@ static int prune_remote(const char *remote, int dry_run)
13481351
else
13491352
printf_ln(_(" * [pruned] %s"),
13501353
abbrev_ref(refname, "refs/remotes/"));
1351-
warn_dangling_symref(stdout, dangling_msg, refname);
13521354
}
13531355

1356+
warn_dangling_symrefs(stdout, dangling_msg, &delete_refs_list);
1357+
string_list_clear(&delete_refs_list, 0);
1358+
13541359
free_remote_ref_states(&states);
13551360
return result;
13561361
}

refs.c

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1611,6 +1611,7 @@ int peel_ref(const char *refname, unsigned char *sha1)
16111611
struct warn_if_dangling_data {
16121612
FILE *fp;
16131613
const char *refname;
1614+
const struct string_list *refnames;
16141615
const char *msg_fmt;
16151616
};
16161617

@@ -1625,8 +1626,12 @@ static int warn_if_dangling_symref(const char *refname, const unsigned char *sha
16251626
return 0;
16261627

16271628
resolves_to = resolve_ref_unsafe(refname, junk, 0, NULL);
1628-
if (!resolves_to || strcmp(resolves_to, d->refname))
1629+
if (!resolves_to
1630+
|| (d->refname
1631+
? strcmp(resolves_to, d->refname)
1632+
: !string_list_has_string(d->refnames, resolves_to))) {
16291633
return 0;
1634+
}
16301635

16311636
fprintf(d->fp, d->msg_fmt, refname);
16321637
fputc('\n', d->fp);
@@ -1639,6 +1644,18 @@ void warn_dangling_symref(FILE *fp, const char *msg_fmt, const char *refname)
16391644

16401645
data.fp = fp;
16411646
data.refname = refname;
1647+
data.refnames = NULL;
1648+
data.msg_fmt = msg_fmt;
1649+
for_each_rawref(warn_if_dangling_symref, &data);
1650+
}
1651+
1652+
void warn_dangling_symrefs(FILE *fp, const char *msg_fmt, const struct string_list *refnames)
1653+
{
1654+
struct warn_if_dangling_data data;
1655+
1656+
data.fp = fp;
1657+
data.refname = NULL;
1658+
data.refnames = refnames;
16421659
data.msg_fmt = msg_fmt;
16431660
for_each_rawref(warn_if_dangling_symref, &data);
16441661
}

refs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ static inline const char *has_glob_specials(const char *pattern)
8989
extern int for_each_rawref(each_ref_fn, void *);
9090

9191
extern void warn_dangling_symref(FILE *fp, const char *msg_fmt, const char *refname);
92+
extern void warn_dangling_symrefs(FILE *fp, const char *msg_fmt, const struct string_list* refnames);
9293

9394
/*
9495
* Lock the packed-refs file for writing. Flags is passed to

0 commit comments

Comments
 (0)