Merge branch 'kn/update-ref-symref'

"git update-ref --stdin" learned to handle transactional updates of
symbolic-refs.

* kn/update-ref-symref:
  update-ref: add support for 'symref-update' command
  reftable: pick either 'oid' or 'target' for new updates
  update-ref: add support for 'symref-create' command
  update-ref: add support for 'symref-delete' command
  update-ref: add support for 'symref-verify' command
  refs: specify error for regular refs with `old_target`
  refs: create and use `ref_update_expects_existing_old_ref()`
This commit is contained in:
Junio C Hamano
2024-06-20 15:45:11 -07:00
14 changed files with 836 additions and 42 deletions

43
refs.c
View File

@ -914,7 +914,7 @@ int refs_delete_ref(struct ref_store *refs, const char *msg,
transaction = ref_store_transaction_begin(refs, &err);
if (!transaction ||
ref_transaction_delete(transaction, refname, old_oid,
flags, msg, &err) ||
NULL, flags, msg, &err) ||
ref_transaction_commit(transaction, &err)) {
error("%s", err.buf);
ref_transaction_free(transaction);
@ -1238,43 +1238,57 @@ int ref_transaction_update(struct ref_transaction *transaction,
int ref_transaction_create(struct ref_transaction *transaction,
const char *refname,
const struct object_id *new_oid,
const char *new_target,
unsigned int flags, const char *msg,
struct strbuf *err)
{
if (!new_oid || is_null_oid(new_oid)) {
strbuf_addf(err, "'%s' has a null OID", refname);
if (new_oid && new_target)
BUG("create called with both new_oid and new_target set");
if ((!new_oid || is_null_oid(new_oid)) && !new_target) {
strbuf_addf(err, "'%s' has neither a valid OID nor a target", refname);
return 1;
}
return ref_transaction_update(transaction, refname, new_oid,
null_oid(), NULL, NULL, flags,
null_oid(), new_target, NULL, flags,
msg, err);
}
int ref_transaction_delete(struct ref_transaction *transaction,
const char *refname,
const struct object_id *old_oid,
unsigned int flags, const char *msg,
const char *old_target,
unsigned int flags,
const char *msg,
struct strbuf *err)
{
if (old_oid && is_null_oid(old_oid))
BUG("delete called with old_oid set to zeros");
if (old_oid && old_target)
BUG("delete called with both old_oid and old_target set");
if (old_target && !(flags & REF_NO_DEREF))
BUG("delete cannot operate on symrefs with deref mode");
return ref_transaction_update(transaction, refname,
null_oid(), old_oid,
NULL, NULL, flags,
NULL, old_target, flags,
msg, err);
}
int ref_transaction_verify(struct ref_transaction *transaction,
const char *refname,
const struct object_id *old_oid,
const char *old_target,
unsigned int flags,
struct strbuf *err)
{
if (!old_oid)
BUG("verify called with old_oid set to NULL");
if (!old_target && !old_oid)
BUG("verify called with old_oid and old_target set to NULL");
if (old_oid && old_target)
BUG("verify called with both old_oid and old_target set");
if (old_target && !(flags & REF_NO_DEREF))
BUG("verify cannot operate on symrefs with deref mode");
return ref_transaction_update(transaction, refname,
NULL, old_oid,
NULL, NULL,
NULL, old_target,
flags, NULL, err);
}
@ -2485,7 +2499,7 @@ int refs_delete_refs(struct ref_store *refs, const char *logmsg,
for_each_string_list_item(item, refnames) {
ret = ref_transaction_delete(transaction, item->string,
NULL, flags, msg, &err);
NULL, NULL, flags, msg, &err);
if (ret) {
warning(_("could not delete reference %s: %s"),
item->string, err.buf);
@ -2595,7 +2609,7 @@ static int migrate_one_ref(const char *refname, const struct object_id *oid,
if (ret < 0)
goto done;
} else {
ret = ref_transaction_create(data->transaction, refname, oid,
ret = ref_transaction_create(data->transaction, refname, oid, NULL,
REF_SKIP_CREATE_REFLOG | REF_SKIP_OID_VERIFICATION,
NULL, data->errbuf);
if (ret < 0)
@ -2878,3 +2892,10 @@ done:
strbuf_release(&new_gitdir);
return ret;
}
int ref_update_expects_existing_old_ref(struct ref_update *update)
{
return (update->flags & REF_HAVE_OLD) &&
(!is_null_oid(&update->old_oid) || update->old_target);
}