@@ -559,7 +559,7 @@ static int replace_each_worktree_head_symref(struct worktree **worktrees,
continue;
refs = get_worktree_ref_store(worktrees[i]);
- if (refs_update_symref(refs, "HEAD", newref, logmsg, NULL))
+ if (refs_update_symref(refs, "HEAD", newref, logmsg, NULL, 0))
ret = error(_("HEAD of working tree %s is not updated"),
worktrees[i]->path);
}
@@ -1015,7 +1015,8 @@ static void update_refs_for_switch(const struct checkout_opts *opts,
describe_detached_head(_("HEAD is now at"), new_branch_info->commit);
}
} else if (new_branch_info->path) { /* Switch branches. */
- if (refs_update_symref(get_main_ref_store(the_repository), "HEAD", new_branch_info->path, msg.buf, NULL) < 0)
+ if (refs_update_symref(get_main_ref_store(the_repository), "HEAD", new_branch_info->path,
+ msg.buf, NULL, 0) < 0)
die(_("unable to update HEAD"));
if (!opts->quiet) {
if (old_branch_info->path && !strcmp(new_branch_info->path, old_branch_info->path)) {
@@ -1479,7 +1480,7 @@ static int switch_unborn_to_new_branch(const struct checkout_opts *opts)
die(_("You are on a branch yet to be born"));
strbuf_addf(&branch_ref, "refs/heads/%s", opts->new_branch);
status = refs_update_symref(get_main_ref_store(the_repository),
- "HEAD", branch_ref.buf, "checkout -b", NULL);
+ "HEAD", branch_ref.buf, "checkout -b", NULL, 0);
strbuf_release(&branch_ref);
if (!opts->quiet)
fprintf(stderr, _("Switched to a new branch '%s'\n"),
@@ -661,7 +661,7 @@ static void update_remote_refs(const struct ref *refs,
strbuf_addstr(&head_ref, "HEAD");
if (refs_update_symref(get_main_ref_store(the_repository), head_ref.buf,
remote_head_points_at->peer_ref->name,
- msg, NULL) < 0)
+ msg, NULL, 0) < 0)
die(_("unable to update %s"), head_ref.buf);
strbuf_release(&head_ref);
}
@@ -673,7 +673,8 @@ static void update_head(const struct ref *our, const struct ref *remote,
const char *head;
if (our && skip_prefix(our->name, "refs/heads/", &head)) {
/* Local default branch link */
- if (refs_update_symref(get_main_ref_store(the_repository), "HEAD", our->name, NULL, NULL) < 0)
+ if (refs_update_symref(get_main_ref_store(the_repository), "HEAD", our->name,
+ NULL, NULL, 0) < 0)
die(_("unable to update HEAD"));
if (!option_bare) {
refs_update_ref(get_main_ref_store(the_repository),
@@ -702,7 +703,8 @@ static void update_head(const struct ref *our, const struct ref *remote,
* Unborn head from remote; same as "our" case above except
* that we have no ref to update.
*/
- if (refs_update_symref(get_main_ref_store(the_repository), "HEAD", unborn, NULL, NULL) < 0)
+ if (refs_update_symref(get_main_ref_store(the_repository), "HEAD", unborn,
+ NULL, NULL, 0) < 0)
die(_("unable to update HEAD"));
if (!option_bare)
install_branch_config(0, head, remote_name, unborn);
@@ -980,7 +980,8 @@ static int merge(int argc, const char **argv, const char *prefix)
die(_("a notes merge into %s is already in-progress at %s"),
notes_ref, wt->path);
free_worktrees(worktrees);
- if (refs_update_symref(get_main_ref_store(the_repository), "NOTES_MERGE_REF", notes_ref, NULL, NULL))
+ if (refs_update_symref(get_main_ref_store(the_repository), "NOTES_MERGE_REF", notes_ref,
+ NULL, NULL, 0))
die(_("failed to store link to current notes ref (%s)"),
notes_ref);
fprintf(stderr, _("Automatic notes merge failed. Fix conflicts in %s "
@@ -244,7 +244,8 @@ static int add(int argc, const char **argv, const char *prefix)
strbuf_reset(&buf2);
strbuf_addf(&buf2, "refs/remotes/%s/%s", name, master);
- if (refs_update_symref(get_main_ref_store(the_repository), buf.buf, buf2.buf, "remote add", NULL))
+ if (refs_update_symref(get_main_ref_store(the_repository), buf.buf, buf2.buf,
+ "remote add", NULL, 0))
result = error(_("Could not setup master '%s'"), master);
}
@@ -864,7 +865,8 @@ static int mv(int argc, const char **argv, const char *prefix)
strbuf_reset(&buf3);
strbuf_addf(&buf3, "remote: renamed %s to %s",
item->string, buf.buf);
- if (refs_update_symref(get_main_ref_store(the_repository), buf.buf, buf2.buf, buf3.buf, NULL))
+ if (refs_update_symref(get_main_ref_store(the_repository), buf.buf, buf2.buf,
+ buf3.buf, NULL, 0))
die(_("creating '%s' failed"), buf.buf);
display_progress(progress, ++refs_renamed_nr);
}
@@ -1469,7 +1471,8 @@ static int set_head(int argc, const char **argv, const char *prefix)
/* make sure it's valid */
if (!refs_ref_exists(refs, buf2.buf))
result |= error(_("Not a valid ref: %s"), buf2.buf);
- else if (refs_update_symref(refs, buf.buf, buf2.buf, "remote set-head", &buf_prev))
+ else if (refs_update_symref(refs, buf.buf, buf2.buf,
+ "remote set-head", &buf_prev, 0))
result |= error(_("Could not setup %s"), buf.buf);
else if (opt_a) {
report_auto(argv[0], head_name, &buf_prev);
@@ -88,7 +88,7 @@ int cmd_symbolic_ref(int argc,
if (check_refname_format(argv[1], REFNAME_ALLOW_ONELEVEL) < 0)
die("Refusing to set '%s' to invalid ref '%s'", argv[0], argv[1]);
ret = !!refs_update_symref(get_main_ref_store(the_repository),
- argv[0], argv[1], msg, NULL);
+ argv[0], argv[1], msg, NULL, 0);
break;
default:
usage_with_options(git_symbolic_ref_usage, options);
@@ -517,7 +517,7 @@ static int add_worktree(const char *path, const char *refname,
ret = refs_update_ref(wt_refs, NULL, "HEAD", &commit->object.oid,
NULL, 0, UPDATE_REFS_MSG_ON_ERR);
else
- ret = refs_update_symref(wt_refs, "HEAD", symref.buf, NULL, NULL);
+ ret = refs_update_symref(wt_refs, "HEAD", symref.buf, NULL, NULL, 0);
if (ret)
goto done;
@@ -2115,29 +2115,43 @@ int peel_iterated_oid(struct repository *r, const struct object_id *base, struct
int refs_update_symref(struct ref_store *refs, const char *ref,
const char *target, const char *logmsg,
- struct strbuf *before_target)
+ struct strbuf *before_target, int create_only)
{
struct ref_transaction *transaction;
struct strbuf err = STRBUF_INIT;
int ret = 0;
transaction = ref_store_transaction_begin(refs, &err);
- if (!transaction ||
- ref_transaction_update(transaction, ref, NULL, NULL,
- target, NULL, REF_NO_DEREF,
- logmsg, &err) ||
- ref_transaction_commit(transaction, &err)) {
+ if (!transaction) {
+ error_return:
ret = error("%s", err.buf);
+ goto cleanup;
}
+ if (create_only) {
+ int create_ret = 0;
+ if (ref_transaction_create(transaction, ref, NULL, target,
+ REF_NO_DEREF, logmsg, &err))
+ goto error_return;
+ create_ret = ref_transaction_commit(transaction, &err);
+ if (create_ret && create_ret != TRANSACTION_CREATE_EXISTS)
+ ret = error("%s", err.buf);
- strbuf_release(&err);
+ } else {
+ if (ref_transaction_update(transaction, ref, NULL, NULL,
+ target, NULL, REF_NO_DEREF,
+ logmsg, &err) ||
+ ref_transaction_commit(transaction, &err))
+ goto error_return;
+ }
- if (transaction && before_target && transaction->updates[0]->before_target)
- strbuf_addstr(before_target, transaction->updates[0]->before_target);
+cleanup:
+ strbuf_release(&err);
- if (transaction)
+ if (transaction) {
+ if (before_target && transaction->updates[0]->before_target)
+ strbuf_addstr(before_target, transaction->updates[0]->before_target);
ref_transaction_free(transaction);
-
+ }
return ret;
}
@@ -572,7 +572,7 @@ int refs_copy_existing_ref(struct ref_store *refs, const char *oldref,
int refs_update_symref(struct ref_store *refs, const char *refname,
const char *target, const char *logmsg,
- struct strbuf *before_target);
+ struct strbuf *before_target, int create_only);
enum action_on_err {
UPDATE_REFS_MSG_ON_ERR,
@@ -76,7 +76,7 @@ static int update_refs(const struct reset_head_opts *opts,
if (!ret)
ret = refs_update_symref(get_main_ref_store(the_repository),
"HEAD", switch_to_branch,
- reflog_head, NULL);
+ reflog_head, NULL, 0);
}
if (!ret && run_hook)
run_hooks_l(the_repository, "post-checkout",
@@ -5107,7 +5107,8 @@ static int pick_commits(struct repository *r,
}
msg = reflog_message(opts, "finish", "returning to %s",
head_ref.buf);
- if (refs_update_symref(get_main_ref_store(the_repository), "HEAD", head_ref.buf, msg, NULL)) {
+ if (refs_update_symref(get_main_ref_store(the_repository), "HEAD", head_ref.buf,
+ msg, NULL, 0)) {
res = error(_("could not update HEAD to %s"),
head_ref.buf);
goto cleanup_head_ref;
@@ -2275,7 +2275,8 @@ void create_reference_database(enum ref_storage_format ref_storage_format,
die(_("invalid initial branch name: '%s'"),
initial_branch);
- if (refs_update_symref(get_main_ref_store(the_repository), "HEAD", ref, NULL, NULL) < 0)
+ if (refs_update_symref(get_main_ref_store(the_repository), "HEAD", ref,
+ NULL, NULL, 0) < 0)
exit(1);
free(ref);
}
@@ -120,7 +120,7 @@ static int cmd_create_symref(struct ref_store *refs, const char **argv)
const char *target = notnull(*argv++, "target");
const char *logmsg = *argv++;
- return refs_update_symref(refs, refname, target, logmsg, NULL);
+ return refs_update_symref(refs, refname, target, logmsg, NULL, 0);
}
static struct flag_definition transaction_flags[] = {
Allow the caller to specify that it only wants to update the symref if it does not already exist. Silently ignore the error from the transaction API if the symref already exists. Signed-off-by: Bence Ferdinandy <bence@ferdinandy.com> --- Notes: v4: new patch v5: no change v6: - switched from bool to int for create_only - refactored logic in refs_update_symref with goto as layed out by Junio builtin/branch.c | 2 +- builtin/checkout.c | 5 +++-- builtin/clone.c | 8 +++++--- builtin/notes.c | 3 ++- builtin/remote.c | 9 ++++++--- builtin/symbolic-ref.c | 2 +- builtin/worktree.c | 2 +- refs.c | 36 +++++++++++++++++++++++++----------- refs.h | 2 +- reset.c | 2 +- sequencer.c | 3 ++- setup.c | 3 ++- t/helper/test-ref-store.c | 2 +- 13 files changed, 51 insertions(+), 28 deletions(-)