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 <jl@opera.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Jens Lindström committed
May 23, 2014 at 12:30 UTC
e6bea66db6229a0975ebba510a1d2827bf09cb7f
3 files changed
+25
-2
builtin/remote.c
+6
-1
@@ -1313,6 +1313,7 @@ static int prune_remote(const char *remote, int dry_run)
1313
{
1314
int result = 0, i;
1315
struct ref_states states;
1316
+ struct string_list delete_refs_list = STRING_LIST_INIT_NODUP;
1317
const char **delete_refs;
1318
const char *dangling_msg = dry_run
1319
? _(" %s will become dangling!")
@@ -1339,6 +1340,8 @@ static int prune_remote(const char *remote, int dry_run)
1340
for (i = 0; i < states.stale.nr; i++) {
1341
const char *refname = states.stale.items[i].util;
1342
1343
+ string_list_insert(&delete_refs_list, refname);
1344
+
1345
if (!dry_run)
1346
result |= delete_ref(refname, NULL, 0);
1347
@@ -1348,9 +1351,11 @@ static int prune_remote(const char *remote, int dry_run)
1351
else
1352
printf_ln(_(" * [pruned] %s"),
1353
abbrev_ref(refname, "refs/remotes/"));
1351
- warn_dangling_symref(stdout, dangling_msg, refname);
1354
}
1355
1356
+ warn_dangling_symrefs(stdout, dangling_msg, &delete_refs_list);
1357
+ string_list_clear(&delete_refs_list, 0);
1358
+
1359
free_remote_ref_states(&states);
1360
return result;
1361
}
refs.c
+18
-1
@@ -1611,6 +1611,7 @@ int peel_ref(const char *refname, unsigned char *sha1)
1611
struct warn_if_dangling_data {
1612
FILE *fp;
1613
const char *refname;
1614
+ const struct string_list *refnames;
1615
const char *msg_fmt;
1616
};
1617
@@ -1625,8 +1626,12 @@ static int warn_if_dangling_symref(const char *refname, const unsigned char *sha
1626
return 0;
1627
1628
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))) {
1633
return 0;
1634
+ }
1635
1636
fprintf(d->fp, d->msg_fmt, refname);
1637
fputc('\n', d->fp);
@@ -1639,6 +1644,18 @@ void warn_dangling_symref(FILE *fp, const char *msg_fmt, const char *refname)
1644
1645
data.fp = fp;
1646
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;
1659
data.msg_fmt = msg_fmt;
1660
for_each_rawref(warn_if_dangling_symref, &data);
1661
}
refs.h
+1
@@ -89,6 +89,7 @@ static inline const char *has_glob_specials(const char *pattern)
89
extern int for_each_rawref(each_ref_fn, void *);
90
91
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);
93
94
/*
95
* Lock the packed-refs file for writing. Flags is passed to