git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 3/9] odb: compute object hash in `odb_write_object_ext()`

From
Patrick Steinhardt <ps@pks.im>
Date
Jul 17, 2026, 09:32 UTC
Message-ID
<20260717-pks-odb-move-loose-object-writing-v1-3-46446a3cb5b7@pks.im>
In-Reply-To
<20260717-pks-odb-move-loose-object-writing-v1-0-46446a3cb5b7@pks.im>

Same as in a preceding commit, compute the object hash in `odb_write_object_ext()` so that we can unify this logic.

Besides unification, this change also allows us to lift the object existence check out of the "loose" backend into the generic layer, which will happen in the next commit.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 object-file.c                 | 35 ++++++++---------------------------
 object-file.h                 |  4 ----
 odb.c                         |  2 ++
 odb/source-files.c            |  2 +-
 odb/source-inmemory.c         |  6 +++---
 odb/source-loose.c            | 12 +++++++-----
 odb/source-packed.c           |  2 +-
 odb/source.h                  |  4 ++--
 t/unit-tests/u-odb-inmemory.c |  1 +
 9 files changed, 25 insertions(+), 43 deletions(-)
diff --git a/object-file.c b/object-file.c
index 5283292f1e..9ca14f484d 100644
--- a/object-file.c
+++ b/object-file.c
@@ -316,31 +316,6 @@ int parse_loose_header(const char *hdr, struct object_info *oi)
 	return 0;
 }
 
-static void hash_object_body(const struct git_hash_algo *algo, struct git_hash_ctx *c,
-			     const void *buf, size_t len,
-			     struct object_id *oid,
-			     char *hdr, size_t *hdrlen)
-{
-	git_hash_init(c, algo);
-	git_hash_update(c, hdr, *hdrlen);
-	git_hash_update(c, buf, len);
-	git_hash_final_oid(oid, c);
-}
-
-void write_object_file_prepare(const struct git_hash_algo *algo,
-			       const void *buf, size_t len,
-			       enum object_type type, struct object_id *oid,
-			       char *hdr, size_t *hdrlen)
-{
-	struct git_hash_ctx c;
-
-	/* Generate the header */
-	*hdrlen = format_object_header(hdr, *hdrlen, type, len);
-
-	/* Hash (function pointers) computation */
-	hash_object_body(algo, &c, buf, len, oid, hdr, hdrlen);
-}
-
 #define CHECK_COLLISION_DEST_VANISHED -2
 
 static int check_collision(const char *source, const char *dest)
