object-file: introduce function to iterate through objects

We have multiple divergent interfaces to iterate through objects of a specific backend: - `for_each_loose_object()` yields all loose objects. - `for_each_packed_object()` (somewhat obviously) yields all packed objects. These functions have different function signatures, which makes it hard to create a common abstraction layer that covers both of these. Introduce a new function `odb_source_loose_for_each_object()` to plug this gap. This function doesn't take any data specific to loose objects, but instead it accepts a `struct object_info` that will be populated the exact same as if `odb_source_loose_read_object()` was called. The benefit of this new interface is that we can continue to pass backend-specific data, as `struct object_info` contains a union for these exact use cases. This will allow us to unify how we iterate through objects across both loose and packed objects in a subsequent commit. The `for_each_loose_object()` function continues to exist for now, but it will be removed at the end of this patch series. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Jan 26, 2026 at 10:51 UTC cde615b6f05228cd7cf125de6bf5757381f65381
3 files changed +71
object-file.c
+48
@@ -1801,6 +1801,54 @@ int for_each_loose_object(struct object_database *odb,
1801 return 0;
1802 }
1803
1804 +struct for_each_object_wrapper_data {
1805 + struct odb_source *source;
1806 + const struct object_info *request;
1807 + odb_for_each_object_cb cb;
1808 + void *cb_data;
1809 +};
1810 +
1811 +static int for_each_object_wrapper_cb(const struct object_id *oid,
1812 + const char *path,
1813 + void *cb_data)
1814 +{
1815 + struct for_each_object_wrapper_data *data = cb_data;
1816 +
1817 + if (data->request) {
1818 + struct object_info oi = *data->request;
1819 +
1820 + if (read_object_info_from_path(data->source, path, oid, &oi, 0) < 0)
1821 + return -1;
1822 +
1823 + return data->cb(oid, &oi, data->cb_data);
1824 + } else {
1825 + return data->cb(oid, NULL, data->cb_data);
1826 + }
1827 +}
1828 +
1829 +int odb_source_loose_for_each_object(struct odb_source *source,
1830 + const struct object_info *request,
1831 + odb_for_each_object_cb cb,
1832 + void *cb_data,
1833 + unsigned flags)
1834 +{
1835 + struct for_each_object_wrapper_data data = {
1836 + .source = source,
1837 + .request = request,
1838 + .cb = cb,
1839 + .cb_data = cb_data,
1840 + };
1841 +
1842 + /* There are no loose promisor objects, so we can return immediately. */
1843 + if ((flags & ODB_FOR_EACH_OBJECT_PROMISOR_ONLY))
1844 + return 0;
1845 + if ((flags & ODB_FOR_EACH_OBJECT_LOCAL_ONLY) && !source->local)
1846 + return 0;
1847 +
1848 + return for_each_loose_file_in_source(source, for_each_object_wrapper_cb,
1849 + NULL, NULL, &data);
1850 +}
1851 +
1852 static int append_loose_object(const struct object_id *oid,
1853 const char *path UNUSED,
1854 void *data)
object-file.h
+11
@@ -137,6 +137,17 @@ int for_each_loose_object(struct object_database *odb,
137 each_loose_object_fn, void *,
138 enum odb_for_each_object_flags flags);
139
140 +/*
141 + * Iterate through all loose objects in the given object database source and
142 + * invoke the callback function for each of them. If given, the object info
143 + * will be populated with the object's data as if you had called
144 + * `odb_source_loose_read_object_info()` on the object.
145 + */
146 +int odb_source_loose_for_each_object(struct odb_source *source,
147 + const struct object_info *request,
148 + odb_for_each_object_cb cb,
149 + void *cb_data,
150 + unsigned flags);
151
152 /**
153 * format_object_header() is a thin wrapper around s xsnprintf() that
odb.h
+12
@@ -463,6 +463,18 @@ enum odb_for_each_object_flags {
463 ODB_FOR_EACH_OBJECT_SKIP_ON_DISK_KEPT_PACKS = (1<<4),
464 };
465
466 +/*
467 + * A callback function that can be used to iterate through objects. If given,
468 + * the optional `oi` parameter will be populated the same as if you would call
469 + * `odb_read_object_info()`.
470 + *
471 + * Returning a non-zero error code will cause iteration to abort. The error
472 + * code will be propagated.
473 + */
474 +typedef int (*odb_for_each_object_cb)(const struct object_id *oid,
475 + struct object_info *oi,
476 + void *cb_data);
477 +
478 enum {
479 /*
480 * By default, `odb_write_object()` does not actually write anything