Merge branch 'ph/use-delete-refs'

When removing many branches and tags, the code used to do so one
ref at a time.  There is another API it can use to delete multiple
refs, and it makes quite a lot of performance difference when the
refs are packed.

* ph/use-delete-refs:
  use delete_refs when deleting tags or branches
This commit is contained in:
Junio C Hamano 2021-02-05 16:40:45 -08:00
commit f6ef8baba2
2 changed files with 62 additions and 29 deletions

View File

@ -202,6 +202,9 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
int remote_branch = 0; int remote_branch = 0;
struct strbuf bname = STRBUF_INIT; struct strbuf bname = STRBUF_INIT;
unsigned allowed_interpret; unsigned allowed_interpret;
struct string_list refs_to_delete = STRING_LIST_INIT_DUP;
struct string_list_item *item;
int branch_name_pos;
switch (kinds) { switch (kinds) {
case FILTER_REFS_REMOTES: case FILTER_REFS_REMOTES:
@ -219,6 +222,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
default: default:
die(_("cannot use -a with -d")); die(_("cannot use -a with -d"));
} }
branch_name_pos = strcspn(fmt, "%");
if (!force) { if (!force) {
head_rev = lookup_commit_reference(the_repository, &head_oid); head_rev = lookup_commit_reference(the_repository, &head_oid);
@ -265,30 +269,35 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
goto next; goto next;
} }
if (delete_ref(NULL, name, is_null_oid(&oid) ? NULL : &oid, item = string_list_append(&refs_to_delete, name);
REF_NO_DEREF)) { item->util = xstrdup((flags & REF_ISBROKEN) ? "broken"
error(remote_branch
? _("Error deleting remote-tracking branch '%s'")
: _("Error deleting branch '%s'"),
bname.buf);
ret = 1;
goto next;
}
if (!quiet) {
printf(remote_branch
? _("Deleted remote-tracking branch %s (was %s).\n")
: _("Deleted branch %s (was %s).\n"),
bname.buf,
(flags & REF_ISBROKEN) ? "broken"
: (flags & REF_ISSYMREF) ? target : (flags & REF_ISSYMREF) ? target
: find_unique_abbrev(&oid, DEFAULT_ABBREV)); : find_unique_abbrev(&oid, DEFAULT_ABBREV));
}
delete_branch_config(bname.buf);
next: next:
free(target); free(target);
} }
if (delete_refs(NULL, &refs_to_delete, REF_NO_DEREF))
ret = 1;
for_each_string_list_item(item, &refs_to_delete) {
char *describe_ref = item->util;
char *name = item->string;
if (!ref_exists(name)) {
char *refname = name + branch_name_pos;
if (!quiet)
printf(remote_branch
? _("Deleted remote-tracking branch %s (was %s).\n")
: _("Deleted branch %s (was %s).\n"),
name + branch_name_pos, describe_ref);
delete_branch_config(refname);
}
free(describe_ref);
}
string_list_clear(&refs_to_delete, 0);
free(name); free(name);
strbuf_release(&bname); strbuf_release(&bname);

View File

@ -72,10 +72,10 @@ static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting,
} }
typedef int (*each_tag_name_fn)(const char *name, const char *ref, typedef int (*each_tag_name_fn)(const char *name, const char *ref,
const struct object_id *oid, const void *cb_data); const struct object_id *oid, void *cb_data);
static int for_each_tag_name(const char **argv, each_tag_name_fn fn, static int for_each_tag_name(const char **argv, each_tag_name_fn fn,
const void *cb_data) void *cb_data)
{ {
const char **p; const char **p;
struct strbuf ref = STRBUF_INIT; struct strbuf ref = STRBUF_INIT;
@ -97,18 +97,42 @@ static int for_each_tag_name(const char **argv, each_tag_name_fn fn,
return had_error; return had_error;
} }
static int delete_tag(const char *name, const char *ref, static int collect_tags(const char *name, const char *ref,
const struct object_id *oid, const void *cb_data) const struct object_id *oid, void *cb_data)
{ {
if (delete_ref(NULL, ref, oid, 0)) struct string_list *ref_list = cb_data;
return 1;
printf(_("Deleted tag '%s' (was %s)\n"), name, string_list_append(ref_list, ref);
find_unique_abbrev(oid, DEFAULT_ABBREV)); ref_list->items[ref_list->nr - 1].util = oiddup(oid);
return 0; return 0;
} }
static int delete_tags(const char **argv)
{
int result;
struct string_list refs_to_delete = STRING_LIST_INIT_DUP;
struct string_list_item *item;
result = for_each_tag_name(argv, collect_tags, (void *)&refs_to_delete);
if (delete_refs(NULL, &refs_to_delete, REF_NO_DEREF))
result = 1;
for_each_string_list_item(item, &refs_to_delete) {
const char *name = item->string;
struct object_id *oid = item->util;
if (!ref_exists(name))
printf(_("Deleted tag '%s' (was %s)\n"),
item->string + 10,
find_unique_abbrev(oid, DEFAULT_ABBREV));
free(oid);
}
string_list_clear(&refs_to_delete, 0);
return result;
}
static int verify_tag(const char *name, const char *ref, static int verify_tag(const char *name, const char *ref,
const struct object_id *oid, const void *cb_data) const struct object_id *oid, void *cb_data)
{ {
int flags; int flags;
const struct ref_format *format = cb_data; const struct ref_format *format = cb_data;
@ -512,7 +536,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
if (filter.reachable_from || filter.unreachable_from) if (filter.reachable_from || filter.unreachable_from)
die(_("--merged and --no-merged options are only allowed in list mode")); die(_("--merged and --no-merged options are only allowed in list mode"));
if (cmdmode == 'd') if (cmdmode == 'd')
return for_each_tag_name(argv, delete_tag, NULL); return delete_tags(argv);
if (cmdmode == 'v') { if (cmdmode == 'v') {
if (format.format && verify_ref_format(&format)) if (format.format && verify_ref_format(&format))
usage_with_options(git_tag_usage, options); usage_with_options(git_tag_usage, options);