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

[PATCH v4 05/14] refs: expose peeled object ID via the iterator

From
Patrick Steinhardt <ps@pks.im>
Date
Oct 23, 2025, 07:16 UTC
Message-ID
<20251023-b4-pks-ref-filter-skip-parsing-objects-v4-5-2be68ce82c9a@pks.im>
In-Reply-To
<20251023-b4-pks-ref-filter-skip-parsing-objects-v4-0-2be68ce82c9a@pks.im>

Both the "files" and "reftable" backend are able to store peeled values for tags in the respective formats. This allows for a more efficient lookup of the target object of such a tag without having to manually peel via the object database.

The infrastructure to access these peeled object IDs is somewhat funky though. When iterating through objects, we store a pointer reference to the current iterator in a global variable. The callbacks invoked by that iterator are then expected to call `peel_iterated_oid()`, which checks whether the globally-stored iterator's current reference refers to the one handed into that function. If so, we ask the iterator to peel the object, otherwise we manually peel the object via the object database. Depending on global state like this is somewhat weird and also quite fragile.

Introduce a new `struct reference::peeled_oid` field that can be populated by the reference backends. This field can be accessed via a new function `reference_get_peeled_oid()` that either uses that value, if set, or alternatively peels via the ODB. With this change we don't have to rely on global state anymore, but make the peeled object ID available to the callback functions directly.

Adjust trivial callers that already have a `struct reference` available. Remaining callers will be adjusted in subsequent commits.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 builtin/describe.c      |  2 +-
 builtin/gc.c            |  2 +-
 builtin/pack-objects.c  |  7 ++++---
 commit-graph.c          |  2 +-
 ls-refs.c               |  2 +-
 midx-write.c            |  2 +-
 pseudo-merge.c          |  2 +-
 refs.c                  | 12 ++++++++++++
 refs.h                  | 19 +++++++++++++++++++
 refs/packed-backend.c   |  1 +
 refs/reftable-backend.c |  5 +++++
 repack-midx.c           |  2 +-
 12 files changed, 48 insertions(+), 10 deletions(-)
diff --git a/builtin/describe.c b/builtin/describe.c
index 79545350443..443546aaac9 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -208,7 +208,7 @@ static int get_name(const struct reference *ref, void *cb_data UNUSED)
 	}
 
 	/* Is it annotated? */
