Git development
 help / color / mirror / Atom feed
From: Karthik Nayak <karthik.188@gmail.com>
To: git@vger.kernel.org
Cc: Karthik Nayak <karthik.188@gmail.com>
Subject: [PATCH 6/8] refs: move object parsing to the generic layer
Date: Mon, 20 Apr 2026 12:12:04 +0200	[thread overview]
Message-ID: <20260420-refs-move-to-generic-layer-v1-6-513e354f376b@gmail.com> (raw)
In-Reply-To: <20260420-refs-move-to-generic-layer-v1-0-513e354f376b@gmail.com>

Regular reference updates made via reference transactions validate that
the provided object ID exists in the object database, this is done by
calling 'parse_object()'. This check is done independently by the
backends.

Let's move this to the generic layer, ensuring the backends only have to
care about reference storage and not about validation of the object IDs.
With this also remove the 'REF_TRANSACTION_ERROR_INVALID_NEW_VALUE'
error type as its no longer used.

Since we don't iterate over individual references in
`ref_transaction_prepare()`, we add this check to
`ref_transaction_update()`. This means that the validation is done as
soon as an update is queued, without needing to prepare the
transaction. It can be argued that this is more ideal, since this
validation has no dependency on the reference transaction being
prepared.

It must be noted that the change in behavior means that this error
cannot be ignored even with usage of batched updates, since this happens
when the update is being added to the transaction. But since the caller
gets specific error codes, they can either abort the transaction or
continue adding other updates to the transaction.

Modify 'builtin/receive-pack.c' to now capture the error type so that
the error propagated to the client stays the same. Also remove two of
the tests which validates batch-updates with invalid new_oid.

Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
 builtin/receive-pack.c  | 22 +++++++++++++---------
 refs.c                  | 18 ++++++++++++++++++
 refs/files-backend.c    | 28 ++--------------------------
 refs/reftable-backend.c | 19 -------------------
 4 files changed, 33 insertions(+), 54 deletions(-)

diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 878aa7f0ed..0fb3d57de8 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -1641,8 +1641,8 @@ static const char *update(struct command *cmd, struct shallow_info *si)
 			ret = NULL; /* good */
 		}
 		strbuf_release(&err);
