@@ -1268,31 +1268,27 @@ static int files_pack_refs(struct ref_store *ref_store, unsigned int flags)
static int files_delete_refs(struct ref_store *ref_store, const char *msg,
struct string_list *refnames, unsigned int flags)
{
- struct files_ref_store *refs =
- files_downcast(ref_store, REF_STORE_WRITE, "delete_refs");
+ struct ref_transaction *transaction;
struct strbuf err = STRBUF_INIT;
int i, result = 0;
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(ref_store, &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))
+ if (ref_transaction_delete(transaction, refname, NULL,
+ flags, msg, &err))
result |= error(_("could not remove reference %s"), refname);
}
+ if (ref_transaction_commit(transaction, &err))
+ goto error;
+ ref_transaction_free(transaction);
strbuf_release(&err);
return result;
@@ -1309,6 +1305,7 @@ static int files_delete_refs(struct ref_store *ref_store, const char *msg,
else
error(_("could not delete references: %s"), err.buf);
+ ref_transaction_free(transaction);
strbuf_release(&err);
return -1;
}
@@ -1519,55 +1519,6 @@ static int packed_initial_transaction_commit(struct ref_store *ref_store,
return ref_transaction_commit(transaction, err);
}
-static int packed_delete_refs(struct ref_store *ref_store, const char *msg,
- struct string_list *refnames, unsigned int flags)
-{
- struct packed_ref_store *refs =
- packed_downcast(ref_store, REF_STORE_WRITE, "delete_refs");
- struct strbuf err = STRBUF_INIT;
- struct ref_transaction *transaction;
- struct string_list_item *item;
- int ret;
-
- (void)refs; /* We need the check above, but don't use the variable */
-
- if (!refnames->nr)
- return 0;
-
- /*
- * Since we don't check the references' old_oids, the
- * individual updates can't fail, so we can pack all of the
- * updates into a single transaction.
- */
-
- transaction = ref_store_transaction_begin(ref_store, &err);
- if (!transaction)
- return -1;
-
- for_each_string_list_item(item, refnames) {
- if (ref_transaction_delete(transaction, item->string, NULL,
- flags, msg, &err)) {
- warning(_("could not delete reference %s: %s"),
- item->string, err.buf);
- strbuf_reset(&err);
- }
- }
-
- ret = ref_transaction_commit(transaction, &err);
-
- if (ret) {
- 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);
- }
-
- ref_transaction_free(transaction);
- strbuf_release(&err);
- return ret;
-}
-
static int packed_pack_refs(struct ref_store *ref_store, unsigned int flags)
{
/*
@@ -1595,7 +1546,7 @@ struct ref_storage_be refs_be_packed = {
.pack_refs = packed_pack_refs,
.create_symref = NULL,
- .delete_refs = packed_delete_refs,
+ .delete_refs = NULL,
.rename_ref = NULL,
.copy_ref = NULL,
@@ -789,39 +789,7 @@ test_expect_success "branch: rename branches" '
test_cmp_heads_and_tags -C workdir expect
'
-# Mismatched hook output for "git branch -d":
-#
-# * The delete branches operation should be treated as one transaction,
-# but was splitted into several transactions on loose references,
-# and the "reference-transaction committed" command was executed
-# redundantly on the packed-ref-store.
-#
-# The differences are as follows:
-#
-# @@ -2,11 +2,19 @@
-# <ZERO-OID> <ZERO-OID> refs/heads/topic1
-# <ZERO-OID> <ZERO-OID> refs/heads/topic2
-# <ZERO-OID> <ZERO-OID> refs/heads/topic3
-# +## Call hook: reference-transaction committed ##
-# +<ZERO-OID> <ZERO-OID> refs/heads/topic1
-# +<ZERO-OID> <ZERO-OID> refs/heads/topic2
-# +<ZERO-OID> <ZERO-OID> refs/heads/topic3
-# +## Call hook: reference-transaction prepared ##
-# +<ZERO-OID> <ZERO-OID> refs/heads/topic1
-# +## Call hook: reference-transaction committed ##
-# +<ZERO-OID> <ZERO-OID> refs/heads/topic1
-# ## Call hook: reference-transaction prepared ##
-# -<COMMIT-A> <ZERO-OID> refs/heads/topic1
-# <COMMIT-B> <ZERO-OID> refs/heads/topic2
-# -<COMMIT-C> <ZERO-OID> refs/heads/topic3
-# ## Call hook: reference-transaction committed ##
-# -<COMMIT-A> <ZERO-OID> refs/heads/topic1
-# <COMMIT-B> <ZERO-OID> refs/heads/topic2
-# +## Call hook: reference-transaction prepared ##
-# +<COMMIT-C> <ZERO-OID> refs/heads/topic3
-# +## Call hook: reference-transaction committed ##
-# <COMMIT-C> <ZERO-OID> refs/heads/topic3
-test_expect_failure "branch: remove branches" '
+test_expect_success "branch: remove branches" '
test_when_finished "rm -f $HOOK_OUTPUT" &&
cat >expect <<-\EOF &&
@@ -950,39 +918,7 @@ test_expect_success "tag: update refs to create loose refs" '
test_cmp_heads_and_tags -C workdir expect
'
-# Mismatched hook output for "git tag -d":
-#
-# * The delete tags operation should be treated as one transaction,
-# but was splitted into several transactions on loose references,
-# and the "reference-transaction committed" command was executed
-# redundantly on the packed-ref-store.
-#
-# The differences are as follows:
-#
-# @@ -2,11 +2,19 @@
-# <ZERO-OID> <ZERO-OID> refs/tags/v1
-# <ZERO-OID> <ZERO-OID> refs/tags/v2
-# <ZERO-OID> <ZERO-OID> refs/tags/v3
-# +## Call hook: reference-transaction committed ##
-# +<ZERO-OID> <ZERO-OID> refs/tags/v1
-# +<ZERO-OID> <ZERO-OID> refs/tags/v2
-# +<ZERO-OID> <ZERO-OID> refs/tags/v3
-# +## Call hook: reference-transaction prepared ##
-# +<ZERO-OID> <ZERO-OID> refs/tags/v1
-# +## Call hook: reference-transaction committed ##
-# +<ZERO-OID> <ZERO-OID> refs/tags/v1
-# ## Call hook: reference-transaction prepared ##
-# -<COMMIT-A> <ZERO-OID> refs/tags/v1
-# <COMMIT-B> <ZERO-OID> refs/tags/v2
-# -<COMMIT-C> <ZERO-OID> refs/tags/v3
-# ## Call hook: reference-transaction committed ##
-# -<COMMIT-A> <ZERO-OID> refs/tags/v1
-# <COMMIT-B> <ZERO-OID> refs/tags/v2
-# +## Call hook: reference-transaction prepared ##
-# +<COMMIT-C> <ZERO-OID> refs/tags/v3
-# +## Call hook: reference-transaction committed ##
-# <COMMIT-C> <ZERO-OID> refs/tags/v3
-test_expect_failure "tag: remove tags with mixed ref_stores" '
+test_expect_success "tag: remove tags with mixed ref_stores" '
test_when_finished "rm -f $HOOK_OUTPUT" &&
cat >expect <<-\EOF &&
@@ -168,6 +168,8 @@ test_expect_success REFFILES 'fetch --prune fails to delete branches' '
cd "$D" &&
git clone . prune-fail &&
cd prune-fail &&
+ git update-ref refs/remotes/origin/extrabranch main~ &&
+ git pack-refs --all &&
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 &&
@@ -175,6 +177,20 @@ test_expect_success REFFILES 'fetch --prune fails to delete branches' '
test_must_fail git fetch --prune origin
'
+test_expect_success REFFILES 'fetch --prune ok for loose refs not in locked packed-refs' '
+ cd "$D" &&
+ git clone . prune-ok-ref-not-packed &&
+ (
+ cd prune-ok-ref-not-packed &&
+ git update-ref refs/remotes/origin/extrabranch main &&
+ : for loose refs not in packed-refs, we can delete them even the packed-refs is locked &&
+ :>.git/packed-refs.new &&
+
+ git fetch --prune origin &&
+ test_must_fail git rev-parse refs/remotes/origin/extrabranch --
+ )
+'
+
test_expect_success 'fetch --atomic works with a single branch' '
test_when_finished "rm -rf \"$D\"/atomic" &&