]> git.ipfire.org Git - thirdparty/git.git/commitdiff
Merge branch 'kn/ref-transaction-symref'
authorJunio C Hamano <gitster@pobox.com>
Mon, 20 May 2024 18:20:04 +0000 (11:20 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 20 May 2024 18:20:04 +0000 (11:20 -0700)
Updates to symbolic refs can now be made as a part of ref
transaction.

* kn/ref-transaction-symref:
  refs: remove `create_symref` and associated dead code
  refs: rename `refs_create_symref()` to `refs_update_symref()`
  refs: use transaction in `refs_create_symref()`
  refs: add support for transactional symref updates
  refs: move `original_update_refname` to 'refs.c'
  refs: support symrefs in 'reference-transaction' hook
  files-backend: extract out `create_symref_lock()`
  refs: accept symref values in `ref_transaction_update()`

21 files changed:
1  2 
branch.c
builtin/branch.c
builtin/checkout.c
builtin/clone.c
builtin/fast-import.c
builtin/fetch.c
builtin/notes.c
builtin/receive-pack.c
builtin/remote.c
builtin/replace.c
builtin/symbolic-ref.c
builtin/tag.c
builtin/update-ref.c
builtin/worktree.c
refs.c
refs.h
refs/reftable-backend.c
reset.c
sequencer.c
setup.c
walker.c

diff --cc branch.c
Simple merge
Simple merge
index 536b8941905c42fd7e06f42c55b64227fd2d1854,2b6166c284e0dda89b829c88313711d078bd2632..f90a4ca4b7a6fd1befeb60cafdc5519037b27165
@@@ -1011,7 -1007,7 +1011,7 @@@ static void update_refs_for_switch(cons
                        describe_detached_head(_("HEAD is now at"), new_branch_info->commit);
                }
        } else if (new_branch_info->path) {     /* Switch branches. */
-               if (refs_create_symref(get_main_ref_store(the_repository), "HEAD", new_branch_info->path, msg.buf) < 0)
 -              if (create_symref("HEAD", new_branch_info->path, msg.buf) < 0)
++              if (refs_update_symref(get_main_ref_store(the_repository), "HEAD", new_branch_info->path, msg.buf) < 0)
                        die(_("unable to update HEAD"));
                if (!opts->quiet) {
                        if (old_branch_info->path && !strcmp(new_branch_info->path, old_branch_info->path)) {
@@@ -1472,8 -1464,7 +1472,8 @@@ static int switch_unborn_to_new_branch(
        if (!opts->new_branch)
                die(_("You are on a branch yet to be born"));
        strbuf_addf(&branch_ref, "refs/heads/%s", opts->new_branch);
-       status = refs_create_symref(get_main_ref_store(the_repository),
 -      status = create_symref("HEAD", branch_ref.buf, "checkout -b");
++      status = refs_update_symref(get_main_ref_store(the_repository),
 +                                  "HEAD", branch_ref.buf, "checkout -b");
        strbuf_release(&branch_ref);
        if (!opts->quiet)
                fprintf(stderr, _("Switched to a new branch '%s'\n"),
diff --cc builtin/clone.c
index 554b29768c351eda6635936a2d29a96f8e921b72,74ec14542e811d10f0dc88c9bfe935fc41af1491..23993b905b779671c7828876f918cfd1e04a92e0
@@@ -653,9 -623,9 +653,9 @@@ static void update_remote_refs(const st
                struct strbuf head_ref = STRBUF_INIT;
                strbuf_addstr(&head_ref, branch_top);
                strbuf_addstr(&head_ref, "HEAD");
-               if (refs_create_symref(get_main_ref_store(the_repository), head_ref.buf,
 -              if (create_symref(head_ref.buf,
 -                                remote_head_points_at->peer_ref->name,
 -                                msg) < 0)
++              if (refs_update_symref(get_main_ref_store(the_repository), head_ref.buf,
 +                                     remote_head_points_at->peer_ref->name,
 +                                     msg) < 0)
                        die(_("unable to update %s"), head_ref.buf);
                strbuf_release(&head_ref);
        }
@@@ -667,12 -637,11 +667,12 @@@ static void update_head(const struct re
        const char *head;
        if (our && skip_prefix(our->name, "refs/heads/", &head)) {
                /* Local default branch link */
-               if (refs_create_symref(get_main_ref_store(the_repository), "HEAD", our->name, NULL) < 0)
 -              if (create_symref("HEAD", our->name, NULL) < 0)
++              if (refs_update_symref(get_main_ref_store(the_repository), "HEAD", our->name, NULL) < 0)
                        die(_("unable to update HEAD"));
                if (!option_bare) {
 -                      update_ref(msg, "HEAD", &our->old_oid, NULL, 0,
 -                                 UPDATE_REFS_DIE_ON_ERR);
 +                      refs_update_ref(get_main_ref_store(the_repository),
 +                                      msg, "HEAD", &our->old_oid, NULL, 0,
 +                                      UPDATE_REFS_DIE_ON_ERR);
                        install_branch_config(0, head, remote_name, our->name);
                }
        } else if (our) {
                 * Unborn head from remote; same as "our" case above except
                 * that we have no ref to update.
                 */
-               if (refs_create_symref(get_main_ref_store(the_repository), "HEAD", unborn, NULL) < 0)
 -              if (create_symref("HEAD", unborn, NULL) < 0)
++              if (refs_update_symref(get_main_ref_store(the_repository), "HEAD", unborn, NULL) < 0)
                        die(_("unable to update HEAD"));
                if (!option_bare)
                        install_branch_config(0, head, remote_name, unborn);
index 184cfa9f5769e749874634ce505361a51c5227da,6a0b39de32571c5dd37d0c7af39a167c34c42a00..d1c0243d04ecb05c4c618c997ac0cb76f8514823
@@@ -1632,11 -1631,10 +1632,11 @@@ static int update_branch(struct branch 
                        return -1;
                }
        }
 -      transaction = ref_transaction_begin(&err);
 +      transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
 +                                                &err);
        if (!transaction ||
            ref_transaction_update(transaction, b->name, &b->oid, &old_oid,
-                                  0, msg, &err) ||
+                                  NULL, NULL, 0, msg, &err) ||
            ref_transaction_commit(transaction, &err)) {
                ref_transaction_free(transaction);
                error("%s", err.buf);
diff --cc builtin/fetch.c
Simple merge
diff --cc builtin/notes.c
index a5ce90d9f93c657e68f1a30a8f41810d0cfc6ab2,cb011303e68d7725b8ed7bed0f2069e81859d692..7f80b3449bd3633601b22ab776f5e7173a3ba897
@@@ -981,7 -977,7 +981,7 @@@ static int merge(int argc, const char *
                        die(_("a notes merge into %s is already in-progress at %s"),
                            default_notes_ref(), wt->path);
                free_worktrees(worktrees);
-               if (refs_create_symref(get_main_ref_store(the_repository), "NOTES_MERGE_REF", default_notes_ref(), NULL))
 -              if (create_symref("NOTES_MERGE_REF", default_notes_ref(), NULL))
++              if (refs_update_symref(get_main_ref_store(the_repository), "NOTES_MERGE_REF", default_notes_ref(), NULL))
                        die(_("failed to store link to current notes ref (%s)"),
                            default_notes_ref());
                fprintf(stderr, _("Automatic notes merge failed. Fix conflicts in %s "
Simple merge
index ff70d6835a49a33dcbe39a6af5af0661cdeaa06f,8412d12fa55100132c69ae24914b2db536bf77c9..d52b1c0e10ffc1f164c6fa541ba9b381b1bc7d73
@@@ -240,7 -240,7 +240,7 @@@ static int add(int argc, const char **a
                strbuf_reset(&buf2);
                strbuf_addf(&buf2, "refs/remotes/%s/%s", name, master);
  
-               if (refs_create_symref(get_main_ref_store(the_repository), buf.buf, buf2.buf, "remote add"))
 -              if (create_symref(buf.buf, buf2.buf, "remote add"))
++              if (refs_update_symref(get_main_ref_store(the_repository), buf.buf, buf2.buf, "remote add"))
                        return error(_("Could not setup master '%s'"), master);
        }
  
@@@ -845,7 -843,7 +845,7 @@@ static int mv(int argc, const char **ar
                strbuf_reset(&buf3);
                strbuf_addf(&buf3, "remote: renamed %s to %s",
                                item->string, buf.buf);
-               if (refs_create_symref(get_main_ref_store(the_repository), buf.buf, buf2.buf, buf3.buf))
 -              if (create_symref(buf.buf, buf2.buf, buf3.buf))
++              if (refs_update_symref(get_main_ref_store(the_repository), buf.buf, buf2.buf, buf3.buf))
                        die(_("creating '%s' failed"), buf.buf);
                display_progress(progress, ++refs_renamed_nr);
        }
@@@ -1421,9 -1415,9 +1421,9 @@@ static int set_head(int argc, const cha
        if (head_name) {
                strbuf_addf(&buf2, "refs/remotes/%s/%s", argv[0], head_name);
                /* make sure it's valid */
 -              if (!ref_exists(buf2.buf))
 +              if (!refs_ref_exists(get_main_ref_store(the_repository), buf2.buf))
                        result |= error(_("Not a valid ref: %s"), buf2.buf);
-               else if (refs_create_symref(get_main_ref_store(the_repository), buf.buf, buf2.buf, "remote set-head"))
 -              else if (create_symref(buf.buf, buf2.buf, "remote set-head"))
++              else if (refs_update_symref(get_main_ref_store(the_repository), buf.buf, buf2.buf, "remote set-head"))
                        result |= error(_("Could not setup %s"), buf.buf);
                else if (opt_a)
                        printf("%s/HEAD set to %s\n", argv[0], head_name);
index bc2a948c800e9bc477b0cb73f2995b4246477d63,7690687b0ed645d7138701bdb05e2f208777d93d..f46ff57691fa552926936e4e27c2a5b2d888938b
@@@ -198,11 -198,10 +198,11 @@@ static int replace_object_oid(const cha
                return -1;
        }
  
 -      transaction = ref_transaction_begin(&err);
 +      transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
 +                                                &err);
        if (!transaction ||
            ref_transaction_update(transaction, ref.buf, repl, &prev,
-                                  0, NULL, &err) ||
+                                  NULL, NULL, 0, NULL, &err) ||
            ref_transaction_commit(transaction, &err))
                res = error("%s", err.buf);
  
index b2b0a41fb6761abfee7e0b96e43dd38df27d2374,c9defe4d2e4ff057bce4dc31330ae1f964225ede..81abdd170fe73e2a5aa836cdf3069e0eb426c802
@@@ -83,8 -79,7 +83,8 @@@ int cmd_symbolic_ref(int argc, const ch
                        die("Refusing to point HEAD outside of refs/");
                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_create_symref(get_main_ref_store(the_repository),
 -              ret = !!create_symref(argv[0], argv[1], msg);
++              ret = !!refs_update_symref(get_main_ref_store(the_repository),
 +                                         argv[0], argv[1], msg);
                break;
        default:
                usage_with_options(git_symbolic_ref_usage, options);
diff --cc builtin/tag.c
index b18eec91ab50a515976c6b86f83638242f94d2ca,40a65fdebce1f6c77f7247ed1748e8a169ad7761..6e2c0cf3420156f37d927ab1cd162edf1a2813a1
@@@ -673,13 -654,13 +673,14 @@@ int cmd_tag(int argc, const char **argv
                        opt.sign = 1;
                path = git_pathdup("TAG_EDITMSG");
                create_tag(&object, object_ref, tag, &buf, &opt, &prev, &object,
 -                         path);
 +                         &trailer_args, path);
        }
  
 -      transaction = ref_transaction_begin(&err);
 +      transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
 +                                                &err);
        if (!transaction ||
            ref_transaction_update(transaction, ref.buf, &object, &prev,
+                                  NULL, NULL,
                                   create_reflog ? REF_FORCE_CREATE_REFLOG : 0,
                                   reflog_msg.buf, &err) ||
            ref_transaction_commit(transaction, &err)) {
Simple merge
Simple merge
diff --cc refs.c
index a26c50a401ed8d63118d67d70d93231022630d8c,fa5471d219b60bb516cb6e2135598e2f4a6aa09b..32e91ff74038503211b2cde43c7fab64cc8dfdbc
--- 1/refs.c
--- 2/refs.c
+++ b/refs.c
@@@ -2181,21 -2284,36 +2199,29 @@@ int peel_iterated_oid(const struct obje
        return peel_object(base, peeled) ? -1 : 0;
  }
  
- int refs_create_symref(struct ref_store *refs,
-                      const char *ref_target,
-                      const char *refs_heads_master,
-                      const char *logmsg)
+ int refs_update_symref(struct ref_store *refs, const char *ref,
+                      const char *target, const char *logmsg)
  {
-       char *msg;
-       int retval;
+       struct ref_transaction *transaction;
+       struct strbuf err = STRBUF_INIT;
+       int ret = 0;
  
-       msg = normalize_reflog_message(logmsg);
-       retval = refs->be->create_symref(refs, ref_target, refs_heads_master,
-                                        msg);
-       free(msg);
-       return retval;
+       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)) {
+               ret = error("%s", err.buf);
+       }
+       strbuf_release(&err);
+       if (transaction)
+               ref_transaction_free(transaction);
+       return ret;
  }
  
 -int create_symref(const char *ref_target, const char *refs_heads_master,
 -                const char *logmsg)
 -{
 -      return refs_update_symref(get_main_ref_store(the_repository), ref_target,
 -                                refs_heads_master, logmsg);
 -}
 -
  int ref_update_reject_duplicates(struct string_list *refnames,
                                 struct strbuf *err)
  {
@@@ -2634,3 -2823,43 +2672,38 @@@ int refs_copy_existing_ref(struct ref_s
        free(msg);
        return retval;
  }
 -int copy_existing_ref(const char *oldref, const char *newref, const char *logmsg)
 -{
 -      return refs_copy_existing_ref(get_main_ref_store(the_repository), oldref, newref, logmsg);
 -}
 -
+ const char *ref_update_original_update_refname(struct ref_update *update)
+ {
+       while (update->parent_update)
+               update = update->parent_update;
+       return update->refname;
+ }
+ int ref_update_has_null_new_value(struct ref_update *update)
+ {
+       return !update->new_target && is_null_oid(&update->new_oid);
+ }
+ int ref_update_check_old_target(const char *referent, struct ref_update *update,
+                               struct strbuf *err)
+ {
+       if (!update->old_target)
+               BUG("called without old_target set");
+       if (!strcmp(referent, update->old_target))
+               return 0;
+       if (!strcmp(referent, ""))
+               strbuf_addf(err, "verifying symref target: '%s': "
+                           "reference is missing but expected %s",
+                           ref_update_original_update_refname(update),
+                           update->old_target);
+       else
+               strbuf_addf(err, "verifying symref target: '%s': "
+                           "is at %s but expected %s",
+                           ref_update_original_update_refname(update),
+                           referent, update->old_target);
+       return -1;
+ }
diff --cc refs.h
index d02dd79ca66f630a01311e8255d1b1417a6072a0,71cc1c58e000b963ea6f8538a28ed3e1a88f12b3..fb419ab2edcf186d5565ed12126f04bf9151b9d4
--- 1/refs.h
--- 2/refs.h
+++ b/refs.h
@@@ -562,9 -603,12 +562,9 @@@ int refs_rename_ref(struct ref_store *r
  /** copy ref, return 0 on success **/
  int refs_copy_existing_ref(struct ref_store *refs, const char *oldref,
                    const char *newref, const char *logmsg);
 -int copy_existing_ref(const char *oldref, const char *newref,
 -                      const char *logmsg);
  
- int refs_create_symref(struct ref_store *refs, const char *refname,
+ int refs_update_symref(struct ref_store *refs, const char *refname,
                       const char *target, const char *logmsg);
 -int create_symref(const char *refname, const char *target, const char *logmsg);
  
  enum action_on_err {
        UPDATE_REFS_MSG_ON_ERR,
index 010ef811b6484197912189edf8a4cf901262bf9c,8f5165c4ba34193fc170df648bfbd555d246bf80..98cebbcf39ae695b2f567daabeba25782932b361
@@@ -1088,18 -1080,35 +1087,35 @@@ static int write_transaction_table(stru
                           (u->flags & REF_FORCE_CREATE_REFLOG ||
                            should_write_log(&arg->refs->base, u->refname))) {
                        struct reftable_log_record *log;
+                       int create_reflog = 1;
+                       if (u->new_target) {
+                               if (!refs_resolve_ref_unsafe(&arg->refs->base, u->new_target,
+                                                            RESOLVE_REF_READING, &u->new_oid, NULL)) {
+                                       /*
+                                        * TODO: currently we skip creating reflogs for dangling
+                                        * symref updates. It would be nice to capture this as
+                                        * zero oid updates however.
+                                        */
+                                       create_reflog = 0;
+                               }
+                       }
  
-                       ALLOC_GROW(logs, logs_nr + 1, logs_alloc);
-                       log = &logs[logs_nr++];
-                       memset(log, 0, sizeof(*log));
-                       fill_reftable_log_record(log, &committer_ident);
-                       log->update_index = ts;
-                       log->refname = xstrdup(u->refname);
-                       memcpy(log->value.update.new_hash, u->new_oid.hash, GIT_MAX_RAWSZ);
-                       memcpy(log->value.update.old_hash, tx_update->current_oid.hash, GIT_MAX_RAWSZ);
-                       log->value.update.message =
-                               xstrndup(u->msg, arg->refs->write_options.block_size / 2);
+                       if (create_reflog) {
+                               ALLOC_GROW(logs, logs_nr + 1, logs_alloc);
+                               log = &logs[logs_nr++];
+                               memset(log, 0, sizeof(*log));
 -                              fill_reftable_log_record(log);
++                              fill_reftable_log_record(log, &committer_ident);
+                               log->update_index = ts;
+                               log->refname = xstrdup(u->refname);
+                               memcpy(log->value.update.new_hash,
+                                      u->new_oid.hash, GIT_MAX_RAWSZ);
+                               memcpy(log->value.update.old_hash,
+                                      tx_update->current_oid.hash, GIT_MAX_RAWSZ);
+                               log->value.update.message =
+                                       xstrndup(u->msg, arg->refs->write_options.block_size / 2);
+                       }
                }
  
                if (u->flags & REF_LOG_ONLY)
diff --cc reset.c
index 59ebb1f842caef1e1892f6c4a38b272c895ae328,d619cb7115323febadbf4ae84e6764200f962cab..937f11c0f490986e172a9126ded0744c877d2666
+++ b/reset.c
@@@ -62,19 -60,16 +62,19 @@@ static int update_refs(const struct res
                reflog_head = msg.buf;
        }
        if (!switch_to_branch)
 -              ret = update_ref(reflog_head, "HEAD", oid, head,
 -                               detach_head ? REF_NO_DEREF : 0,
 -                               UPDATE_REFS_MSG_ON_ERR);
 +              ret = refs_update_ref(get_main_ref_store(the_repository),
 +                                    reflog_head, "HEAD", oid, head,
 +                                    detach_head ? REF_NO_DEREF : 0,
 +                                    UPDATE_REFS_MSG_ON_ERR);
        else {
 -              ret = update_ref(reflog_branch ? reflog_branch : reflog_head,
 -                               switch_to_branch, oid, NULL, 0,
 -                               UPDATE_REFS_MSG_ON_ERR);
 +              ret = refs_update_ref(get_main_ref_store(the_repository),
 +                                    reflog_branch ? reflog_branch : reflog_head,
 +                                    switch_to_branch, oid, NULL, 0,
 +                                    UPDATE_REFS_MSG_ON_ERR);
                if (!ret)
-                       ret = refs_create_symref(get_main_ref_store(the_repository),
 -                      ret = create_symref("HEAD", switch_to_branch,
 -                                          reflog_head);
++                      ret = refs_update_symref(get_main_ref_store(the_repository),
 +                                               "HEAD", switch_to_branch,
 +                                               reflog_head);
        }
        if (!ret && run_hook)
                run_hooks_l("post-checkout",
diff --cc sequencer.c
index 19421cbdb8d1845e0f1d299276cd99e5b973bb1f,af1b25692b791a798abc8c7581e4df5ec47497ec..dbd60d79b9c73619d38e0504eec9e74dace7dc3d
@@@ -5043,7 -4976,7 +5044,7 @@@ cleanup_head_ref
                        }
                        msg = reflog_message(opts, "finish", "returning to %s",
                                head_ref.buf);
-                       if (refs_create_symref(get_main_ref_store(the_repository), "HEAD", head_ref.buf, msg)) {
 -                      if (create_symref("HEAD", head_ref.buf, msg)) {
++                      if (refs_update_symref(get_main_ref_store(the_repository), "HEAD", head_ref.buf, msg)) {
                                res = error(_("could not update HEAD to %s"),
                                        head_ref.buf);
                                goto cleanup_head_ref;
diff --cc setup.c
index c7d3375645e613e66bfbf2976422b164af851f13,f4b32f76e3d86b46dbd7713195592906b73b9571..9247cded6a351ba67501005695414fe4306758ff
+++ b/setup.c
@@@ -2067,7 -2001,7 +2067,7 @@@ void create_reference_database(unsigne
                        die(_("invalid initial branch name: '%s'"),
                            initial_branch);
  
-               if (refs_create_symref(get_main_ref_store(the_repository), "HEAD", ref, NULL) < 0)
 -              if (create_symref("HEAD", ref, NULL) < 0)
++              if (refs_update_symref(get_main_ref_store(the_repository), "HEAD", ref, NULL) < 0)
                        exit(1);
                free(ref);
        }
diff --cc walker.c
Simple merge