-	}
-	else {
+	} else {
+		enum ref_transaction_error err_type;
 		struct strbuf err = STRBUF_INIT;
 		if (shallow_update && si->shallow_ref[cmd->index] &&
 		    update_shallow_ref(cmd, si)) {
@@ -1650,14 +1650,18 @@ static const char *update(struct command *cmd, struct shallow_info *si)
 			goto out;
 		}
 
-		if (ref_transaction_update(transaction,
-					   namespaced_name,
-					   new_oid, old_oid,
-					   NULL, NULL,
-					   0, "push",
-					   &err)) {
+		err_type = ref_transaction_update(transaction,
+						  namespaced_name,
+						  new_oid, old_oid,
+						  NULL, NULL,
+						  0, "push",
+						  &err);
+		if (err_type) {
 			rp_error("%s", err.buf);
-			ret = "failed to update ref";
+			if (err_type == REF_TRANSACTION_ERROR_GENERIC)
+				ret = "failed to update ref";
+			else
+				ret = ref_transaction_error_msg(err_type);
 		} else {
 			ret = NULL; /* good */
 		}
diff --git a/refs.c b/refs.c
index 39fef1cca0..bbe19155f4 100644
--- a/refs.c
+++ b/refs.c
@@ -1416,6 +1416,24 @@ enum ref_transaction_error ref_transaction_update(struct ref_transaction *transa
 	flags |= (new_oid ? REF_HAVE_NEW : 0) | (old_oid ? REF_HAVE_OLD : 0);
 	flags |= (new_target ? REF_HAVE_NEW : 0) | (old_target ? REF_HAVE_OLD : 0);
 
+	if ((flags & REF_HAVE_NEW) && !new_target && !is_null_oid(new_oid) &&
+	    !(flags & REF_SKIP_OID_VERIFICATION) && !(flags & REF_LOG_ONLY)) {
+		struct object *o = parse_object(transaction->ref_store->repo, new_oid);
+
+		if (!o) {
+			strbuf_addf(err,
+				    _("trying to write ref '%s' with nonexistent object %s"),
+				    refname, oid_to_hex(new_oid));
+			return REF_TRANSACTION_ERROR_INVALID_NEW_VALUE;
+		}
+
+		if (o->type != OBJ_COMMIT && is_branch(refname)) {
+			strbuf_addf(err, _("trying to write non-commit object %s to branch '%s'"),
+				    oid_to_hex(new_oid), refname);
+			return REF_TRANSACTION_ERROR_INVALID_NEW_VALUE;
+		}
+	}
+
 	ref_transaction_add_update(transaction, refname, flags,
 				   new_oid, old_oid, new_target,
 				   old_target, NULL, msg);
diff --git a/refs/files-backend.c b/refs/files-backend.c
index 407b97cc44..0e2bbe37a0 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -19,7 +19,6 @@
 #include "../iterator.h"
 #include "../dir-iterator.h"
 #include "../lockfile.h"
-#include "../object.h"
 #include "../path.h"
 #include "../dir.h"
 #include "../chdir-notify.h"
@@ -1589,7 +1588,6 @@ static int rename_tmp_log(struct files_ref_store *refs, const char *newrefname)
 static enum ref_transaction_error write_ref_to_lockfile(struct files_ref_store *refs,
 							struct ref_lock *lock,
 							const struct object_id *oid,
-							int skip_oid_verification,
 							struct strbuf *err);
 static int commit_ref_update(struct files_ref_store *refs,
 			     struct ref_lock *lock,
@@ -1737,7 +1735,7 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store,
 	}
 	oidcpy(&lock->old_oid, &orig_oid);
 
-	if (write_ref_to_lockfile(refs, lock, &orig_oid, 0, &err) ||
+	if (write_ref_to_lockfile(refs, lock, &orig_oid, &err) ||
 	    commit_ref_update(refs, lock, &orig_oid, logmsg, 0, &err)) {
 		error("unable to write current sha1 into %s: %s", newrefname, err.buf);
 		strbuf_release(&err);
@@ -1755,7 +1753,7 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store,
 		goto rollbacklog;
 	}
 
-	if (write_ref_to_lockfile(refs, lock, &orig_oid, 0, &err) ||
+	if (write_ref_to_lockfile(refs, lock, &orig_oid, &err) ||
 	    commit_ref_update(refs, lock, &orig_oid, NULL, REF_SKIP_CREATE_REFLOG, &err)) {
 		error("unable to write current sha1 into %s: %s", oldrefname, err.buf);
 		strbuf_release(&err);
@@ -1999,32 +1997,11 @@ static int files_log_ref_write(struct files_ref_store *refs,
 static enum ref_transaction_error write_ref_to_lockfile(struct files_ref_store *refs,
 							struct ref_lock *lock,
 							const struct object_id *oid,
-							int skip_oid_verification,
 							struct strbuf *err)
 {
 	static char term = '\n';
-	struct object *o;
 	int fd;
 
-	if (!skip_oid_verification) {
-		o = parse_object(refs->base.repo, oid);
-		if (!o) {
-			strbuf_addf(
-				err,
-				"trying to write ref '%s' with nonexistent object %s",
-				lock->ref_name, oid_to_hex(oid));
-			unlock_ref(lock);
-			return REF_TRANSACTION_ERROR_INVALID_NEW_VALUE;
-		}
-		if (o->type != OBJ_COMMIT && is_branch(lock->ref_name)) {
-			strbuf_addf(
-				err,
-				"trying to write non-commit object %s to branch '%s'",
-				oid_to_hex(oid), lock->ref_name);
-			unlock_ref(lock);
-			return REF_TRANSACTION_ERROR_INVALID_NEW_VALUE;
-		}
-	}
 	fd = get_lock_file_fd(&lock->lk);
 	if (write_in_full(fd, oid_to_hex(oid), refs->base.repo->hash_algo->hexsz) < 0 ||
 	    write_in_full(fd, &term, 1) < 0 ||
@@ -2828,7 +2805,6 @@ static enum ref_transaction_error lock_ref_for_update(struct files_ref_store *re
 		} else {
 			ret = write_ref_to_lockfile(
 				refs, lock, &update->new_oid,
-				update->flags & REF_SKIP_OID_VERIFICATION,
 				err);
 			if (ret) {
 				char *write_err = strbuf_detach(err, NULL);
diff --git a/refs/reftable-backend.c b/refs/reftable-backend.c
index bdc3e0aa19..fdf7336c0f 100644
--- a/refs/reftable-backend.c
+++ b/refs/reftable-backend.c
@@ -1081,25 +1081,6 @@ static enum ref_transaction_error prepare_single_update(struct reftable_ref_stor
 		return 0;
 	}
 
-	/* Verify that the new object ID is valid. */
-	if ((u->flags & REF_HAVE_NEW) && !is_null_oid(&u->new_oid) &&
-	    !(u->flags & REF_SKIP_OID_VERIFICATION) &&
-	    !(u->flags & REF_LOG_ONLY)) {
-		struct object *o = parse_object(refs->base.repo, &u->new_oid);
-		if (!o) {
-			strbuf_addf(err,
-				    _("trying to write ref '%s' with nonexistent object %s"),
-				    u->refname, oid_to_hex(&u->new_oid));
-			return REF_TRANSACTION_ERROR_INVALID_NEW_VALUE;
-		}
-
-		if (o->type != OBJ_COMMIT && is_branch(u->refname)) {
-			strbuf_addf(err, _("trying to write non-commit object %s to branch '%s'"),
-				    oid_to_hex(&u->new_oid), u->refname);
-			return REF_TRANSACTION_ERROR_INVALID_NEW_VALUE;
-		}
-	}
-
 	/*
 	 * When we update the reference that HEAD points to we enqueue
 	 * a second log-only update for HEAD so that its reflog is

-- 
2.53.GIT


  parent reply	other threads:[~2026-04-20 10:12 UTC|newest]

Thread overview: 68+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-20 10:11 [PATCH 0/8] refs: move some of the generic logic out of the backends Karthik Nayak
2026-04-20 10:11 ` [PATCH 1/8] refs: remove unused typedef 'ref_transaction_commit_fn' Karthik Nayak
2026-04-22 11:15   ` Patrick Steinhardt
2026-04-22 12:20     ` Karthik Nayak
2026-04-20 10:12 ` [PATCH 2/8] refs: extract out reflog config to generic layer Karthik Nayak
2026-04-22 11:15   ` Patrick Steinhardt
2026-04-22 13:13     ` Karthik Nayak
2026-04-20 10:12 ` [PATCH 3/8] refs: return `ref_transaction_error` from `ref_transaction_update()` Karthik Nayak
2026-04-22 11:15   ` Patrick Steinhardt
2026-04-22 13:14     ` Karthik Nayak
2026-04-20 10:12 ` [PATCH 4/8] update-ref: move `print_rejected_refs()` up Karthik Nayak
2026-04-22 11:15   ` Patrick Steinhardt
2026-04-22 13:16     ` Karthik Nayak
2026-04-20 10:12 ` [PATCH 5/8] update-ref: handle rejections while adding updates Karthik Nayak
2026-04-22 11:15   ` Patrick Steinhardt
2026-04-22 14:13     ` Karthik Nayak
2026-04-20 10:12 ` Karthik Nayak [this message]
2026-04-22 11:15   ` [PATCH 6/8] refs: move object parsing to the generic layer Patrick Steinhardt
2026-04-22 15:03     ` Karthik Nayak
2026-04-20 10:12 ` [PATCH 7/8] refs: add peeled object ID to the `ref_update` struct Karthik Nayak
2026-04-20 10:12 ` [PATCH 8/8] refs: use peeled tag values in reference backends Karthik Nayak
2026-04-23  8:40 ` [PATCH v2 0/9] refs: move some of the generic logic out of the backends Karthik Nayak
2026-04-23  8:40   ` [PATCH v2 1/9] refs: remove unused typedef 'ref_transaction_commit_fn' Karthik Nayak
2026-04-23  8:40   ` [PATCH v2 2/9] refs: introduce `ref_store_init_options` Karthik Nayak
2026-04-23  8:52     ` Patrick Steinhardt
2026-04-24  9:34       ` Karthik Nayak
2026-04-23  8:40   ` [PATCH v2 3/9] refs: extract out reflog config to generic layer Karthik Nayak
2026-04-23  8:52     ` Patrick Steinhardt
2026-04-23  8:40   ` [PATCH v2 4/9] refs: return `ref_transaction_error` from `ref_transaction_update()` Karthik Nayak
2026-04-24 11:01     ` Toon Claes
2026-04-23  8:40   ` [PATCH v2 5/9] update-ref: move `print_rejected_refs()` up Karthik Nayak
2026-04-23  8:40   ` [PATCH v2 6/9] update-ref: handle rejections while adding updates Karthik Nayak
2026-04-23  8:52     ` Patrick Steinhardt
2026-04-24  9:35       ` Karthik Nayak
2026-04-24 11:22     ` Toon Claes
2026-04-27  8:47       ` Karthik Nayak
2026-04-23  8:40   ` [PATCH v2 7/9] refs: move object parsing to the generic layer Karthik Nayak
2026-04-24 12:06     ` Toon Claes
2026-04-27  9:32       ` Karthik Nayak
2026-04-23  8:40   ` [PATCH v2 8/9] refs: add peeled object ID to the `ref_update` struct Karthik Nayak
2026-04-24 16:44     ` Toon Claes
2026-04-27  9:33       ` Karthik Nayak
2026-04-23  8:40   ` [PATCH v2 9/9] refs: use peeled tag values in reference backends Karthik Nayak
2026-04-27 10:42 ` [PATCH v3 0/9] refs: move some of the generic logic out of the backends Karthik Nayak
2026-04-27 10:42   ` [PATCH v3 1/9] refs: remove unused typedef 'ref_transaction_commit_fn' Karthik Nayak
2026-04-27 10:42   ` [PATCH v3 2/9] refs: introduce `ref_store_init_options` Karthik Nayak
2026-04-27 10:42   ` [PATCH v3 3/9] refs: extract out reflog config to generic layer Karthik Nayak
2026-04-27 10:42   ` [PATCH v3 4/9] refs: return `ref_transaction_error` from `ref_transaction_update()` Karthik Nayak
2026-04-27 10:42   ` [PATCH v3 5/9] update-ref: move `print_rejected_refs()` up Karthik Nayak
2026-04-27 10:42   ` [PATCH v3 6/9] update-ref: handle rejections while adding updates Karthik Nayak
2026-04-29 12:24     ` Toon Claes
2026-04-30  9:52       ` Karthik Nayak
2026-04-27 10:42   ` [PATCH v3 7/9] refs: move object parsing to the generic layer Karthik Nayak
2026-04-27 10:42   ` [PATCH v3 8/9] refs: add peeled object ID to the `ref_update` struct Karthik Nayak
2026-04-27 10:42   ` [PATCH v3 9/9] refs: use peeled tag values in reference backends Karthik Nayak
2026-05-04 17:44 ` [PATCH v4 0/9] refs: move some of the generic logic out of the backends Karthik Nayak
2026-05-04 17:44   ` [PATCH v4 1/9] refs: remove unused typedef 'ref_transaction_commit_fn' Karthik Nayak
2026-05-04 17:44   ` [PATCH v4 2/9] refs: introduce `ref_store_init_options` Karthik Nayak
2026-05-04 17:44   ` [PATCH v4 3/9] refs: extract out reflog config to generic layer Karthik Nayak
2026-05-04 17:44   ` [PATCH v4 4/9] refs: return `ref_transaction_error` from `ref_transaction_update()` Karthik Nayak
2026-05-04 17:44   ` [PATCH v4 5/9] update-ref: move `print_rejected_refs()` up Karthik Nayak
2026-05-04 17:44   ` [PATCH v4 6/9] update-ref: handle rejections while adding updates Karthik Nayak
2026-05-05  5:52     ` Patrick Steinhardt
2026-05-05  8:23       ` Karthik Nayak
2026-05-06 19:44         ` Toon Claes
2026-05-04 17:44   ` [PATCH v4 7/9] refs: move object parsing to the generic layer Karthik Nayak
2026-05-04 17:44   ` [PATCH v4 8/9] refs: add peeled object ID to the `ref_update` struct Karthik Nayak
2026-05-04 17:44   ` [PATCH v4 9/9] refs: use peeled tag values in reference backends Karthik Nayak

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260420-refs-move-to-generic-layer-v1-6-513e354f376b@gmail.com \
    --to=karthik.188@gmail.com \
    --cc=git@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox