int refs_delete_ref(struct ref_store *refs, const char *msg, const char *refname, const unsigned char *old_sha1, unsigned int flags) { struct ref_transaction *transaction; struct strbuf err = STRBUF_INIT; if (ref_type(refname) == REF_TYPE_PSEUDOREF) { assert(refs == get_main_ref_store()); return delete_pseudoref(refname, old_sha1); } transaction = ref_store_transaction_begin(refs, &err); if (!transaction || ref_transaction_delete(transaction, refname, old_sha1, flags, msg, &err) || ref_transaction_commit(transaction, &err)) { error("%s", err.buf); ref_transaction_free(transaction); strbuf_release(&err); return 1; } ref_transaction_free(transaction); strbuf_release(&err); return 0; }
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; }
int delete_ref(const char *refname, const unsigned char *old_sha1, unsigned int flags) { struct ref_transaction *transaction; struct strbuf err = STRBUF_INIT; if (ref_type(refname) == REF_TYPE_PSEUDOREF) return delete_pseudoref(refname, old_sha1); transaction = ref_transaction_begin(&err); if (!transaction || ref_transaction_delete(transaction, refname, old_sha1, flags, NULL, &err) || ref_transaction_commit(transaction, &err)) { error("%s", err.buf); ref_transaction_free(transaction); strbuf_release(&err); return 1; } ref_transaction_free(transaction); strbuf_release(&err); return 0; }
static const char *update(struct command *cmd, struct shallow_info *si) { const char *name = cmd->ref_name; struct strbuf namespaced_name_buf = STRBUF_INIT; const char *namespaced_name, *ret; unsigned char *old_sha1 = cmd->old_sha1; unsigned char *new_sha1 = cmd->new_sha1; /* only refs/... are allowed */ if (!starts_with(name, "refs/") || check_refname_format(name + 5, 0)) { rp_error("refusing to create funny ref '%s' remotely", name); return "funny refname"; } strbuf_addf(&namespaced_name_buf, "%s%s", get_git_namespace(), name); namespaced_name = strbuf_detach(&namespaced_name_buf, NULL); if (is_ref_checked_out(namespaced_name)) { switch (deny_current_branch) { case DENY_IGNORE: break; case DENY_WARN: rp_warning("updating the current branch"); break; case DENY_REFUSE: case DENY_UNCONFIGURED: rp_error("refusing to update checked out branch: %s", name); if (deny_current_branch == DENY_UNCONFIGURED) refuse_unconfigured_deny(); return "branch is currently checked out"; case DENY_UPDATE_INSTEAD: ret = update_worktree(new_sha1); if (ret) return ret; break; } } if (!is_null_sha1(new_sha1) && !has_sha1_file(new_sha1)) { error("unpack should have generated %s, " "but I can't find it!", sha1_to_hex(new_sha1)); return "bad pack"; } if (!is_null_sha1(old_sha1) && is_null_sha1(new_sha1)) { if (deny_deletes && starts_with(name, "refs/heads/")) { rp_error("denying ref deletion for %s", name); return "deletion prohibited"; } if (head_name && !strcmp(namespaced_name, head_name)) { switch (deny_delete_current) { case DENY_IGNORE: break; case DENY_WARN: rp_warning("deleting the current branch"); break; case DENY_REFUSE: case DENY_UNCONFIGURED: case DENY_UPDATE_INSTEAD: if (deny_delete_current == DENY_UNCONFIGURED) refuse_unconfigured_deny_delete_current(); rp_error("refusing to delete the current branch: %s", name); return "deletion of the current branch prohibited"; default: return "Invalid denyDeleteCurrent setting"; } } } if (deny_non_fast_forwards && !is_null_sha1(new_sha1) && !is_null_sha1(old_sha1) && starts_with(name, "refs/heads/")) { struct object *old_object, *new_object; struct commit *old_commit, *new_commit; old_object = parse_object(old_sha1); new_object = parse_object(new_sha1); if (!old_object || !new_object || old_object->type != OBJ_COMMIT || new_object->type != OBJ_COMMIT) { error("bad sha1 objects for %s", name); return "bad ref"; } old_commit = (struct commit *)old_object; new_commit = (struct commit *)new_object; if (!in_merge_bases(old_commit, new_commit)) { rp_error("denying non-fast-forward %s" " (you should pull first)", name); return "non-fast-forward"; } } if (run_update_hook(cmd)) { rp_error("hook declined to update %s", name); return "hook declined"; } if (is_null_sha1(new_sha1)) { struct strbuf err = STRBUF_INIT; if (!parse_object(old_sha1)) { old_sha1 = NULL; if (ref_exists(name)) { rp_warning("Allowing deletion of corrupt ref."); } else { rp_warning("Deleting a non-existent ref."); cmd->did_not_exist = 1; } } if (ref_transaction_delete(transaction, namespaced_name, old_sha1, 0, "push", &err)) { rp_error("%s", err.buf); strbuf_release(&err); return "failed to delete"; } strbuf_release(&err); return NULL; /* good */ } else { struct strbuf err = STRBUF_INIT; if (shallow_update && si->shallow_ref[cmd->index] && update_shallow_ref(cmd, si)) return "shallow error"; if (ref_transaction_update(transaction, namespaced_name, new_sha1, old_sha1, 0, "push", &err)) { rp_error("%s", err.buf); strbuf_release(&err); return "failed to update ref"; } strbuf_release(&err); return NULL; /* good */ } }