@@ -476,10 +451,16 @@ void hash_object_file(const struct git_hash_algo *algo, const void *buf,
 		      size_t len, enum object_type type,
 		      struct object_id *oid)
 {
+	struct git_hash_ctx c;
 	char hdr[MAX_HEADER_LEN];
-	size_t hdrlen = sizeof(hdr);
+	int hdrlen;
+
+	hdrlen = format_object_header(hdr, sizeof(hdr), type, len);
 
-	write_object_file_prepare(algo, buf, len, type, oid, hdr, &hdrlen);
+	git_hash_init(&c, algo);
+	git_hash_update(&c, hdr, hdrlen);
+	git_hash_update(&c, buf, len);
+	git_hash_final_oid(oid, &c);
 }
 
 struct transaction_packfile {
diff --git a/object-file.h b/object-file.h
index d04ffa6493..08aafcda0d 100644
--- a/object-file.h
+++ b/object-file.h
@@ -134,10 +134,6 @@ int finalize_object_file_flags(struct repository *repo,
 void hash_object_file(const struct git_hash_algo *algo, const void *buf,
 		      size_t len, enum object_type type,
 		      struct object_id *oid);
-void write_object_file_prepare(const struct git_hash_algo *algo,
-			       const void *buf, size_t len,
-			       enum object_type type, struct object_id *oid,
-			       char *hdr, size_t *hdrlen);
 int write_loose_object(struct odb_source_loose *loose,
 		       const struct object_id *oid, char *hdr,
 		       int hdrlen, const void *buf, unsigned long len,
diff --git a/odb.c b/odb.c
index 1d6538163b..4adbdf8a64 100644
--- a/odb.c
+++ b/odb.c
@@ -995,6 +995,8 @@ int odb_write_object_ext(struct object_database *odb,
 	const struct git_hash_algo *compat = odb->repo->compat_hash_algo;
 	struct object_id compat_oid, *compat_oid_p = NULL;
 
+	hash_object_file(odb->repo->hash_algo, buf, len, type, oid);
+
 	if (compat) {
 		const struct git_hash_algo *algo = odb->repo->hash_algo;
 
diff --git a/odb/source-files.c b/odb/source-files.c
index 3d9f5eca32..06dfc8dd78 100644
--- a/odb/source-files.c
+++ b/odb/source-files.c
@@ -162,7 +162,7 @@ static int odb_source_files_freshen_object(struct odb_source *source,
 static int odb_source_files_write_object(struct odb_source *source,
 					 const void *buf, size_t len,
 					 enum object_type type,
-					 struct object_id *oid,
+					 const struct object_id *oid,
 					 const struct object_id *compat_oid,
 					 enum odb_write_object_flags flags)
 {
diff --git a/odb/source-inmemory.c b/odb/source-inmemory.c
index e727aba427..963d520317 100644
--- a/odb/source-inmemory.c
+++ b/odb/source-inmemory.c
@@ -230,15 +230,13 @@ static int odb_source_inmemory_count_objects(struct odb_source *source,
 static int odb_source_inmemory_write_object(struct odb_source *source,
 					    const void *buf, size_t len,
 					    enum object_type type,
-					    struct object_id *oid,
+					    const struct object_id *oid,
 					    const struct object_id *compat_oid UNUSED,
 					    enum odb_write_object_flags flags UNUSED)
 {
 	struct odb_source_inmemory *inmemory = odb_source_inmemory_downcast(source);
 	struct inmemory_object *object;
 
-	hash_object_file(source->odb->repo->hash_algo, buf, len, type, oid);
-
 	if (!inmemory->objects) {
 		CALLOC_ARRAY(inmemory->objects, 1);
 		oidtree_init(inmemory->objects);
@@ -285,6 +283,8 @@ static int odb_source_inmemory_write_object_stream(struct odb_source *source,
 		goto out;
 	}
 
+	hash_object_file(source->odb->repo->hash_algo, data, total_read, OBJ_BLOB, oid);
+
 	ret = odb_source_inmemory_write_object(source, data, len, OBJ_BLOB, oid,
 					       NULL, 0);
 	if (ret < 0)
diff --git a/odb/source-loose.c b/odb/source-loose.c
index ca223109cd..d4715da6d1 100644
--- a/odb/source-loose.c
+++ b/odb/source-loose.c
@@ -584,19 +584,21 @@ static int odb_source_loose_freshen_object(struct odb_source *source,
 
 static int odb_source_loose_write_object(struct odb_source *source,
 					 const void *buf, size_t len,
-					 enum object_type type, struct object_id *oid,
+					 enum object_type type,
+					 const struct object_id *oid,
 					 const struct object_id *compat_oid,
 					 enum odb_write_object_flags flags)
 {
 	struct odb_source_loose *loose = odb_source_loose_downcast(source);
-	const struct git_hash_algo *algo = source->odb->repo->hash_algo;
 	char hdr[MAX_HEADER_LEN];
-	size_t hdrlen = sizeof(hdr);
+	int hdrlen;
+
+	hdrlen = format_object_header(hdr, sizeof(hdr), type, len);
 
-	/* Normally if we have it in the pack then we do not bother writing
+	/*
+	 * Normally if we have it in the pack then we do not bother writing
 	 * it out into .git/objects/??/?{38} file.
 	 */
-	write_object_file_prepare(algo, buf, len, type, oid, hdr, &hdrlen);
 	if (odb_freshen_object(source->odb, oid))
 		return 0;
 	if (write_loose_object(loose, oid, hdr, hdrlen, buf, len, 0, flags))
diff --git a/odb/source-packed.c b/odb/source-packed.c
index af0d533375..f7f1706447 100644
--- a/odb/source-packed.c
+++ b/odb/source-packed.c
@@ -529,7 +529,7 @@ static int odb_source_packed_write_object(struct odb_source *source UNUSED,
 					  const void *buf UNUSED,
 					  size_t len UNUSED,
 					  enum object_type type UNUSED,
-					  struct object_id *oid UNUSED,
+					  const struct object_id *oid UNUSED,
 					  const struct object_id *compat_oid UNUSED,
 					  unsigned flags UNUSED)
 {
diff --git a/odb/source.h b/odb/source.h
index b3c1ca3a66..c4e94c9d0d 100644
--- a/odb/source.h
+++ b/odb/source.h
@@ -206,7 +206,7 @@ struct odb_source {
 	int (*write_object)(struct odb_source *source,
 			    const void *buf, size_t len,
 			    enum object_type type,
-			    struct object_id *oid,
+			    const struct object_id *oid,
 			    const struct object_id *compat_oid,
 			    enum odb_write_object_flags flags);
 
@@ -416,7 +416,7 @@ static inline int odb_source_freshen_object(struct odb_source *source,
 static inline int odb_source_write_object(struct odb_source *source,
 					  const void *buf, unsigned long len,
 					  enum object_type type,
-					  struct object_id *oid,
+					  const struct object_id *oid,
 					  const struct object_id *compat_oid,
 					  enum odb_write_object_flags flags)
 {
diff --git a/t/unit-tests/u-odb-inmemory.c b/t/unit-tests/u-odb-inmemory.c
index 2dbc3ab1df..28a69fc244 100644
--- a/t/unit-tests/u-odb-inmemory.c
+++ b/t/unit-tests/u-odb-inmemory.c
@@ -43,6 +43,7 @@ static void cl_assert_write_object(struct odb_source_inmemory *source,
 				   struct object_id *oid)
 {
 	size_t content_len = strlen(content);
+	hash_object_file(repo.hash_algo, content, content_len, type, oid);
 	cl_must_pass(odb_source_write_object(&source->base, content, content_len,
 					     type, oid, NULL, 0));
 }
-- 
2.55.0.407.g700c83d4f3.dirty
Previous: Justin ToblerNext: Patrick Steinhardt
Message 6 of 17 in “object-file: move writing of loose objects into "loose" source”
  1. 0/9 object-file: move writing of loose objects into "loose" sourcePatrick Steinhardt, Jul 17, 2026
  2. 1/9 odb: compute compat object ID in `odb_write_object_ext()`Patrick Steinhardt, Jul 17, 2026
  3. Justin ToblerJul 28, 2026
  4. 2/9 t/u-odb-inmemory: implement wrapper for writing objectsPatrick Steinhardt, Jul 17, 2026
  5. Justin ToblerJul 28, 2026
  6. 3/9 odb: compute object hash in `odb_write_object_ext()`Patrick Steinhardt, Jul 17, 2026
  7. 4/9 odb: lift object existence check out of the "loose" backendPatrick Steinhardt, Jul 17, 2026
  8. Toon ClaesJul 22, 2026
  9. 5/9 odb: support setting mtime when writing objectsPatrick Steinhardt, Jul 17, 2026
  10. 6/9 object-file: fix memory leak in `force_object_loose()`Patrick Steinhardt, Jul 17, 2026
  11. 7/9 object-file: force objects loose via generic interfacePatrick Steinhardt, Jul 17, 2026
  12. 8/9 object-file: move `force_object_loose()`Patrick Steinhardt, Jul 17, 2026
  13. 9/9 object-file: move logic to write loose objectsPatrick Steinhardt, Jul 17, 2026
  14. Toon ClaesJul 22, 2026
  15. SZEDER GáborJul 18, 2026
  16. Junio C HamanoJul 19, 2026
  17. Junio C HamanoJul 19, 2026

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.