aboutsummaryrefslogtreecommitdiffstats
path: root/refs.c
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2024-12-19 10:58:27 -0800
committerJunio C Hamano <gitster@pobox.com>2024-12-19 10:58:27 -0800
commit5f212684abb66c9604e745a2296af8c4bb99961c (patch)
tree16d25571b9d3d66c5ccf49df359c7adb99a0124c /refs.c
parentMerge https://github.com/j6t/gitk (diff)
parentfetch set_head: handle mirrored bare repositories (diff)
downloadgit-5f212684abb66c9604e745a2296af8c4bb99961c.tar.gz
git-5f212684abb66c9604e745a2296af8c4bb99961c.zip
Merge branch 'bf/set-head-symref'
When "git fetch $remote" notices that refs/remotes/$remote/HEAD is missing and discovers what branch the other side points with its HEAD, refs/remotes/$remote/HEAD is updated to point to it. * bf/set-head-symref: fetch set_head: handle mirrored bare repositories fetch: set remote/HEAD if it does not exist refs: add create_only option to refs_update_symref_extended refs: add TRANSACTION_CREATE_EXISTS error remote set-head: better output for --auto remote set-head: refactor for readability refs: atomically record overwritten ref in update_symref refs: standardize output of refs_read_symbolic_ref t/t5505-remote: test failure of set-head t/t5505-remote: set default branch to main
Diffstat (limited to 'refs.c')
-rw-r--r--refs.c47
1 files changed, 40 insertions, 7 deletions
diff --git a/refs.c b/refs.c
index 8b71369235..bc0a60c186 100644
--- a/refs.c
+++ b/refs.c
@@ -2167,19 +2167,53 @@ 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)
{
+ return refs_update_symref_extended(refs, ref, target, logmsg, NULL, 0);
+}
+
+int refs_update_symref_extended(struct ref_store *refs, const char *ref,
+ const char *target, const char *logmsg,
+ struct strbuf *referent, int create_only)
+{
struct ref_transaction *transaction;
struct strbuf err = STRBUF_INIT;
- int ret = 0;
+ int ret = 0, prepret = 0;
transaction = ref_store_transaction_begin(refs, 0, &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) {
+ if (ref_transaction_create(transaction, ref, NULL, target,
+ REF_NO_DEREF, logmsg, &err))
+ goto error_return;
+ prepret = ref_transaction_prepare(transaction, &err);
+ if (prepret && prepret != TRANSACTION_CREATE_EXISTS)
+ goto error_return;
+ } else {
+ if (ref_transaction_update(transaction, ref, NULL, NULL,
+ target, NULL, REF_NO_DEREF,
+ logmsg, &err) ||
+ ref_transaction_prepare(transaction, &err))
+ goto error_return;
+ }
+
+ if (referent && refs_read_symbolic_ref(refs, ref, referent) == NOT_A_SYMREF) {
+ struct object_id oid;
+ if (!refs_read_ref(refs, ref, &oid)) {
+ strbuf_addstr(referent, oid_to_hex(&oid));
+ ret = NOT_A_SYMREF;
+ }
}
+ if (prepret == TRANSACTION_CREATE_EXISTS)
+ goto cleanup;
+
+ if (ref_transaction_commit(transaction, &err))
+ goto error_return;
+
+cleanup:
strbuf_release(&err);
if (transaction)
ref_transaction_free(transaction);
@@ -2993,4 +3027,3 @@ 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);
}
-