]> git.ipfire.org Git - thirdparty/git.git/commitdiff
refs: introduce the `ref_transaction_update_reflog` function
authorKarthik Nayak <karthik.188@gmail.com>
Mon, 16 Dec 2024 16:44:31 +0000 (17:44 +0100)
committerJunio C Hamano <gitster@pobox.com>
Mon, 16 Dec 2024 17:45:34 +0000 (09:45 -0800)
Introduce a new function `ref_transaction_update_reflog`, for clients to
add a reflog update to a transaction. While the existing function
`ref_transaction_update` also allows clients to add a reflog entry, this
function does a few things more, It:
  - Enforces that only a reflog entry is added and does not update the
  ref itself.
  - Allows the users to also provide the committer information. This
  means clients can add reflog entries with custom committer
  information.

The `transaction_refname_valid()` function also modifies the error
message selectively based on the type of the update. This change also
affects reflog updates which go through `ref_transaction_update()`.

A follow up commit will utilize this function to add reflog support to
`git refs migrate`.

Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
refs.c
refs.h
refs/files-backend.c

diff --git a/refs.c b/refs.c
index 782bf1090af65196263a3c35ed18d878bb4f2967..8b3882cff17e5e3b0376f75654e32f81a23e5cb2 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -1207,14 +1207,14 @@ static int transaction_refname_valid(const char *refname,
                return 1;
 
        if (is_pseudo_ref(refname)) {
-               strbuf_addf(err, _("refusing to update pseudoref '%s'"),
-                           refname);
+               const char *what = flags & REF_LOG_ONLY ? "reflog for pseudoref" : "pseudoref";
+               strbuf_addf(err, _("refusing to update %s '%s'"), what, refname);
                return 0;
        } else if ((new_oid && !is_null_oid(new_oid)) ?
                 check_refname_format(refname, REFNAME_ALLOW_ONELEVEL) :
                 !refname_is_safe(refname)) {
-               strbuf_addf(err, _("refusing to update ref with bad name '%s'"),
-                           refname);
+               const char *what = flags & REF_LOG_ONLY ? "reflog with bad name" : "ref with bad name";
+               strbuf_addf(err, _("refusing to update %s '%s'"), what, refname);
                return 0;
        }
 
@@ -1257,6 +1257,37 @@ int ref_transaction_update(struct ref_transaction *transaction,
        ref_transaction_add_update(transaction, refname, flags,
                                   new_oid, old_oid, new_target,
                                   old_target, NULL, msg);
+
+       return 0;
+}
+
+int ref_transaction_update_reflog(struct ref_transaction *transaction,
+                                 const char *refname,
+                                 const struct object_id *new_oid,
+                                 const struct object_id *old_oid,
+                                 const char *committer_info, unsigned int flags,
+                                 const char *msg, unsigned int index,
+                                 struct strbuf *err)
+{
+       struct ref_update *update;
+
+       assert(err);
+
+       flags |= REF_LOG_ONLY | REF_NO_DEREF;
+
+       if (!transaction_refname_valid(refname, new_oid, flags, err))
+               return -1;
+
+       update = ref_transaction_add_update(transaction, refname, flags,
+                                           new_oid, old_oid, NULL, NULL,
+                                           committer_info, msg);
+       /*
+        * While we do set the old_oid value, we unset the flag to skip
+        * old_oid verification which only makes sense for refs.
+        */
+       update->flags &= ~REF_HAVE_OLD;
+       update->index = index;
+
        return 0;
 }
 
diff --git a/refs.h b/refs.h
index a5bedf48cf6de91005a7e8d0bf58ca98350397a6..b0dfc65ed2e59c4b66967840339f81e7746a96d3 100644 (file)
--- a/refs.h
+++ b/refs.h
@@ -727,6 +727,20 @@ int ref_transaction_update(struct ref_transaction *transaction,
                           unsigned int flags, const char *msg,
                           struct strbuf *err);
 
+/*
+ * Similar to`ref_transaction_update`, but this function is only for adding
+ * a reflog update. Supports providing custom committer information. The index
+ * field can be utiltized to order updates as desired. When not used, the
+ * updates default to being ordered by refname.
+ */
+int ref_transaction_update_reflog(struct ref_transaction *transaction,
+                                 const char *refname,
+                                 const struct object_id *new_oid,
+                                 const struct object_id *old_oid,
+                                 const char *committer_info, unsigned int flags,
+                                 const char *msg, unsigned int index,
+                                 struct strbuf *err);
+
 /*
  * Add a reference creation to transaction. new_oid is the value that
  * the reference should have after the update; it must not be
index 255fed8354cae982f785b1b85340e2a1eeecf2a6..c11213f52065bcf2fa7612df8f9500692ee2d02c 100644 (file)
@@ -3080,10 +3080,12 @@ static int files_transaction_finish_initial(struct files_ref_store *refs,
                }
 
                /*
-                * packed-refs don't support symbolic refs and root refs, so we
-                * have to queue these references via the loose transaction.
+                * packed-refs don't support symbolic refs, root refs and reflogs,
+                * so we have to queue these references via the loose transaction.
                 */
-               if (update->new_target || is_root_ref(update->refname)) {
+               if (update->new_target ||
+                   is_root_ref(update->refname) ||
+                   (update->flags & REF_LOG_ONLY)) {
                        if (!loose_transaction) {
                                loose_transaction = ref_store_transaction_begin(&refs->base, 0, err);
                                if (!loose_transaction) {
@@ -3092,11 +3094,17 @@ static int files_transaction_finish_initial(struct files_ref_store *refs,
                                }
                        }
 
-                       ref_transaction_add_update(loose_transaction, update->refname,
-                                                  update->flags & ~REF_HAVE_OLD,
-                                                  update->new_target ? NULL : &update->new_oid, NULL,
-                                                  update->new_target, NULL, update->committer_info,
-                                                  NULL);
+                       if (update->flags & REF_LOG_ONLY)
+                               ref_transaction_add_update(loose_transaction, update->refname,
+                                                          update->flags, &update->new_oid,
+                                                          &update->old_oid, NULL, NULL,
+                                                          update->committer_info, update->msg);
+                       else
+                               ref_transaction_add_update(loose_transaction, update->refname,
+                                                          update->flags & ~REF_HAVE_OLD,
+                                                          update->new_target ? NULL : &update->new_oid, NULL,
+                                                          update->new_target, NULL, update->committer_info,
+                                                          NULL);
                } else {
                        ref_transaction_add_update(packed_transaction, update->refname,
                                                   update->flags & ~REF_HAVE_OLD,