diff --git a/refs/files-backend.c b/refs/files-backend.c
index 8db7882aacb..5c23277eda7 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -1265,44 +1265,39 @@ static int files_delete_refs(struct ref_store *ref_store, const char *msg,
 	struct files_ref_store *refs =
 		files_downcast(ref_store, REF_STORE_WRITE, "delete_refs");
 	struct strbuf err = STRBUF_INIT;
-	int i, result = 0;
+	int i;
+	struct ref_transaction *transaction;
 
 	if (!refnames->nr)
 		return 0;
 
-	if (packed_refs_lock(refs->packed_ref_store, 0, &err))
-		goto error;
-
-	if (refs_delete_refs(refs->packed_ref_store, msg, refnames, flags)) {
-		packed_refs_unlock(refs->packed_ref_store);
+	transaction = ref_store_transaction_begin(&refs->base, &err);
+	if (!transaction)
 		goto error;
-	}
-
-	packed_refs_unlock(refs->packed_ref_store);
 
 	for (i = 0; i < refnames->nr; i++) {
 		const char *refname = refnames->items[i].string;
-
-		if (refs_delete_ref(&refs->base, msg, refname, NULL, flags))
-			result |= error(_("could not remove reference %s"), refname);
+		if (ref_transaction_delete(transaction, refname, NULL,
+					   flags, msg, &err))
+			goto error;
 	}
 
+	if (ref_transaction_commit(transaction, &err))
+		goto error;
+
+	ref_transaction_free(transaction);
 	strbuf_release(&err);
-	return result;
+	return 0;
 
 error:
-	/*
-	 * If we failed to rewrite the packed-refs file, then it is
-	 * unsafe to try to remove loose refs, because doing so might
-	 * expose an obsolete packed value for a reference that might
-	 * even point at an object that has been garbage collected.
-	 */
 	if (refnames->nr == 1)
 		error(_("could not delete reference %s: %s"),
 		      refnames->items[0].string, err.buf);
 	else
 		error(_("could not delete references: %s"), err.buf);
 
+	if (transaction)
+		ref_transaction_free(transaction);
 	strbuf_release(&err);
 	return -1;
 }
diff --git a/t/t1416-ref-transaction-hooks.sh b/t/t1416-ref-transaction-hooks.sh
index 27731722a5b..e3d4fe624f7 100755
--- a/t/t1416-ref-transaction-hooks.sh
+++ b/t/t1416-ref-transaction-hooks.sh
@@ -133,4 +133,74 @@ test_expect_success 'interleaving hook calls succeed' '
 	test_cmp expect target-repo.git/actual
 '
 
+test_expect_success 'hook allows deleting loose ref if successful' '
+	test_when_finished "rm actual" &&
+	git branch to-be-deleted $PRE_OID &&
+	test_hook reference-transaction <<-\EOF &&
+		echo "$*" >>actual
+	EOF
+	cat >expect <<-EOF &&
+		aborted
+		prepared
+		committed
+	EOF
+	git branch -d to-be-deleted &&
+	test_cmp expect actual &&
+	test_must_fail git rev-parse refs/heads/to-be-deleted
+'
+
+test_expect_success 'hook allows deleting packed ref if successful' '
+	test_when_finished "rm actual" &&
+	git branch to-be-deleted $PRE_OID &&
+	git pack-refs --all --prune &&
+	test_hook reference-transaction <<-\EOF &&
+		echo "$*" >>actual
+	EOF
+	cat >expect <<-EOF &&
+		prepared
+		prepared
+		committed
+		committed
+	EOF
+	git branch -d to-be-deleted &&
+	test_cmp expect actual &&
+	test_must_fail git rev-parse refs/heads/to-be-deleted
+'
+
+test_expect_success 'hook aborts deleting loose ref in prepared state' '
+	test_when_finished "rm actual" &&
+	test_when_finished "git branch -d to-be-deleted" &&
+	git branch to-be-deleted $PRE_OID &&
+	test_hook reference-transaction <<-\EOF &&
+		echo "$*" >>actual
+		exit 1
+	EOF
+	cat >expect <<-EOF &&
+		aborted
+		prepared
+		aborted
+	EOF
+	test_must_fail git branch -d to-be-deleted &&
+	test_cmp expect actual &&
+	git rev-parse refs/heads/to-be-deleted
+'
+
+test_expect_success 'hook aborts deleting packed ref in prepared state' '
+	test_when_finished "rm actual" &&
+	test_when_finished "git branch -d to-be-deleted" &&
+	git branch to-be-deleted $PRE_OID &&
+	git pack-refs --all --prune &&
+	test_hook reference-transaction <<-\EOF &&
+		echo "$*" >>actual
+		exit 1
+	EOF
+	cat >expect <<-EOF &&
+		prepared
+		aborted
+	EOF
+	test_must_fail git branch -d to-be-deleted &&
+	test_cmp expect actual &&
+	git rev-parse refs/heads/to-be-deleted
+'
+
 test_done
diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh
index 4620f0ca7fa..8b09a99c2e8 100755
--- a/t/t5510-fetch.sh
+++ b/t/t5510-fetch.sh
@@ -169,10 +169,10 @@ test_expect_success REFFILES 'fetch --prune fails to delete branches' '
 	git clone . prune-fail &&
 	cd prune-fail &&
 	git update-ref refs/remotes/origin/extrabranch main &&
-	: this will prevent --prune from locking packed-refs for deleting refs, but adding loose refs still succeeds  &&
-	>.git/packed-refs.new &&
+	: this will prevent --prune from locking refs/remotes/origin/extra for deletion &&
+	>.git/refs/remotes/origin/extrabranch.lock &&
 
-	test_must_fail git fetch --prune origin
+	test_must_fail git fetch --prune origin > outputs 2> errors
 '
 
 test_expect_success 'fetch --atomic works with a single branch' '
