git@vger.kernel.org list mirror (unofficial, one of many)
 help / color / mirror / Atom feed
* [PATCH 1/1] delete multiple tags in a single transaction
@ 2019-08-08  3:59 Phil Hord
  2019-08-08 12:47 ` Martin Ågren
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Phil Hord @ 2019-08-08  3:59 UTC (permalink / raw)
  To: git; +Cc: Phil Hord

From: Phil Hord <phil.hord@gmail.com>

'git tag -d' accepts one or more tag refs to delete, but each deletion
is done by calling `delete_ref` on each argv. This is painfully slow
when removing from packed refs. Use delete_refs instead so all the
removals can be done inside a single transaction with a single write.

I have a repo with 24,000 tags, most of which are not useful to any
developers. Having this many refs slows down many operations that
would otherwise be very fast. Removing these tags when they've been
accidentally fetched again takes about 30 minutes using delete_ref.

    git tag -l feature/* | xargs git tag -d

Removing the same tags using delete_refs takes less than 5 seconds.

Signed-off-by: Phil Hord <phil.hord@gmail.com>
---
 builtin/tag.c | 52 +++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 42 insertions(+), 10 deletions(-)

diff --git a/builtin/tag.c b/builtin/tag.c
index e0a4c25382..f652af83e7 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -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,
-				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,
-			     const void *cb_data)
+			     void *cb_data)
 {
 	const char **p;
 	struct strbuf ref = STRBUF_INIT;
@@ -97,18 +97,50 @@ static int for_each_tag_name(const char **argv, each_tag_name_fn fn,
 	return had_error;
 }
 
-static int delete_tag(const char *name, const char *ref,
-		      const struct object_id *oid, const void *cb_data)
+struct tag_args {
+	char *oid_abbrev;
+	char *refname;
+};
+
+static int make_string_list(const char *name, const char *ref,
+			    const struct object_id *oid, void *cb_data)
 {
-	if (delete_ref(NULL, ref, oid, 0))
-		return 1;
-	printf(_("Deleted tag '%s' (was %s)\n"), name,
-	       find_unique_abbrev(oid, DEFAULT_ABBREV));
+	struct string_list *ref_list = cb_data;
+	struct tag_args *info = xmalloc(sizeof(struct tag_args));
+
+	string_list_append(ref_list, ref);
+
+	info->oid_abbrev = xstrdup(find_unique_abbrev(oid, DEFAULT_ABBREV));
+	info->refname = xstrdup(name);
+	ref_list->items[ref_list->nr - 1].util = info;
 	return 0;
 }
 
+static int delete_tags(const char **argv)
+{
+	int result;
+	struct string_list ref_list = STRING_LIST_INIT_DUP;
+	struct string_list_item *ref_list_item;
+
+	result = for_each_tag_name(argv, make_string_list, (void *) &ref_list);
+	if (!result)
+		result = delete_refs(NULL, &ref_list, REF_NO_DEREF);
+
+	for_each_string_list_item(ref_list_item, &ref_list) {
+		struct tag_args * info = ref_list_item->util;
+		if (!result)
+			printf(_("Deleted tag '%s' (was %s)\n"), info->refname,
+				info->oid_abbrev);
+		free(info->oid_abbrev);
+		free(info->refname);
+		free(info);
+	}
+	string_list_clear(&ref_list, 0);
+	return result;
+}
+
 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;
 	const struct ref_format *format = cb_data;
@@ -511,7 +543,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
 	if (filter.merge_commit)
 		die(_("--merged and --no-merged options are only allowed in list mode"));
 	if (cmdmode == 'd')
-		return for_each_tag_name(argv, delete_tag, NULL);
+		return delete_tags(argv);
 	if (cmdmode == 'v') {
 		if (format.format && verify_ref_format(&format))
 			usage_with_options(git_tag_usage, options);
-- 
2.23.0.rc1.174.g4cc1b04b4c.dirty


^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2019-08-09  3:05 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-08-08  3:59 [PATCH 1/1] delete multiple tags in a single transaction Phil Hord
2019-08-08 12:47 ` Martin Ågren
2019-08-08 12:53   ` [PATCH] t7004: check existence of correct tag Martin Ågren
2019-08-08 18:15 ` [PATCH 1/1] delete multiple tags in a single transaction Elijah Newren
2019-08-08 23:43   ` Phil Hord
2019-08-09  3:05     ` Jeff King
2019-08-08 19:39 ` Junio C Hamano
2019-08-08 23:58   ` Phil Hord

git@vger.kernel.org list mirror (unofficial, one of many)

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://public-inbox.org/git
	git clone --mirror http://ou63pmih66umazou.onion/git
	git clone --mirror http://czquwvybam4bgbro.onion/git
	git clone --mirror http://hjrcffqmbrq6wope.onion/git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V1 git git/ https://public-inbox.org/git \
		git@vger.kernel.org
	public-inbox-index git

Example config snippet for mirrors.
Newsgroups are available over NNTP:
	nntp://news.public-inbox.org/inbox.comp.version-control.git
	nntp://ou63pmih66umazou.onion/inbox.comp.version-control.git
	nntp://czquwvybam4bgbro.onion/inbox.comp.version-control.git
	nntp://hjrcffqmbrq6wope.onion/inbox.comp.version-control.git
	nntp://news.gmane.io/gmane.comp.version-control.git
 note: .onion URLs require Tor: https://www.torproject.org/

code repositories for the project(s) associated with this inbox:

	https://80x24.org/mirrors/git.git

AGPL code for this site: git clone https://public-inbox.org/public-inbox.git