-	if (!peel_iterated_oid(the_repository, ref->oid, &peeled)) {
+	if (!reference_get_peeled_oid(the_repository, ref, &peeled)) {
 		is_annotated = !oideq(ref->oid, &peeled);
 	} else {
 		oidcpy(&peeled, ref->oid);
diff --git a/builtin/gc.c b/builtin/gc.c
index 9de5de175f6..f0cf20d4238 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -1109,7 +1109,7 @@ static int dfs_on_ref(const struct reference *ref, void *cb_data)
 	struct commit_list *stack = NULL;
 	struct commit *commit;
 
-	if (!peel_iterated_oid(the_repository, ref->oid, &peeled))
+	if (!reference_get_peeled_oid(the_repository, ref, &peeled))
 		maybe_peeled = &peeled;
 	if (odb_read_object_info(the_repository->objects, maybe_peeled, NULL) != OBJ_COMMIT)
 		return 0;
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 39633a0158e..1613fecb669 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -838,7 +838,7 @@ static int mark_tagged(const struct reference *ref, void *cb_data UNUSED)
 
 	if (entry)
 		entry->tagged = 1;
-	if (!peel_iterated_oid(the_repository, ref->oid, &peeled)) {
+	if (!reference_get_peeled_oid(the_repository, ref, &peeled)) {
 		entry = packlist_find(&to_pack, &peeled);
 		if (entry)
 			entry->tagged = 1;
@@ -3309,7 +3309,8 @@ static int add_ref_tag(const struct reference *ref, void *cb_data UNUSED)
 {
 	struct object_id peeled;
 
-	if (!peel_iterated_oid(the_repository, ref->oid, &peeled) && obj_is_packed(&peeled))
+	if (!reference_get_peeled_oid(the_repository, ref, &peeled) &&
+	    obj_is_packed(&peeled))
 		add_tag_chain(ref->oid);
 	return 0;
 }
@@ -4537,7 +4538,7 @@ static int mark_bitmap_preferred_tip(const struct reference *ref, void *data UNU
 	struct object_id peeled;
 	struct object *object;
 
-	if (!peel_iterated_oid(the_repository, ref->oid, &peeled))
+	if (!reference_get_peeled_oid(the_repository, ref, &peeled))
 		maybe_peeled = &peeled;
 
 	object = parse_object_or_die(the_repository, maybe_peeled, ref->name);
diff --git a/commit-graph.c b/commit-graph.c
index f91af416259..80be2ff2c39 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -1857,7 +1857,7 @@ static int add_ref_to_set(const struct reference *ref, void *cb_data)
 	struct object_id peeled;
 	struct refs_cb_data *data = (struct refs_cb_data *)cb_data;
 
-	if (!peel_iterated_oid(data->repo, ref->oid, &peeled))
+	if (!reference_get_peeled_oid(data->repo, ref, &peeled))
 		maybe_peeled = &peeled;
 	if (odb_read_object_info(data->repo->objects, maybe_peeled, NULL) == OBJ_COMMIT)
 		oidset_insert(data->commits, maybe_peeled);
diff --git a/ls-refs.c b/ls-refs.c
index 64d02723691..8641281b86c 100644
--- a/ls-refs.c
+++ b/ls-refs.c
@@ -110,7 +110,7 @@ static int send_ref(const struct reference *ref, void *cb_data)
 
 	if (data->peel && ref->oid) {
 		struct object_id peeled;
-		if (!peel_iterated_oid(the_repository, ref->oid, &peeled))
+		if (!reference_get_peeled_oid(the_repository, ref, &peeled))
 			strbuf_addf(&data->buf, " peeled:%s", oid_to_hex(&peeled));
 	}
 
diff --git a/midx-write.c b/midx-write.c
index f4dd875747a..23e61cb0001 100644
--- a/midx-write.c
+++ b/midx-write.c
@@ -709,7 +709,7 @@ static int add_ref_to_pending(const struct reference *ref, void *cb_data)
 		return 0;
 	}
 
-	if (!peel_iterated_oid(revs->repo, ref->oid, &peeled))
+	if (!reference_get_peeled_oid(revs->repo, ref, &peeled))
 		maybe_peeled = &peeled;
 
 	object = parse_object_or_die(revs->repo, maybe_peeled, ref->name);
diff --git a/pseudo-merge.c b/pseudo-merge.c
index 0abd51b42c1..a2d5bd85f95 100644
--- a/pseudo-merge.c
+++ b/pseudo-merge.c
@@ -230,7 +230,7 @@ static int find_pseudo_merge_group_for_ref(const struct reference *ref, void *_d
 	uint32_t i;
 	int has_bitmap;
 
-	if (!peel_iterated_oid(the_repository, ref->oid, &peeled))
+	if (!reference_get_peeled_oid(the_repository, ref, &peeled))
 		maybe_peeled = &peeled;
 
 	c = lookup_commit(the_repository, maybe_peeled);
diff --git a/refs.c b/refs.c
index f96cf43b128..1b1551f9814 100644
--- a/refs.c
+++ b/refs.c
@@ -2334,6 +2334,18 @@ int peel_iterated_oid(struct repository *r, const struct object_id *base, struct
 	return peel_object(r, base, peeled) ? -1 : 0;
 }
 
+int reference_get_peeled_oid(struct repository *repo,
+			     const struct reference *ref,
+			     struct object_id *peeled_oid)
+{
+	if (ref->peeled_oid) {
+		oidcpy(peeled_oid, ref->peeled_oid);
+		return 0;
+	}
+
+	return peel_object(repo, ref->oid, peeled_oid) ? -1 : 0;
+}
+
 int refs_update_symref(struct ref_store *refs, const char *ref,
 		       const char *target, const char *logmsg)
 {
diff --git a/refs.h b/refs.h
index 4f0a685714f..886ed2c0f43 100644
--- a/refs.h
+++ b/refs.h
@@ -371,10 +371,29 @@ struct reference {
 	 */
 	const struct object_id *oid;
 
+	/*
+	 * An optional peeled object ID. This field _may_ be set for tags in
+	 * case the peeled value is present in the backend. Please refer to
+	 * `reference_get_peeled_oid()`.
+	 */
+	const struct object_id *peeled_oid;
+
 	/* A bitfield of `enum reference_status` flags. */
 	unsigned flags;
 };
 
+/*
+ * Peel the tag to a non-tag commit. If present, this uses the peeled object ID
+ * exposed by the reference backend. Otherwise, the object is peeled via the
+ * object database, which is less efficient.
+ *
+ * Return `0` if the reference could be peeled, a negative error code
+ * otherwise.
+ */
+int reference_get_peeled_oid(struct repository *repo,
+			     const struct reference *ref,
+			     struct object_id *peeled_oid);
+
 /*
  * The signature for the callback function for the for_each_*()
  * functions below.  The memory pointed to by the `struct reference`
diff --git a/refs/packed-backend.c b/refs/packed-backend.c
index 711e07f8326..1fefefd54ed 100644
--- a/refs/packed-backend.c
+++ b/refs/packed-backend.c
@@ -963,6 +963,7 @@ static int next_record(struct packed_ref_iterator *iter)
 			iter->base.ref.flags &= ~REF_KNOWS_PEELED;
 		} else {
 			iter->base.ref.flags |= REF_KNOWS_PEELED;
+			iter->base.ref.peeled_oid = &iter->peeled;
 		}
 	} else {
 		oidclr(&iter->peeled, iter->repo->hash_algo);
diff --git a/refs/reftable-backend.c b/refs/reftable-backend.c
index 728886eafd3..e214e120d77 100644
--- a/refs/reftable-backend.c
+++ b/refs/reftable-backend.c
@@ -547,6 +547,7 @@ struct reftable_ref_iterator {
 	struct reftable_iterator iter;
 	struct reftable_ref_record ref;
 	struct object_id oid;
+	struct object_id peeled_oid;
 
 	char *prefix;
 	size_t prefix_len;
@@ -671,6 +672,8 @@ static int reftable_ref_iterator_advance(struct ref_iterator *ref_iterator)
 		case REFTABLE_REF_VAL2:
 			oidread(&iter->oid, iter->ref.value.val2.value,
 				refs->base.repo->hash_algo);
+			oidread(&iter->peeled_oid, iter->ref.value.val2.target_value,
+				refs->base.repo->hash_algo);
 			break;
 		case REFTABLE_REF_SYMREF:
 			referent = refs_resolve_ref_unsafe(&iter->refs->base,
@@ -708,6 +711,8 @@ static int reftable_ref_iterator_advance(struct ref_iterator *ref_iterator)
 		iter->base.ref.name = iter->ref.refname;
 		iter->base.ref.target = referent;
 		iter->base.ref.oid = &iter->oid;
+		if (iter->ref.value_type == REFTABLE_REF_VAL2)
+			iter->base.ref.peeled_oid = &iter->peeled_oid;
 		iter->base.ref.flags = flags;
 
 		break;
diff --git a/repack-midx.c b/repack-midx.c
index 349f7e20b53..74bdfa3a6e9 100644
--- a/repack-midx.c
+++ b/repack-midx.c
@@ -22,7 +22,7 @@ static int midx_snapshot_ref_one(const struct reference *ref, void *_data)
 	const struct object_id *maybe_peeled = ref->oid;
 	struct object_id peeled;
 
-	if (!peel_iterated_oid(data->repo, ref->oid, &peeled))
+	if (!reference_get_peeled_oid(data->repo, ref, &peeled))
 		maybe_peeled = &peeled;
 
 	if (oidset_insert(&data->seen, maybe_peeled))
-- 
2.51.1.930.gacf6e81ea2.dirty
Previous: Patrick SteinhardtNext: Patrick Steinhardt
Message 92 of 106 in “refs: improvements and fixes for peeling tags”
  1. 00/13 refs: improvements and fixes for peeling tagsPatrick Steinhardt, Oct 7, 2025
  2. 01/13 refs: introduce wrapper struct for `each_ref_fn`Patrick Steinhardt, Oct 7, 2025
  3. Justin ToblerOct 7, 2025
  4. Patrick SteinhardtOct 8, 2025
  5. Taylor BlauOct 7, 2025
  6. shejialuoOct 8, 2025
  7. Patrick SteinhardtOct 9, 2025
  8. 02/13 refs: introduce `.ref` field for the base iteratorPatrick Steinhardt, Oct 7, 2025
  9. Karthik NayakOct 7, 2025
  10. Patrick SteinhardtOct 8, 2025
  11. Patrick SteinhardtOct 8, 2025
  12. Justin ToblerOct 7, 2025
  13. Taylor BlauOct 7, 2025
  14. 03/13 refs: refactor reference status flagsPatrick Steinhardt, Oct 7, 2025
  15. Karthik NayakOct 7, 2025
  16. Patrick SteinhardtOct 8, 2025
  17. 04/13 refs: expose peeled object ID via the iteratorPatrick Steinhardt, Oct 7, 2025
  18. Karthik NayakOct 7, 2025
  19. Patrick SteinhardtOct 8, 2025
  20. Karthik NayakOct 15, 2025
  21. 05/13 upload-pack: convert to use `reference_get_peeled_oid()`Patrick Steinhardt, Oct 7, 2025
  22. Karthik NayakOct 7, 2025
  23. Patrick SteinhardtOct 8, 2025
  24. 06/13 ref-filter: propagate peeled object IDPatrick Steinhardt, Oct 7, 2025
  25. 07/13 builtin/show-ref: convert to use `reference_get_peeled_oid()`Patrick Steinhardt, Oct 7, 2025
  26. 08/13 refs: drop `current_ref_iter` hackPatrick Steinhardt, Oct 7, 2025
  27. 09/13 refs: drop infrastructure to peel via iteratorsPatrick Steinhardt, Oct 7, 2025
  28. 10/13 object: add flag to `peel_object()` to verify object typePatrick Steinhardt, Oct 7, 2025
  29. Kristoffer HaugsbakkOct 8, 2025
  30. 11/13 refs: don't store peeled object IDs for invalid tagsPatrick Steinhardt, Oct 7, 2025
  31. 12/13 ref-filter: detect broken tags when dereferencing themPatrick Steinhardt, Oct 7, 2025
  32. 13/13 ref-filter: parse objects on demandPatrick Steinhardt, Oct 7, 2025
  33. Kristoffer HaugsbakkOct 8, 2025
  34. Patrick SteinhardtOct 8, 2025
  35. Junio C HamanoOct 7, 2025
  36. Taylor BlauOct 7, 2025
  37. Junio C HamanoOct 7, 2025
  38. 00/14 refs: improvements and fixes for peeling tagsPatrick Steinhardt, Oct 8, 2025
  39. 01/14 refs: introduce wrapper struct for `each_ref_fn`Patrick Steinhardt, Oct 8, 2025
  40. 02/14 refs: introduce `.ref` field for the base iteratorPatrick Steinhardt, Oct 8, 2025
  41. 03/14 refs: fully reset `struct ref_iterator::ref` on iterationPatrick Steinhardt, Oct 8, 2025
  42. 04/14 refs: refactor reference status flagsPatrick Steinhardt, Oct 8, 2025
  43. 05/14 refs: expose peeled object ID via the iteratorPatrick Steinhardt, Oct 8, 2025
  44. 06/14 upload-pack: convert to use `reference_get_peeled_oid()`Patrick Steinhardt, Oct 8, 2025
  45. 07/14 ref-filter: propagate peeled object IDPatrick Steinhardt, Oct 8, 2025
  46. 08/14 builtin/show-ref: convert to use `reference_get_peeled_oid()`Patrick Steinhardt, Oct 8, 2025
  47. 09/14 refs: drop `current_ref_iter` hackPatrick Steinhardt, Oct 8, 2025
  48. 10/14 refs: drop infrastructure to peel via iteratorsPatrick Steinhardt, Oct 8, 2025
  49. 11/14 object: add flag to `peel_object()` to verify object typePatrick Steinhardt, Oct 8, 2025
  50. 12/14 refs: don't store peeled object IDs for invalid tagsPatrick Steinhardt, Oct 8, 2025
  51. shejialuoOct 8, 2025
  52. Patrick SteinhardtOct 9, 2025
  53. 13/14 ref-filter: detect broken tags when dereferencing themPatrick Steinhardt, Oct 8, 2025
  54. 14/14 ref-filter: parse objects on demandPatrick Steinhardt, Oct 8, 2025
  55. Jeff KingOct 9, 2025
  56. Patrick SteinhardtOct 9, 2025
  57. Jeff KingOct 9, 2025
  58. Patrick SteinhardtOct 9, 2025
  59. Jeff KingOct 10, 2025
  60. Patrick SteinhardtOct 10, 2025
  61. Jeff KingOct 10, 2025
  62. Junio C HamanoOct 10, 2025
  63. Patrick SteinhardtOct 14, 2025
  64. Junio C HamanoOct 14, 2025
  65. Toon ClaesOct 9, 2025
  66. Junio C HamanoOct 9, 2025
  67. 00/14 refs: improvements and fixes for peeling tagsPatrick Steinhardt, Oct 22, 2025
  68. 01/14 refs: introduce wrapper struct for `each_ref_fn`Patrick Steinhardt, Oct 22, 2025
  69. 02/14 refs: introduce `.ref` field for the base iteratorPatrick Steinhardt, Oct 22, 2025
  70. 03/14 refs: fully reset `struct ref_iterator::ref` on iterationPatrick Steinhardt, Oct 22, 2025
  71. 04/14 refs: refactor reference status flagsPatrick Steinhardt, Oct 22, 2025
  72. 05/14 refs: expose peeled object ID via the iteratorPatrick Steinhardt, Oct 22, 2025
  73. 06/14 upload-pack: convert to use `reference_get_peeled_oid()`Patrick Steinhardt, Oct 22, 2025
  74. 07/14 ref-filter: propagate peeled object IDPatrick Steinhardt, Oct 22, 2025
  75. 08/14 builtin/show-ref: convert to use `reference_get_peeled_oid()`Patrick Steinhardt, Oct 22, 2025
  76. 09/14 refs: drop `current_ref_iter` hackPatrick Steinhardt, Oct 22, 2025
  77. 10/14 refs: drop infrastructure to peel via iteratorsPatrick Steinhardt, Oct 22, 2025
  78. 11/14 object: add flag to `peel_object()` to verify object typePatrick Steinhardt, Oct 22, 2025
  79. 12/14 refs: don't store peeled object IDs for invalid tagsPatrick Steinhardt, Oct 22, 2025
  80. 13/14 ref-filter: detect broken tags when dereferencing themPatrick Steinhardt, Oct 22, 2025
  81. 14/14 ref-filter: parse objects on demandPatrick Steinhardt, Oct 22, 2025
  82. Junio C HamanoOct 22, 2025
  83. Patrick SteinhardtOct 23, 2025
  84. Karthik NayakOct 22, 2025
  85. Junio C HamanoOct 22, 2025
  86. Patrick SteinhardtOct 23, 2025
  87. 00/14 refs: improvements and fixes for peeling tagsPatrick Steinhardt, Oct 23, 2025
  88. 01/14 refs: introduce wrapper struct for `each_ref_fn`Patrick Steinhardt, Oct 23, 2025
  89. 02/14 refs: introduce `.ref` field for the base iteratorPatrick Steinhardt, Oct 23, 2025
  90. 03/14 refs: fully reset `struct ref_iterator::ref` on iterationPatrick Steinhardt, Oct 23, 2025
  91. 04/14 refs: refactor reference status flagsPatrick Steinhardt, Oct 23, 2025
  92. 05/14 refs: expose peeled object ID via the iteratorPatrick Steinhardt, Oct 23, 2025
  93. 06/14 upload-pack: convert to use `reference_get_peeled_oid()`Patrick Steinhardt, Oct 23, 2025
  94. 07/14 ref-filter: propagate peeled object IDPatrick Steinhardt, Oct 23, 2025
  95. 08/14 builtin/show-ref: convert to use `reference_get_peeled_oid()`Patrick Steinhardt, Oct 23, 2025
  96. 09/14 refs: drop `current_ref_iter` hackPatrick Steinhardt, Oct 23, 2025
  97. 10/14 refs: drop infrastructure to peel via iteratorsPatrick Steinhardt, Oct 23, 2025
  98. 11/14 object: add flag to `peel_object()` to verify object typePatrick Steinhardt, Oct 23, 2025
  99. 12/14 refs: don't store peeled object IDs for invalid tagsPatrick Steinhardt, Oct 23, 2025
  100. 13/14 ref-filter: detect broken tags when dereferencing themPatrick Steinhardt, Oct 23, 2025
  101. 14/14 ref-filter: parse objects on demandPatrick Steinhardt, Oct 23, 2025
  102. Jeff KingNov 4, 2025
  103. Junio C HamanoNov 4, 2025
  104. Jeff KingNov 4, 2025
  105. Junio C HamanoOct 23, 2025
  106. Patrick SteinhardtOct 24, 2025

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.