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 fast_forward_to(const unsigned char *to, const unsigned char *from, int unborn, struct replay_opts *opts) { struct ref_transaction *transaction; struct strbuf sb = STRBUF_INIT; struct strbuf err = STRBUF_INIT; read_cache(); if (checkout_fast_forward(from, to, 1)) exit(128); /* the callee should have complained already */ strbuf_addf(&sb, _("%s: fast-forward"), action_name(opts)); transaction = ref_transaction_begin(&err); if (!transaction || ref_transaction_update(transaction, "HEAD", to, unborn ? null_sha1 : from, 0, sb.buf, &err) || ref_transaction_commit(transaction, &err)) { ref_transaction_free(transaction); error("%s", err.buf); strbuf_release(&sb); strbuf_release(&err); return -1; } strbuf_release(&sb); strbuf_release(&err); ref_transaction_free(transaction); return 0; }
static void execute_commands_non_atomic(struct command *commands, struct shallow_info *si) { struct command *cmd; struct strbuf err = STRBUF_INIT; for (cmd = commands; cmd; cmd = cmd->next) { if (!should_process_cmd(cmd)) continue; transaction = ref_transaction_begin(&err); if (!transaction) { rp_error("%s", err.buf); strbuf_reset(&err); cmd->error_string = "transaction failed to start"; continue; } cmd->error_string = update(cmd, si); if (!cmd->error_string && ref_transaction_commit(transaction, &err)) { rp_error("%s", err.buf); strbuf_reset(&err); cmd->error_string = "failed to update ref"; } ref_transaction_free(transaction); } strbuf_release(&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; }
int refs_update_ref(struct ref_store *refs, const char *msg, const char *refname, const unsigned char *new_sha1, const unsigned char *old_sha1, unsigned int flags, enum action_on_err onerr) { struct ref_transaction *t = NULL; struct strbuf err = STRBUF_INIT; int ret = 0; if (ref_type(refname) == REF_TYPE_PSEUDOREF) { assert(refs == get_main_ref_store()); ret = write_pseudoref(refname, new_sha1, old_sha1, &err); } else { t = ref_store_transaction_begin(refs, &err); if (!t || ref_transaction_update(t, refname, new_sha1, old_sha1, flags, msg, &err) || ref_transaction_commit(t, &err)) { ret = 1; ref_transaction_free(t); } } if (ret) { const char *str = "update_ref failed for ref '%s': %s"; switch (onerr) { case UPDATE_REFS_MSG_ON_ERR: error(str, refname, err.buf); break; case UPDATE_REFS_DIE_ON_ERR: die(str, refname, err.buf); break; case UPDATE_REFS_QUIET_ON_ERR: break; } strbuf_release(&err); return 1; } strbuf_release(&err); if (t) ref_transaction_free(t); return 0; }
static void execute_commands_atomic(struct command *commands, struct shallow_info *si) { struct command *cmd; struct strbuf err = STRBUF_INIT; const char *reported_error = "atomic push failure"; transaction = ref_transaction_begin(&err); if (!transaction) { rp_error("%s", err.buf); strbuf_reset(&err); reported_error = "transaction failed to start"; goto failure; } for (cmd = commands; cmd; cmd = cmd->next) { if (!should_process_cmd(cmd)) continue; cmd->error_string = update(cmd, si); if (cmd->error_string) goto failure; } if (ref_transaction_commit(transaction, &err)) { rp_error("%s", err.buf); reported_error = "atomic transaction failed"; goto failure; } goto cleanup; failure: for (cmd = commands; cmd; cmd = cmd->next) if (!cmd->error_string) cmd->error_string = reported_error; cleanup: ref_transaction_free(transaction); strbuf_release(&err); }
static int replace_object_oid(const char *object_ref, struct object_id *object, const char *replace_ref, struct object_id *repl, int force) { struct object_id prev; enum object_type obj_type, repl_type; struct strbuf ref = STRBUF_INIT; struct ref_transaction *transaction; struct strbuf err = STRBUF_INIT; int res = 0; obj_type = oid_object_info(the_repository, object, NULL); repl_type = oid_object_info(the_repository, repl, NULL); if (!force && obj_type != repl_type) return error("Objects must be of the same type.\n" "'%s' points to a replaced object of type '%s'\n" "while '%s' points to a replacement object of " "type '%s'.", object_ref, type_name(obj_type), replace_ref, type_name(repl_type)); if (check_ref_valid(object, &prev, &ref, force)) { strbuf_release(&ref); return -1; } transaction = ref_transaction_begin(&err); if (!transaction || ref_transaction_update(transaction, ref.buf, repl, &prev, 0, NULL, &err) || ref_transaction_commit(transaction, &err)) res = error("%s", err.buf); ref_transaction_free(transaction); strbuf_release(&ref); return res; }
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 int packed_initial_transaction_commit(struct ref_store *ref_store, struct ref_transaction *transaction, struct strbuf *err) { return ref_transaction_commit(transaction, err); }
void create_branch(const char *head, const char *name, const char *start_name, int force, int reflog, int clobber_head, int quiet, enum branch_track track) { struct commit *commit; unsigned char sha1[20]; char *real_ref, msg[PATH_MAX + 20]; struct strbuf ref = STRBUF_INIT; int forcing = 0; int dont_change_ref = 0; int explicit_tracking = 0; if (track == BRANCH_TRACK_EXPLICIT || track == BRANCH_TRACK_OVERRIDE) explicit_tracking = 1; if (validate_new_branchname(name, &ref, force, track == BRANCH_TRACK_OVERRIDE || clobber_head)) { if (!force) dont_change_ref = 1; else forcing = 1; } real_ref = NULL; if (get_sha1(start_name, sha1)) { if (explicit_tracking) { if (advice_set_upstream_failure) { error(_(upstream_missing), start_name); advise(_(upstream_advice)); exit(1); } die(_(upstream_missing), start_name); } die(_("Not a valid object name: '%s'."), start_name); } switch (dwim_ref(start_name, strlen(start_name), sha1, &real_ref)) { case 0: /* Not branching from any existing branch */ if (explicit_tracking) die(_(upstream_not_branch), start_name); break; case 1: /* Unique completion -- good, only if it is a real branch */ if (!starts_with(real_ref, "refs/heads/") && validate_remote_tracking_branch(real_ref)) { if (explicit_tracking) die(_(upstream_not_branch), start_name); else real_ref = NULL; } break; default: die(_("Ambiguous object name: '%s'."), start_name); break; } if ((commit = lookup_commit_reference(sha1)) == NULL) die(_("Not a valid branch point: '%s'."), start_name); hashcpy(sha1, commit->object.sha1); if (forcing) snprintf(msg, sizeof msg, "branch: Reset to %s", start_name); else if (!dont_change_ref) snprintf(msg, sizeof msg, "branch: Created from %s", start_name); if (reflog) log_all_ref_updates = 1; if (!dont_change_ref) { struct ref_transaction *transaction; struct strbuf err = STRBUF_INIT; transaction = ref_transaction_begin(&err); if (!transaction || ref_transaction_update(transaction, ref.buf, sha1, null_sha1, 0, !forcing, &err) || ref_transaction_commit(transaction, msg, &err)) die("%s", err.buf); ref_transaction_free(transaction); strbuf_release(&err); } if (real_ref && track) setup_tracking(ref.buf + 11, real_ref, track, quiet); strbuf_release(&ref); free(real_ref); }
int walker_fetch(struct walker *walker, int targets, char **target, const char **write_ref, const char *write_ref_log_details) { struct strbuf refname = STRBUF_INIT; struct strbuf err = STRBUF_INIT; struct ref_transaction *transaction = NULL; unsigned char *sha1 = xmalloc(targets * 20); char *msg = NULL; int i, ret = -1; save_commit_buffer = 0; if (write_ref) { transaction = ref_transaction_begin(&err); if (!transaction) { error("%s", err.buf); goto done; } } if (!walker->get_recover) { for_each_ref(mark_complete, NULL); commit_list_sort_by_date(&complete); } for (i = 0; i < targets; i++) { if (interpret_target(walker, target[i], &sha1[20 * i])) { error("Could not interpret response from server '%s' as something to pull", target[i]); goto done; } if (process(walker, lookup_unknown_object(&sha1[20 * i]))) goto done; } if (loop(walker)) goto done; if (!write_ref) { ret = 0; goto done; } if (write_ref_log_details) { msg = xstrfmt("fetch from %s", write_ref_log_details); } else { msg = NULL; } for (i = 0; i < targets; i++) { if (!write_ref[i]) continue; strbuf_reset(&refname); strbuf_addf(&refname, "refs/%s", write_ref[i]); if (ref_transaction_update(transaction, refname.buf, &sha1[20 * i], NULL, 0, msg ? msg : "fetch (unknown)", &err)) { error("%s", err.buf); goto done; } } if (ref_transaction_commit(transaction, &err)) { error("%s", err.buf); goto done; } ret = 0; done: ref_transaction_free(transaction); free(msg); free(sha1); strbuf_release(&err); strbuf_release(&refname); return ret; }
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; 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"; } } 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 (!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: 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"; } } } 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)) { 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 (delete_ref(namespaced_name, old_sha1, 0)) { rp_error("failed to delete %s", name); return "failed to delete"; } return NULL; /* good */ } else { struct strbuf err = STRBUF_INIT; struct ref_transaction *transaction; if (shallow_update && si->shallow_ref[cmd->index] && update_shallow_ref(cmd, si)) return "shallow error"; transaction = ref_transaction_begin(&err); if (!transaction || ref_transaction_update(transaction, namespaced_name, new_sha1, old_sha1, 0, 1, "push", &err) || ref_transaction_commit(transaction, &err)) { ref_transaction_free(transaction); rp_error("%s", err.buf); strbuf_release(&err); return "failed to update ref"; } ref_transaction_free(transaction); strbuf_release(&err); return NULL; /* good */ } }
int cmd_tag(int argc, const char **argv, const char *prefix) { struct strbuf buf = STRBUF_INIT; struct strbuf ref = STRBUF_INIT; unsigned char object[20], prev[20]; const char *object_ref, *tag; struct create_tag_options opt; char *cleanup_arg = NULL; int create_reflog = 0; int annotate = 0, force = 0; int cmdmode = 0, create_tag_object = 0; const char *msgfile = NULL, *keyid = NULL; struct msg_arg msg = { 0, STRBUF_INIT }; struct ref_transaction *transaction; struct strbuf err = STRBUF_INIT; struct ref_filter filter; static struct ref_sorting *sorting = NULL, **sorting_tail = &sorting; const char *format = NULL; struct option options[] = { OPT_CMDMODE('l', "list", &cmdmode, N_("list tag names"), 'l'), { OPTION_INTEGER, 'n', NULL, &filter.lines, N_("n"), N_("print <n> lines of each tag message"), PARSE_OPT_OPTARG, NULL, 1 }, OPT_CMDMODE('d', "delete", &cmdmode, N_("delete tags"), 'd'), OPT_CMDMODE('v', "verify", &cmdmode, N_("verify tags"), 'v'), OPT_GROUP(N_("Tag creation options")), OPT_BOOL('a', "annotate", &annotate, N_("annotated tag, needs a message")), OPT_CALLBACK('m', "message", &msg, N_("message"), N_("tag message"), parse_msg_arg), OPT_FILENAME('F', "file", &msgfile, N_("read message from file")), OPT_BOOL('s', "sign", &opt.sign, N_("annotated and GPG-signed tag")), OPT_STRING(0, "cleanup", &cleanup_arg, N_("mode"), N_("how to strip spaces and #comments from message")), OPT_STRING('u', "local-user", &keyid, N_("key-id"), N_("use another key to sign the tag")), OPT__FORCE(&force, N_("replace the tag if exists")), OPT_BOOL(0, "create-reflog", &create_reflog, N_("create a reflog")), OPT_GROUP(N_("Tag listing options")), OPT_COLUMN(0, "column", &colopts, N_("show tag list in columns")), OPT_CONTAINS(&filter.with_commit, N_("print only tags that contain the commit")), OPT_WITH(&filter.with_commit, N_("print only tags that contain the commit")), OPT_MERGED(&filter, N_("print only tags that are merged")), OPT_NO_MERGED(&filter, N_("print only tags that are not merged")), OPT_CALLBACK(0 , "sort", sorting_tail, N_("key"), N_("field name to sort on"), &parse_opt_ref_sorting), { OPTION_CALLBACK, 0, "points-at", &filter.points_at, N_("object"), N_("print only tags of the object"), 0, parse_opt_object_name }, OPT_STRING( 0 , "format", &format, N_("format"), N_("format to use for the output")), OPT_END() }; git_config(git_tag_config, sorting_tail); memset(&opt, 0, sizeof(opt)); memset(&filter, 0, sizeof(filter)); filter.lines = -1; argc = parse_options(argc, argv, prefix, options, git_tag_usage, 0); if (keyid) { opt.sign = 1; set_signing_key(keyid); } create_tag_object = (opt.sign || annotate || msg.given || msgfile); if (argc == 0 && !cmdmode) cmdmode = 'l'; if ((create_tag_object || force) && (cmdmode != 0)) usage_with_options(git_tag_usage, options); finalize_colopts(&colopts, -1); if (cmdmode == 'l' && filter.lines != -1) { if (explicitly_enable_column(colopts)) die(_("--column and -n are incompatible")); colopts = 0; } if (!sorting) sorting = ref_default_sorting(); if (cmdmode == 'l') { int ret; if (column_active(colopts)) { struct column_options copts; memset(&copts, 0, sizeof(copts)); copts.padding = 2; run_column_filter(colopts, &copts); } filter.name_patterns = argv; ret = list_tags(&filter, sorting, format); if (column_active(colopts)) stop_column_filter(); return ret; } if (filter.lines != -1) die(_("-n option is only allowed with -l.")); if (filter.with_commit) die(_("--contains option is only allowed with -l.")); if (filter.points_at.nr) die(_("--points-at option is only allowed with -l.")); if (filter.merge_commit) die(_("--merged and --no-merged option are only allowed with -l")); if (cmdmode == 'd') return for_each_tag_name(argv, delete_tag); if (cmdmode == 'v') return for_each_tag_name(argv, verify_tag); if (msg.given || msgfile) { if (msg.given && msgfile) die(_("only one -F or -m option is allowed.")); if (msg.given) strbuf_addbuf(&buf, &(msg.buf)); else { if (!strcmp(msgfile, "-")) { if (strbuf_read(&buf, 0, 1024) < 0) die_errno(_("cannot read '%s'"), msgfile); } else { if (strbuf_read_file(&buf, msgfile, 1024) < 0) die_errno(_("could not open or read '%s'"), msgfile); } } } tag = argv[0]; object_ref = argc == 2 ? argv[1] : "HEAD"; if (argc > 2) die(_("too many params")); if (get_sha1(object_ref, object)) die(_("Failed to resolve '%s' as a valid ref."), object_ref); if (strbuf_check_tag_ref(&ref, tag)) die(_("'%s' is not a valid tag name."), tag); if (read_ref(ref.buf, prev)) hashclr(prev); else if (!force) die(_("tag '%s' already exists"), tag); opt.message_given = msg.given || msgfile; if (!cleanup_arg || !strcmp(cleanup_arg, "strip")) opt.cleanup_mode = CLEANUP_ALL; else if (!strcmp(cleanup_arg, "verbatim")) opt.cleanup_mode = CLEANUP_NONE; else if (!strcmp(cleanup_arg, "whitespace")) opt.cleanup_mode = CLEANUP_SPACE; else die(_("Invalid cleanup mode %s"), cleanup_arg); if (create_tag_object) { if (force_sign_annotate && !annotate) opt.sign = 1; create_tag(object, tag, &buf, &opt, prev, object); } transaction = ref_transaction_begin(&err); if (!transaction || ref_transaction_update(transaction, ref.buf, object, prev, create_reflog ? REF_FORCE_CREATE_REFLOG : 0, NULL, &err) || ref_transaction_commit(transaction, &err)) die("%s", err.buf); ref_transaction_free(transaction); if (force && !is_null_sha1(prev) && hashcmp(prev, object)) printf(_("Updated tag '%s' (was %s)\n"), tag, find_unique_abbrev(prev, DEFAULT_ABBREV)); strbuf_release(&err); strbuf_release(&buf); strbuf_release(&ref); return 0; }