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

[PATCH 07/14] refs/iterator: separate lifecycle from iteration

From
Patrick Steinhardt <ps@pks.im>
Date
Feb 17, 2025, 15:50 UTC
Message-ID
<20250217-pks-update-ref-optimization-v1-7-a2b6d87a24af@pks.im>
In-Reply-To
<20250217-pks-update-ref-optimization-v1-0-a2b6d87a24af@pks.im>

The ref and reflog iterators have their lifecycle attached to iteration: once the iterator reaches its end, it is automatically released and the caller doesn't have to care about that anymore. When the iterator should be released before it has been exhausted, callers must explicitly abort the iterator via `ref_iterator_abort()`.

This lifecycle is somewhat unusual in the Git codebase and creates two problems:

  - Callsites need to be very careful about when exactly they call
    `ref_iterator_abort()`, as calling the function is only valid when
    the iterator itself still is. This leads to somewhat awkward calling
    patterns in some situations.
  - It is impossible to reuse iterators and re-seek them to a different
    prefix. This feature isn't supported by any iterator implementation
    except for the reftable iterators anyway, but if it was implemented
    it would allow us to optimize cases where we need to search for
    specific references repeatedly by reusing internal state.

Detangle the lifecycle from iteration so that we don't deallocate the iterator anymore once it is exhausted. Instead, callers are now expected to always call a newly introduce `ref_iterator_free()` function that deallocates the iterator and its internal state.

While at it, drop the return value of `ref_iterator_abort()`, which wasn't really required by any of the iterator implementations anyway. Furthermore, stop calling `base_ref_iterator_free()` in any of the backends, but instead call it in `ref_iterator_free()`.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 builtin/clone.c              |  2 +
 dir-iterator.c               | 24 +++++------
 dir-iterator.h               | 13 ++----
 refs.c                       |  7 +++-
 refs/debug.c                 |  9 ++---
 refs/files-backend.c         | 36 +++++------------
 refs/iterator.c              | 95 ++++++++++++++------------------------------
 refs/packed-backend.c        | 27 ++++++-------
 refs/ref-cache.c             |  9 ++---
 refs/refs-internal.h         | 31 +++++----------
 refs/reftable-backend.c      | 34 ++++------------
 t/helper/test-dir-iterator.c |  1 +
 12 files changed, 99 insertions(+), 189 deletions(-)
diff --git a/builtin/clone.c b/builtin/clone.c
index fd001d800c6..ac3e84b2b18 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -426,6 +426,8 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
 		strbuf_setlen(src, src_len);
 		die(_("failed to iterate over '%s'"), src->buf);
 	}
+
+	dir_iterator_free(iter);
 }
 
 static void clone_local(const char *src_repo, const char *dest_repo)
diff --git a/dir-iterator.c b/dir-iterator.c
index de619846f29..857e1d9bdaf 100644
--- a/dir-iterator.c
+++ b/dir-iterator.c
@@ -193,9 +193,9 @@ int dir_iterator_advance(struct dir_iterator *dir_iterator)
 
 	if (S_ISDIR(iter->base.st.st_mode) && push_level(iter)) {
 		if (errno != ENOENT && iter->flags & DIR_ITERATOR_PEDANTIC)
-			goto error_out;
+			return ITER_ERROR;
 		if (iter->levels_nr == 0)
-			goto error_out;
+			return ITER_ERROR;
 	}
 
 	/* Loop until we find an entry that we can give back to the caller. */
@@ -211,11 +211,11 @@ int dir_iterator_advance(struct dir_iterator *dir_iterator)
 			int ret = next_directory_entry(level->dir, iter->base.path.buf, &de);
 			if (ret < 0) {
 				if (iter->flags & DIR_ITERATOR_PEDANTIC)
-					goto error_out;
+					return ITER_ERROR;
 				continue;
 			} else if (ret > 0) {
 				if (pop_level(iter) == 0)
-					return dir_iterator_abort(dir_iterator);
+					return ITER_DONE;
 				continue;
 			}
 
@@ -223,7 +223,7 @@ int dir_iterator_advance(struct dir_iterator *dir_iterator)
 		} else {
 			if (level->entries_idx >= level->entries.nr) {
 				if (pop_level(iter) == 0)
-					return dir_iterator_abort(dir_iterator);
+					return ITER_DONE;
 				continue;
 			}
 
@@ -232,22 +232,21 @@ int dir_iterator_advance(struct dir_iterator *dir_iterator)
 
 		if (prepare_next_entry_data(iter, name)) {
 			if (errno != ENOENT && iter->flags & DIR_ITERATOR_PEDANTIC)
-				goto error_out;
+				return ITER_ERROR;
 			continue;
 		}
 
 		return ITER_OK;
 	}
-
-error_out:
-	dir_iterator_abort(dir_iterator);
-	return ITER_ERROR;
 }
 
-int dir_iterator_abort(struct dir_iterator *dir_iterator)
+void dir_iterator_free(struct dir_iterator *dir_iterator)
 {
 	struct dir_iterator_int *iter = (struct dir_iterator_int *)dir_iterator;
 
+	if (!iter)
+		return;
+
 	for (; iter->levels_nr; iter->levels_nr--) {
 		struct dir_iterator_level *level =
 			&iter->levels[iter->levels_nr - 1];
@@ -266,7 +265,6 @@ int dir_iterator_abort(struct dir_iterator *dir_iterator)
 	free(iter->levels);
 	strbuf_release(&iter->base.path);
 	free(iter);
-	return ITER_DONE;
 }
 
 struct dir_iterator *dir_iterator_begin(const char *path, unsigned int flags)
@@ -301,7 +299,7 @@ struct dir_iterator *dir_iterator_begin(const char *path, unsigned int flags)
 	return dir_iterator;
 
 error_out:
-	dir_iterator_abort(dir_iterator);
+	dir_iterator_free(dir_iterator);
 	errno = saved_errno;
 	return NULL;
 }
diff --git a/dir-iterator.h b/dir-iterator.h
index 6d438809b6e..01f51f6bac1 100644
--- a/dir-iterator.h
+++ b/dir-iterator.h
@@ -27,10 +27,8 @@
  *             goto error_handler;
  *
  *     while ((ok = dir_iterator_advance(iter)) == ITER_OK) {
- *             if (want_to_stop_iteration()) {
- *                     ok = dir_iterator_abort(iter);
+ *             if (want_to_stop_iteration())
  *                     break;
- *             }
  *
  *             // Access information about the current path:
  *             if (S_ISDIR(iter->st.st_mode))
@@ -39,6 +37,7 @@
  *
  *     if (ok != ITER_DONE)
  *             handle_error();
+ *     dir_iterator_release(iter);
  *
  * Callers are allowed to modify iter->path while they are working,
  * but they must restore it to its original contents before calling
@@ -107,11 +106,7 @@ struct dir_iterator *dir_iterator_begin(const char *path, unsigned int flags);
  */
 int dir_iterator_advance(struct dir_iterator *iterator);
 
-/*
- * End the iteration before it has been exhausted. Free the
- * dir_iterator and any associated resources and return ITER_DONE. On
- * error, free the dir_iterator and return ITER_ERROR.
- */
-int dir_iterator_abort(struct dir_iterator *iterator);
+/* Free the dir_iterator and any associated resources. */
+void dir_iterator_free(struct dir_iterator *iterator);
 
 #endif
diff --git a/refs.c b/refs.c
index eaf41421f50..8eff60a2186 100644
--- a/refs.c
+++ b/refs.c
@@ -2476,6 +2476,7 @@ int refs_verify_refnames_available(struct ref_store *refs,
 {
 	struct strbuf dirname = STRBUF_INIT;
 	struct strbuf referent = STRBUF_INIT;
+	struct ref_iterator *iter = NULL;
 	struct strset dirnames;
 	int ret = -1;
 
@@ -2552,7 +2553,6 @@ int refs_verify_refnames_available(struct ref_store *refs,
 		strbuf_addch(&dirname, '/');
 
 		if (!initial_transaction) {
-			struct ref_iterator *iter;
 			int ok;
 
 			iter = refs_ref_iterator_begin(refs, dirname.buf, NULL, 0,
@@ -2564,12 +2564,14 @@ int refs_verify_refnames_available(struct ref_store *refs,
 
 				strbuf_addf(err, _("'%s' exists; cannot create '%s'"),
 					    iter->refname, refname);
-				ref_iterator_abort(iter);
 				goto cleanup;
 			}
 
 			if (ok != ITER_DONE)
 				BUG("error while iterating over references");
+
+			ref_iterator_free(iter);
+			iter = NULL;
 		}
 
 		extra_refname = find_descendant_ref(dirname.buf, extras, skip);
@@ -2586,6 +2588,7 @@ int refs_verify_refnames_available(struct ref_store *refs,
 	strbuf_release(&referent);
 	strbuf_release(&dirname);
 	strset_clear(&dirnames);
+	ref_iterator_free(iter);
 	return ret;
 }
 
diff --git a/refs/debug.c b/refs/debug.c
index fbc4df08b43..a9786da4ba1 100644
--- a/refs/debug.c
+++ b/refs/debug.c
@@ -179,19 +179,18 @@ static int debug_ref_iterator_peel(struct ref_iterator *ref_iterator,
 	return res;
 }
 
-static int debug_ref_iterator_abort(struct ref_iterator *ref_iterator)
+static void debug_ref_iterator_release(struct ref_iterator *ref_iterator)
 {
 	struct debug_ref_iterator *diter =
 		(struct debug_ref_iterator *)ref_iterator;
-	int res = diter->iter->vtable->abort(diter->iter);
-	trace_printf_key(&trace_refs, "iterator_abort: %d\n", res);
-	return res;
+	diter->iter->vtable->release(diter->iter);
+	trace_printf_key(&trace_refs, "iterator_abort\n");
 }
 
 static struct ref_iterator_vtable debug_ref_iterator_vtable = {
 	.advance = debug_ref_iterator_advance,
 	.peel = debug_ref_iterator_peel,
-	.abort = debug_ref_iterator_abort,
+	.release = debug_ref_iterator_release,
 };
 
 static struct ref_iterator *
diff --git a/refs/files-backend.c b/refs/files-backend.c
index 29f08dced40..9511b6f3448 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -919,10 +919,6 @@ static int files_ref_iterator_advance(struct ref_iterator *ref_iterator)
 		return ITER_OK;
 	}
 
-	iter->iter0 = NULL;
-	if (ref_iterator_abort(ref_iterator) != ITER_DONE)
-		ok = ITER_ERROR;
-
 	return ok;
 }
 
@@ -935,23 +931,17 @@ static int files_ref_iterator_peel(struct ref_iterator *ref_iterator,
 	return ref_iterator_peel(iter->iter0, peeled);
 }
 
-static int files_ref_iterator_abort(struct ref_iterator *ref_iterator)
+static void files_ref_iterator_release(struct ref_iterator *ref_iterator)
 {
 	struct files_ref_iterator *iter =
 		(struct files_ref_iterator *)ref_iterator;
-	int ok = ITER_DONE;
-
-	if (iter->iter0)
-		ok = ref_iterator_abort(iter->iter0);
-
-	base_ref_iterator_free(ref_iterator);
-	return ok;
+	ref_iterator_free(iter->iter0);
 }
 
 static struct ref_iterator_vtable files_ref_iterator_vtable = {
 	.advance = files_ref_iterator_advance,
 	.peel = files_ref_iterator_peel,
-	.abort = files_ref_iterator_abort,
+	.release = files_ref_iterator_release,
 };
 
 static struct ref_iterator *files_ref_iterator_begin(
@@ -1382,7 +1372,7 @@ static int should_pack_refs(struct files_ref_store *refs,
 				    iter->flags, opts))
 			refcount++;
 		if (refcount >= limit) {
-			ref_iterator_abort(iter);
+			ref_iterator_free(iter);
 			return 1;
 		}
 	}
@@ -1390,6 +1380,7 @@ static int should_pack_refs(struct files_ref_store *refs,
 	if (ret != ITER_DONE)
 		die("error while iterating over references");
 
+	ref_iterator_free(iter);
 	return 0;
 }
 
@@ -1456,6 +1447,7 @@ static int files_pack_refs(struct ref_store *ref_store,
 	packed_refs_unlock(refs->packed_ref_store);
 
 	prune_refs(refs, &refs_to_prune);
+	ref_iterator_free(iter);
 	strbuf_release(&err);
 	return 0;
 }
@@ -2303,9 +2295,6 @@ static int files_reflog_iterator_advance(struct ref_iterator *ref_iterator)
 		return ITER_OK;
 	}
 
-	iter->dir_iterator = NULL;
-	if (ref_iterator_abort(ref_iterator) == ITER_ERROR)
-		ok = ITER_ERROR;
 	return ok;
 }
 
@@ -2315,23 +2304,17 @@ static int files_reflog_iterator_peel(struct ref_iterator *ref_iterator UNUSED,
 	BUG("ref_iterator_peel() called for reflog_iterator");
 }
 
-static int files_reflog_iterator_abort(struct ref_iterator *ref_iterator)
+static void files_reflog_iterator_release(struct ref_iterator *ref_iterator)
 {
 	struct files_reflog_iterator *iter =
 		(struct files_reflog_iterator *)ref_iterator;
-	int ok = ITER_DONE;
-
-	if (iter->dir_iterator)
-		ok = dir_iterator_abort(iter->dir_iterator);
-
-	base_ref_iterator_free(ref_iterator);
-	return ok;
+	dir_iterator_free(iter->dir_iterator);
 }
 
 static struct ref_iterator_vtable files_reflog_iterator_vtable = {
 	.advance = files_reflog_iterator_advance,
 	.peel = files_reflog_iterator_peel,
-	.abort = files_reflog_iterator_abort,
+	.release = files_reflog_iterator_release,
 };
 
 static struct ref_iterator *reflog_iterator_begin(struct ref_store *ref_store,
@@ -3808,6 +3791,7 @@ static int files_fsck_refs_dir(struct ref_store *ref_store,
 		ret = error(_("failed to iterate over '%s'"), sb.buf);
 
 out:
+	dir_iterator_free(iter);
 	strbuf_release(&sb);
 	strbuf_release(&refname);
 	return ret;
diff --git a/refs/iterator.c b/refs/iterator.c
index d25e568bf0b..aaeff270437 100644
--- a/refs/iterator.c
+++ b/refs/iterator.c
@@ -21,9 +21,14 @@ int ref_iterator_peel(struct ref_iterator *ref_iterator,
 	return ref_iterator->vtable->peel(ref_iterator, peeled);
 }
 
-int ref_iterator_abort(struct ref_iterator *ref_iterator)
+void ref_iterator_free(struct ref_iterator *ref_iterator)
 {
-	return ref_iterator->vtable->abort(ref_iterator);
+	if (ref_iterator) {
+		ref_iterator->vtable->release(ref_iterator);
+		/* Help make use-after-free bugs fail quickly: */
+		ref_iterator->vtable = NULL;
+		free(ref_iterator);
+	}
 }
 
 void base_ref_iterator_init(struct ref_iterator *iter,
@@ -36,20 +41,13 @@ void base_ref_iterator_init(struct ref_iterator *iter,
 	iter->flags = 0;
 }
 
-void base_ref_iterator_free(struct ref_iterator *iter)
-{
-	/* Help make use-after-free bugs fail quickly: */
-	iter->vtable = NULL;
-	free(iter);
-}
-
 struct empty_ref_iterator {
 	struct ref_iterator base;
 };
 
-static int empty_ref_iterator_advance(struct ref_iterator *ref_iterator)
+static int empty_ref_iterator_advance(struct ref_iterator *ref_iterator UNUSED)
 {
-	return ref_iterator_abort(ref_iterator);
+	return ITER_DONE;
 }
 
 static int empty_ref_iterator_peel(struct ref_iterator *ref_iterator UNUSED,
@@ -58,16 +56,14 @@ static int empty_ref_iterator_peel(struct ref_iterator *ref_iterator UNUSED,
 	BUG("peel called for empty iterator");
 }
 
-static int empty_ref_iterator_abort(struct ref_iterator *ref_iterator)
+static void empty_ref_iterator_release(struct ref_iterator *ref_iterator UNUSED)
 {
-	base_ref_iterator_free(ref_iterator);
-	return ITER_DONE;
 }
 
 static struct ref_iterator_vtable empty_ref_iterator_vtable = {
 	.advance = empty_ref_iterator_advance,
 	.peel = empty_ref_iterator_peel,
-	.abort = empty_ref_iterator_abort,
+	.release = empty_ref_iterator_release,
 };
 
 struct ref_iterator *empty_ref_iterator_begin(void)
@@ -151,11 +147,13 @@ static int merge_ref_iterator_advance(struct ref_iterator *ref_iterator)
 	if (!iter->current) {
 		/* Initialize: advance both iterators to their first entries */
 		if ((ok = ref_iterator_advance(iter->iter0)) != ITER_OK) {
+			ref_iterator_free(iter->iter0);
 			iter->iter0 = NULL;
 			if (ok == ITER_ERROR)
 				goto error;
 		}
 		if ((ok = ref_iterator_advance(iter->iter1)) != ITER_OK) {
+			ref_iterator_free(iter->iter1);
 			iter->iter1 = NULL;
 			if (ok == ITER_ERROR)
 				goto error;
@@ -166,6 +164,7 @@ static int merge_ref_iterator_advance(struct ref_iterator *ref_iterator)
 		 * entry:
 		 */
 		if ((ok = ref_iterator_advance(*iter->current)) != ITER_OK) {
+			ref_iterator_free(*iter->current);
 			*iter->current = NULL;
 			if (ok == ITER_ERROR)
 				goto error;
@@ -179,9 +178,8 @@ static int merge_ref_iterator_advance(struct ref_iterator *ref_iterator)
 			iter->select(iter->iter0, iter->iter1, iter->cb_data);
 
 		if (selection == ITER_SELECT_DONE) {
-			return ref_iterator_abort(ref_iterator);
+			return ITER_DONE;
 		} else if (selection == ITER_SELECT_ERROR) {
-			ref_iterator_abort(ref_iterator);
 			return ITER_ERROR;
 		}
 
@@ -195,6 +193,7 @@ static int merge_ref_iterator_advance(struct ref_iterator *ref_iterator)
 
 		if (selection & ITER_SKIP_SECONDARY) {
 			if ((ok = ref_iterator_advance(*secondary)) != ITER_OK) {
+				ref_iterator_free(*secondary);
 				*secondary = NULL;
 				if (ok == ITER_ERROR)
 					goto error;
@@ -211,7 +210,6 @@ static int merge_ref_iterator_advance(struct ref_iterator *ref_iterator)
 	}
 
 error:
-	ref_iterator_abort(ref_iterator);
 	return ITER_ERROR;
 }
 
@@ -227,28 +225,18 @@ static int merge_ref_iterator_peel(struct ref_iterator *ref_iterator,
 	return ref_iterator_peel(*iter->current, peeled);
 }
 
-static int merge_ref_iterator_abort(struct ref_iterator *ref_iterator)
+static void merge_ref_iterator_release(struct ref_iterator *ref_iterator)
 {
 	struct merge_ref_iterator *iter =
 		(struct merge_ref_iterator *)ref_iterator;
-	int ok = ITER_DONE;
-
-	if (iter->iter0) {
-		if (ref_iterator_abort(iter->iter0) != ITER_DONE)
-			ok = ITER_ERROR;
-	}
-	if (iter->iter1) {
-		if (ref_iterator_abort(iter->iter1) != ITER_DONE)
-			ok = ITER_ERROR;
-	}
-	base_ref_iterator_free(ref_iterator);
-	return ok;
+	ref_iterator_free(iter->iter0);
+	ref_iterator_free(iter->iter1);
 }
 
 static struct ref_iterator_vtable merge_ref_iterator_vtable = {
 	.advance = merge_ref_iterator_advance,
 	.peel = merge_ref_iterator_peel,
-	.abort = merge_ref_iterator_abort,
+	.release = merge_ref_iterator_release,
 };
 
 struct ref_iterator *merge_ref_iterator_begin(
@@ -310,10 +298,10 @@ struct ref_iterator *overlay_ref_iterator_begin(
 	 * them.
 	 */
 	if (is_empty_ref_iterator(front)) {
-		ref_iterator_abort(front);
+		ref_iterator_free(front);
 		return back;
 	} else if (is_empty_ref_iterator(back)) {
-		ref_iterator_abort(back);
+		ref_iterator_free(back);
 		return front;
 	}
 
@@ -350,19 +338,10 @@ static int prefix_ref_iterator_advance(struct ref_iterator *ref_iterator)
 
 	while ((ok = ref_iterator_advance(iter->iter0)) == ITER_OK) {
 		int cmp = compare_prefix(iter->iter0->refname, iter->prefix);
-
 		if (cmp < 0)
 			continue;
-
-		if (cmp > 0) {
-			/*
-			 * As the source iterator is ordered, we
-			 * can stop the iteration as soon as we see a
-			 * refname that comes after the prefix:
-			 */
-			ok = ref_iterator_abort(iter->iter0);
-			break;
-		}
+		if (cmp > 0)
+			return ITER_DONE;
 
 		if (iter->trim) {
 			/*
@@ -386,9 +365,6 @@ static int prefix_ref_iterator_advance(struct ref_iterator *ref_iterator)
 		return ITER_OK;
 	}
 
-	iter->iter0 = NULL;
-	if (ref_iterator_abort(ref_iterator) != ITER_DONE)
-		return ITER_ERROR;
 	return ok;
 }
 
@@ -401,23 +377,18 @@ static int prefix_ref_iterator_peel(struct ref_iterator *ref_iterator,
 	return ref_iterator_peel(iter->iter0, peeled);
 }
 
-static int prefix_ref_iterator_abort(struct ref_iterator *ref_iterator)
+static void prefix_ref_iterator_release(struct ref_iterator *ref_iterator)
 {
 	struct prefix_ref_iterator *iter =
 		(struct prefix_ref_iterator *)ref_iterator;
-	int ok = ITER_DONE;
-
-	if (iter->iter0)
-		ok = ref_iterator_abort(iter->iter0);
+	ref_iterator_free(iter->iter0);
 	free(iter->prefix);
-	base_ref_iterator_free(ref_iterator);
-	return ok;
 }
 
 static struct ref_iterator_vtable prefix_ref_iterator_vtable = {
 	.advance = prefix_ref_iterator_advance,
 	.peel = prefix_ref_iterator_peel,
-	.abort = prefix_ref_iterator_abort,
+	.release = prefix_ref_iterator_release,
 };
 
 struct ref_iterator *prefix_ref_iterator_begin(struct ref_iterator *iter0,
@@ -453,20 +424,14 @@ int do_for_each_ref_iterator(struct ref_iterator *iter,
 	current_ref_iter = iter;
 	while ((ok = ref_iterator_advance(iter)) == ITER_OK) {
 		retval = fn(iter->refname, iter->referent, iter->oid, iter->flags, cb_data);
-		if (retval) {
-			/*
-			 * If ref_iterator_abort() returns ITER_ERROR,
-			 * we ignore that error in deference to the
-			 * callback function's return value.
-			 */
-			ref_iterator_abort(iter);
+		if (retval)
 			goto out;
-		}
 	}
 
 out:
 	current_ref_iter = old_ref_iter;
 	if (ok == ITER_ERROR)
-		return -1;
+		retval = -1;
+	ref_iterator_free(iter);
 	return retval;
 }
diff --git a/refs/packed-backend.c b/refs/packed-backend.c
index a7b6f74b6e3..38a1956d1a8 100644
--- a/refs/packed-backend.c
+++ b/refs/packed-backend.c
@@ -954,9 +954,6 @@ static int packed_ref_iterator_advance(struct ref_iterator *ref_iterator)
 		return ITER_OK;
 	}
 
-	if (ref_iterator_abort(ref_iterator) != ITER_DONE)
-		ok = ITER_ERROR;
-
 	return ok;
 }
 
@@ -976,23 +973,19 @@ static int packed_ref_iterator_peel(struct ref_iterator *ref_iterator,
 	}
 }
 
-static int packed_ref_iterator_abort(struct ref_iterator *ref_iterator)
+static void packed_ref_iterator_release(struct ref_iterator *ref_iterator)
 {
 	struct packed_ref_iterator *iter =
 		(struct packed_ref_iterator *)ref_iterator;
-	int ok = ITER_DONE;
-
 	strbuf_release(&iter->refname_buf);
 	free(iter->jump);
 	release_snapshot(iter->snapshot);
-	base_ref_iterator_free(ref_iterator);
-	return ok;
 }
 
 static struct ref_iterator_vtable packed_ref_iterator_vtable = {
 	.advance = packed_ref_iterator_advance,
 	.peel = packed_ref_iterator_peel,
-	.abort = packed_ref_iterator_abort
+	.release = packed_ref_iterator_release,
 };
 
 static int jump_list_entry_cmp(const void *va, const void *vb)
@@ -1362,8 +1355,10 @@ static int write_with_updates(struct packed_ref_store *refs,
 	 */
 	iter = packed_ref_iterator_begin(&refs->base, "", NULL,
 					 DO_FOR_EACH_INCLUDE_BROKEN);
-	if ((ok = ref_iterator_advance(iter)) != ITER_OK)
+	if ((ok = ref_iterator_advance(iter)) != ITER_OK) {
+		ref_iterator_free(iter);
 		iter = NULL;
+	}
 
 	i = 0;
 
@@ -1411,8 +1406,10 @@ static int write_with_updates(struct packed_ref_store *refs,
 				 * the iterator over the unneeded
 				 * value.
 				 */
-				if ((ok = ref_iterator_advance(iter)) != ITER_OK)
+				if ((ok = ref_iterator_advance(iter)) != ITER_OK) {
+					ref_iterator_free(iter);
 					iter = NULL;
+				}
 				cmp = +1;
 			} else {
 				/*
@@ -1449,8 +1446,10 @@ static int write_with_updates(struct packed_ref_store *refs,
 					       peel_error ? NULL : &peeled))
 				goto write_error;
 
-			if ((ok = ref_iterator_advance(iter)) != ITER_OK)
+			if ((ok = ref_iterator_advance(iter)) != ITER_OK) {
+				ref_iterator_free(iter);
 				iter = NULL;
+			}
 		} else if (is_null_oid(&update->new_oid)) {
 			/*
 			 * The update wants to delete the reference,
@@ -1499,9 +1498,7 @@ static int write_with_updates(struct packed_ref_store *refs,
 		    get_tempfile_path(refs->tempfile), strerror(errno));
 
 error:
-	if (iter)
-		ref_iterator_abort(iter);
-
+	ref_iterator_free(iter);
 	delete_tempfile(&refs->tempfile);
 	return -1;
 }
diff --git a/refs/ref-cache.c b/refs/ref-cache.c
index 02f09e4df88..6457e02c1ea 100644
--- a/refs/ref-cache.c
+++ b/refs/ref-cache.c
@@ -409,7 +409,7 @@ static int cache_ref_iterator_advance(struct ref_iterator *ref_iterator)
 		if (++level->index == level->dir->nr) {
 			/* This level is exhausted; pop up a level */
 			if (--iter->levels_nr == 0)
-				return ref_iterator_abort(ref_iterator);
+				return ITER_DONE;
 
 			continue;
 		}
@@ -452,21 +452,18 @@ static int cache_ref_iterator_peel(struct ref_iterator *ref_iterator,
 	return peel_object(iter->repo, ref_iterator->oid, peeled) ? -1 : 0;
 }
 
-static int cache_ref_iterator_abort(struct ref_iterator *ref_iterator)
+static void cache_ref_iterator_release(struct ref_iterator *ref_iterator)
 {
 	struct cache_ref_iterator *iter =
 		(struct cache_ref_iterator *)ref_iterator;
-
 	free((char *)iter->prefix);
 	free(iter->levels);
-	base_ref_iterator_free(ref_iterator);
-	return ITER_DONE;
 }
 
 static struct ref_iterator_vtable cache_ref_iterator_vtable = {
 	.advance = cache_ref_iterator_advance,
 	.peel = cache_ref_iterator_peel,
-	.abort = cache_ref_iterator_abort
+	.release = cache_ref_iterator_release,
 };
 
 struct ref_iterator *cache_ref_iterator_begin(struct ref_cache *cache,
diff --git a/refs/refs-internal.h b/refs/refs-internal.h
index aaab711bb96..27ff822cf43 100644
--- a/refs/refs-internal.h
+++ b/refs/refs-internal.h
@@ -273,11 +273,11 @@ enum do_for_each_ref_flags {
  * the next reference and returns ITER_OK. The data pointed at by
  * refname and oid belong to the iterator; if you want to retain them
  * after calling ref_iterator_advance() again or calling
- * ref_iterator_abort(), you must make a copy. When the iteration has
+ * ref_iterator_free(), you must make a copy. When the iteration has
  * been exhausted, ref_iterator_advance() releases any resources
  * associated with the iteration, frees the ref_iterator object, and
  * returns ITER_DONE. If you want to abort the iteration early, call
- * ref_iterator_abort(), which also frees the ref_iterator object and
+ * ref_iterator_free(), which also frees the ref_iterator object and
  * any associated resources. If there was an internal error advancing
  * to the next entry, ref_iterator_advance() aborts the iteration,
  * frees the ref_iterator, and returns ITER_ERROR.
@@ -292,10 +292,8 @@ enum do_for_each_ref_flags {
  *     struct ref_iterator *iter = ...;
  *
  *     while ((ok = ref_iterator_advance(iter)) == ITER_OK) {
- *             if (want_to_stop_iteration()) {
- *                     ok = ref_iterator_abort(iter);
+ *             if (want_to_stop_iteration())
  *                     break;
- *             }
  *
  *             // Access information about the current reference:
  *             if (!(iter->flags & REF_ISSYMREF))
@@ -307,6 +305,7 @@ enum do_for_each_ref_flags {
  *
  *     if (ok != ITER_DONE)
  *             handle_error();
+ *     ref_iterator_free(iter);
  */
 struct ref_iterator {
 	struct ref_iterator_vtable *vtable;
@@ -333,12 +332,8 @@ int ref_iterator_advance(struct ref_iterator *ref_iterator);
 int ref_iterator_peel(struct ref_iterator *ref_iterator,
 		      struct object_id *peeled);
 
-/*
- * End the iteration before it has been exhausted, freeing the
- * reference iterator and any associated resources and returning
- * ITER_DONE. If the abort itself failed, return ITER_ERROR.
- */
-int ref_iterator_abort(struct ref_iterator *ref_iterator);
+/* Free the reference iterator and any associated resources. */
+void ref_iterator_free(struct ref_iterator *ref_iterator);
 
 /*
  * An iterator over nothing (its first ref_iterator_advance() call
@@ -438,13 +433,6 @@ struct ref_iterator *prefix_ref_iterator_begin(struct ref_iterator *iter0,
 void base_ref_iterator_init(struct ref_iterator *iter,
 			    struct ref_iterator_vtable *vtable);
 
-/*
- * Base class destructor for ref_iterators. Destroy the ref_iterator
- * part of iter and shallow-free the object. This is meant to be
- * called only by the destructors of derived classes.
- */
-void base_ref_iterator_free(struct ref_iterator *iter);
-
 /* Virtual function declarations for ref_iterators: */
 
 /*
@@ -463,15 +451,14 @@ typedef int ref_iterator_peel_fn(struct ref_iterator *ref_iterator,
 
 /*
  * Implementations of this function should free any resources specific
- * to the derived class, then call base_ref_iterator_free() to clean
- * up and free the ref_iterator object.
+ * to the derived class.
  */
-typedef int ref_iterator_abort_fn(struct ref_iterator *ref_iterator);
+typedef void ref_iterator_release_fn(struct ref_iterator *ref_iterator);
 
 struct ref_iterator_vtable {
 	ref_iterator_advance_fn *advance;
 	ref_iterator_peel_fn *peel;
-	ref_iterator_abort_fn *abort;
+	ref_iterator_release_fn *release;
 };
 
 /*
diff --git a/refs/reftable-backend.c b/refs/reftable-backend.c
index 2a90e7cb391..06543f79c64 100644
--- a/refs/reftable-backend.c
+++ b/refs/reftable-backend.c
@@ -711,17 +711,10 @@ static int reftable_ref_iterator_advance(struct ref_iterator *ref_iterator)
 		break;
 	}
 
-	if (iter->err > 0) {
-		if (ref_iterator_abort(ref_iterator) != ITER_DONE)
-			return ITER_ERROR;
+	if (iter->err > 0)
 		return ITER_DONE;
-	}
-
-	if (iter->err < 0) {
-		ref_iterator_abort(ref_iterator);
+	if (iter->err < 0)
 		return ITER_ERROR;
-	}
-
 	return ITER_OK;
 }
 
@@ -740,7 +733,7 @@ static int reftable_ref_iterator_peel(struct ref_iterator *ref_iterator,
 	return -1;
 }
 
-static int reftable_ref_iterator_abort(struct ref_iterator *ref_iterator)
+static void reftable_ref_iterator_release(struct ref_iterator *ref_iterator)
 {
 	struct reftable_ref_iterator *iter =
 		(struct reftable_ref_iterator *)ref_iterator;
@@ -751,14 +744,12 @@ static int reftable_ref_iterator_abort(struct ref_iterator *ref_iterator)
 			free(iter->exclude_patterns[i]);
 		free(iter->exclude_patterns);
 	}
-	free(iter);
-	return ITER_DONE;
 }
 
 static struct ref_iterator_vtable reftable_ref_iterator_vtable = {
 	.advance = reftable_ref_iterator_advance,
 	.peel = reftable_ref_iterator_peel,
-	.abort = reftable_ref_iterator_abort
+	.release = reftable_ref_iterator_release,
 };
 
 static int qsort_strcmp(const void *va, const void *vb)
@@ -2017,17 +2008,10 @@ static int reftable_reflog_iterator_advance(struct ref_iterator *ref_iterator)
 		break;
 	}
 
-	if (iter->err > 0) {
-		if (ref_iterator_abort(ref_iterator) != ITER_DONE)
-			return ITER_ERROR;
+	if (iter->err > 0)
 		return ITER_DONE;
-	}
-
-	if (iter->err < 0) {
-		ref_iterator_abort(ref_iterator);
+	if (iter->err < 0)
 		return ITER_ERROR;
-	}
-
 	return ITER_OK;
 }
 
@@ -2038,21 +2022,19 @@ static int reftable_reflog_iterator_peel(struct ref_iterator *ref_iterator UNUSE
 	return -1;
 }
 
-static int reftable_reflog_iterator_abort(struct ref_iterator *ref_iterator)
+static void reftable_reflog_iterator_release(struct ref_iterator *ref_iterator)
 {
 	struct reftable_reflog_iterator *iter =
 		(struct reftable_reflog_iterator *)ref_iterator;
 	reftable_log_record_release(&iter->log);
 	reftable_iterator_destroy(&iter->iter);
 	strbuf_release(&iter->last_name);
-	free(iter);
-	return ITER_DONE;
 }
 
 static struct ref_iterator_vtable reftable_reflog_iterator_vtable = {
 	.advance = reftable_reflog_iterator_advance,
 	.peel = reftable_reflog_iterator_peel,
-	.abort = reftable_reflog_iterator_abort
+	.release = reftable_reflog_iterator_release,
 };
 
 static struct reftable_reflog_iterator *reflog_iterator_for_stack(struct reftable_ref_store *refs,
diff --git a/t/helper/test-dir-iterator.c b/t/helper/test-dir-iterator.c
index 6b297bd7536..8d46e8ba409 100644
--- a/t/helper/test-dir-iterator.c
+++ b/t/helper/test-dir-iterator.c
@@ -53,6 +53,7 @@ int cmd__dir_iterator(int argc, const char **argv)
 		printf("(%s) [%s] %s\n", diter->relative_path, diter->basename,
 		       diter->path.buf);
 	}
+	dir_iterator_free(diter);
 
 	if (iter_status != ITER_DONE) {
 		printf("dir_iterator_advance failure\n");
-- 
2.48.1.666.gff9fcf71b7.dirty
Previous: Patrick SteinhardtNext: shejialuo
Message 11 of 169 in “refs: batch refname availability checks”
  1. 00/14 refs: batch refname availability checksPatrick Steinhardt, Feb 17, 2025
  2. 01/14 object-name: introduce `repo_get_oid_with_flags()`Patrick Steinhardt, Feb 17, 2025
  3. 02/14 object-name: allow skipping ambiguity checks in `get_oid()` familyPatrick Steinhardt, Feb 17, 2025
  4. 03/14 builtin/update-ref: skip ambiguity checks when parsing object IDsPatrick Steinhardt, Feb 17, 2025
  5. Karthik NayakFeb 18, 2025
  6. 04/14 refs: introduce function to batch refname availability checksPatrick Steinhardt, Feb 17, 2025
  7. 05/14 refs/reftable: start using `refs_verify_refnames_available()`Patrick Steinhardt, Feb 17, 2025
  8. 06/14 refs: stop re-verifying common prefixes for availabilityPatrick Steinhardt, Feb 17, 2025
  9. Karthik NayakFeb 18, 2025
  10. Patrick SteinhardtFeb 19, 2025
  11. 07/14 refs/iterator: separate lifecycle from iterationPatrick Steinhardt, Feb 17, 2025
  12. shejialuoFeb 18, 2025
  13. Patrick SteinhardtFeb 19, 2025
  14. shejialuoFeb 19, 2025
  15. Patrick SteinhardtFeb 19, 2025
  16. shejialuoFeb 19, 2025
  17. Patrick SteinhardtFeb 19, 2025
  18. Patrick SteinhardtFeb 19, 2025
  19. shejialuoFeb 19, 2025
  20. Karthik NayakFeb 18, 2025
  21. Patrick SteinhardtFeb 19, 2025
  22. 08/14 refs/iterator: provide infrastructure to re-seek iteratorsPatrick Steinhardt, Feb 17, 2025
  23. 09/14 refs/iterator: implement seeking for merged iteratorsPatrick Steinhardt, Feb 17, 2025
  24. Karthik NayakFeb 19, 2025
  25. 10/14 refs/iterator: implement seeking for reftable iteratorsPatrick Steinhardt, Feb 17, 2025
  26. Karthik NayakFeb 19, 2025
  27. 11/14 refs/iterator: implement seeking for ref-cache iteratorsPatrick Steinhardt, Feb 17, 2025
  28. 12/14 refs/iterator: implement seeking for `packed-ref` iteratorsPatrick Steinhardt, Feb 17, 2025
  29. 13/14 refs/iterator: implement seeking for "files" iteratorsPatrick Steinhardt, Feb 17, 2025
  30. 14/14 refs: reuse iterators when determining refname availabilityPatrick Steinhardt, Feb 17, 2025
  31. brian m. carlsonFeb 18, 2025
  32. 00/16 refs: batch refname availability checksPatrick Steinhardt, Feb 19, 2025
  33. 01/16 object-name: introduce `repo_get_oid_with_flags()`Patrick Steinhardt, Feb 19, 2025
  34. Justin ToblerFeb 19, 2025
  35. 02/16 object-name: allow skipping ambiguity checks in `get_oid()` familyPatrick Steinhardt, Feb 19, 2025
  36. Jeff KingFeb 21, 2025
  37. Patrick SteinhardtFeb 21, 2025
  38. Jeff KingFeb 21, 2025
  39. 03/16 builtin/update-ref: skip ambiguity checks when parsing object IDsPatrick Steinhardt, Feb 19, 2025
  40. Justin ToblerFeb 19, 2025
  41. Patrick SteinhardtFeb 20, 2025
  42. 04/16 refs: introduce function to batch refname availability checksPatrick Steinhardt, Feb 19, 2025
  43. 05/16 refs/reftable: batch refname availability checksPatrick Steinhardt, Feb 19, 2025
  44. 06/16 refs/files: batch refname availability checks for normal transactionsPatrick Steinhardt, Feb 19, 2025
  45. 07/16 refs/files: batch refname availability checks for initial transactionsPatrick Steinhardt, Feb 19, 2025
  46. 08/16 refs: stop re-verifying common prefixes for availabilityPatrick Steinhardt, Feb 19, 2025
  47. 09/16 refs/iterator: separate lifecycle from iterationPatrick Steinhardt, Feb 19, 2025
  48. 11/16 refs/iterator: implement seeking for merged iteratorsPatrick Steinhardt, Feb 19, 2025
  49. shejialuoFeb 24, 2025
  50. Patrick SteinhardtFeb 25, 2025
  51. 10/16 refs/iterator: provide infrastructure to re-seek iteratorsPatrick Steinhardt, Feb 19, 2025
  52. shejialuoFeb 24, 2025
  53. Patrick SteinhardtFeb 25, 2025
  54. 12/16 refs/iterator: implement seeking for reftable iteratorsPatrick Steinhardt, Feb 19, 2025
  55. shejialuoFeb 24, 2025
  56. Patrick SteinhardtFeb 25, 2025
  57. 13/16 refs/iterator: implement seeking for ref-cache iteratorsPatrick Steinhardt, Feb 19, 2025
  58. shejialuoFeb 24, 2025
  59. Patrick SteinhardtFeb 25, 2025
  60. 14/16 refs/iterator: implement seeking for `packed-ref` iteratorsPatrick Steinhardt, Feb 19, 2025
  61. shejialuoFeb 24, 2025
  62. Patrick SteinhardtFeb 25, 2025
  63. shejialuoFeb 25, 2025
  64. 16/16 refs: reuse iterators when determining refname availabilityPatrick Steinhardt, Feb 19, 2025
  65. shejialuoFeb 24, 2025
  66. 15/16 refs/iterator: implement seeking for "files" iteratorsPatrick Steinhardt, Feb 19, 2025
  67. shejialuoFeb 24, 2025
  68. Patrick SteinhardtFeb 25, 2025
  69. 00/16 refs: batch refname availability checksPatrick Steinhardt, Feb 25, 2025
  70. 01/16 object-name: introduce `repo_get_oid_with_flags()`Patrick Steinhardt, Feb 25, 2025
  71. 02/16 object-name: allow skipping ambiguity checks in `get_oid()` familyPatrick Steinhardt, Feb 25, 2025
  72. 03/16 builtin/update-ref: skip ambiguity checks when parsing object IDsPatrick Steinhardt, Feb 25, 2025
  73. Junio C HamanoFeb 26, 2025
  74. Patrick SteinhardtFeb 27, 2025
  75. 04/16 refs: introduce function to batch refname availability checksPatrick Steinhardt, Feb 25, 2025
  76. 05/16 refs/reftable: batch refname availability checksPatrick Steinhardt, Feb 25, 2025
  77. 06/16 refs/files: batch refname availability checks for normal transactionsPatrick Steinhardt, Feb 25, 2025
  78. 07/16 refs/files: batch refname availability checks for initial transactionsPatrick Steinhardt, Feb 25, 2025
  79. 08/16 refs: stop re-verifying common prefixes for availabilityPatrick Steinhardt, Feb 25, 2025
  80. 10/16 refs/iterator: provide infrastructure to re-seek iteratorsPatrick Steinhardt, Feb 25, 2025
  81. 09/16 refs/iterator: separate lifecycle from iterationPatrick Steinhardt, Feb 25, 2025
  82. 11/16 refs/iterator: implement seeking for merged iteratorsPatrick Steinhardt, Feb 25, 2025
  83. 12/16 refs/iterator: implement seeking for reftable iteratorsPatrick Steinhardt, Feb 25, 2025
  84. 13/16 refs/iterator: implement seeking for ref-cache iteratorsPatrick Steinhardt, Feb 25, 2025
  85. 14/16 refs/iterator: implement seeking for packed-ref iteratorsPatrick Steinhardt, Feb 25, 2025
  86. 15/16 refs/iterator: implement seeking for files iteratorsPatrick Steinhardt, Feb 25, 2025
  87. 16/16 refs: reuse iterators when determining refname availabilityPatrick Steinhardt, Feb 25, 2025
  88. 00/16 refs: batch refname availability checksPatrick Steinhardt, Feb 28, 2025
  89. 01/16 object-name: introduce `repo_get_oid_with_flags()`Patrick Steinhardt, Feb 28, 2025
  90. 02/16 object-name: allow skipping ambiguity checks in `get_oid()` familyPatrick Steinhardt, Feb 28, 2025
  91. Karthik NayakMar 6, 2025
  92. 03/16 builtin/update-ref: skip ambiguity checks when parsing object IDsPatrick Steinhardt, Feb 28, 2025
  93. 04/16 refs: introduce function to batch refname availability checksPatrick Steinhardt, Feb 28, 2025
  94. Karthik NayakMar 6, 2025
  95. 05/16 refs/reftable: batch refname availability checksPatrick Steinhardt, Feb 28, 2025
  96. Karthik NayakMar 6, 2025
  97. Karthik NayakMar 6, 2025
  98. Patrick SteinhardtMar 6, 2025
  99. 06/16 refs/files: batch refname availability checks for normal transactionsPatrick Steinhardt, Feb 28, 2025
  100. 07/16 refs/files: batch refname availability checks for initial transactionsPatrick Steinhardt, Feb 28, 2025
  101. Karthik NayakMar 6, 2025
  102. 08/16 refs: stop re-verifying common prefixes for availabilityPatrick Steinhardt, Feb 28, 2025
  103. 09/16 refs/iterator: separate lifecycle from iterationPatrick Steinhardt, Feb 28, 2025
  104. 10/16 refs/iterator: provide infrastructure to re-seek iteratorsPatrick Steinhardt, Feb 28, 2025
  105. 11/16 refs/iterator: implement seeking for merged iteratorsPatrick Steinhardt, Feb 28, 2025
  106. 12/16 refs/iterator: implement seeking for reftable iteratorsPatrick Steinhardt, Feb 28, 2025
  107. Karthik NayakMar 6, 2025
  108. 13/16 refs/iterator: implement seeking for ref-cache iteratorsPatrick Steinhardt, Feb 28, 2025
  109. 14/16 refs/iterator: implement seeking for packed-ref iteratorsPatrick Steinhardt, Feb 28, 2025
  110. 15/16 refs/iterator: implement seeking for files iteratorsPatrick Steinhardt, Feb 28, 2025
  111. 16/16 refs: reuse iterators when determining refname availabilityPatrick Steinhardt, Feb 28, 2025
  112. Karthik NayakMar 6, 2025
  113. 00/16 refs: batch refname availability checksPatrick Steinhardt, Mar 6, 2025
  114. 01/16 object-name: introduce `repo_get_oid_with_flags()`Patrick Steinhardt, Mar 6, 2025
  115. 02/16 object-name: allow skipping ambiguity checks in `get_oid()` familyPatrick Steinhardt, Mar 6, 2025
  116. shejialuoMar 12, 2025
  117. 03/16 builtin/update-ref: skip ambiguity checks when parsing object IDsPatrick Steinhardt, Mar 6, 2025
  118. 04/16 refs: introduce function to batch refname availability checksPatrick Steinhardt, Mar 6, 2025
  119. shejialuoMar 12, 2025
  120. shejialuoMar 12, 2025
  121. Patrick SteinhardtMar 12, 2025
  122. 05/16 refs/reftable: batch refname availability checksPatrick Steinhardt, Mar 6, 2025
  123. shejialuoMar 12, 2025
  124. Patrick SteinhardtMar 12, 2025
  125. 06/16 refs/files: batch refname availability checks for normal transactionsPatrick Steinhardt, Mar 6, 2025
  126. shejialuoMar 12, 2025
  127. Patrick SteinhardtMar 12, 2025
  128. 07/16 refs/files: batch refname availability checks for initial transactionsPatrick Steinhardt, Mar 6, 2025
  129. shejialuoMar 12, 2025
  130. Patrick SteinhardtMar 12, 2025
  131. 08/16 refs: stop re-verifying common prefixes for availabilityPatrick Steinhardt, Mar 6, 2025
  132. shejialuoMar 12, 2025
  133. Patrick SteinhardtMar 12, 2025
  134. 11/16 refs/iterator: implement seeking for merged iteratorsPatrick Steinhardt, Mar 6, 2025
  135. 09/16 refs/iterator: separate lifecycle from iterationPatrick Steinhardt, Mar 6, 2025
  136. shejialuoMar 12, 2025
  137. Patrick SteinhardtMar 12, 2025
  138. 10/16 refs/iterator: provide infrastructure to re-seek iteratorsPatrick Steinhardt, Mar 6, 2025
  139. 12/16 refs/iterator: implement seeking for reftable iteratorsPatrick Steinhardt, Mar 6, 2025
  140. 13/16 refs/iterator: implement seeking for ref-cache iteratorsPatrick Steinhardt, Mar 6, 2025
  141. 14/16 refs/iterator: implement seeking for packed-ref iteratorsPatrick Steinhardt, Mar 6, 2025
  142. 15/16 refs/iterator: implement seeking for files iteratorsPatrick Steinhardt, Mar 6, 2025
  143. 16/16 refs: reuse iterators when determining refname availabilityPatrick Steinhardt, Mar 6, 2025
  144. Karthik NayakMar 6, 2025
  145. shejialuoMar 12, 2025
  146. 00/16 refs: batch refname availability checksPatrick Steinhardt, Mar 12, 2025
  147. 01/16 object-name: introduce `repo_get_oid_with_flags()`Patrick Steinhardt, Mar 12, 2025
  148. 02/16 object-name: allow skipping ambiguity checks in `get_oid()` familyPatrick Steinhardt, Mar 12, 2025
  149. 03/16 builtin/update-ref: skip ambiguity checks when parsing object IDsPatrick Steinhardt, Mar 12, 2025
  150. 04/16 refs: introduce function to batch refname availability checksPatrick Steinhardt, Mar 12, 2025
  151. 05/16 refs/reftable: batch refname availability checksPatrick Steinhardt, Mar 12, 2025
  152. 06/16 refs/files: batch refname availability checks for normal transactionsPatrick Steinhardt, Mar 12, 2025
  153. 07/16 refs/files: batch refname availability checks for initial transactionsPatrick Steinhardt, Mar 12, 2025
  154. 08/16 refs: stop re-verifying common prefixes for availabilityPatrick Steinhardt, Mar 12, 2025
  155. 11/16 refs/iterator: implement seeking for merged iteratorsPatrick Steinhardt, Mar 12, 2025
  156. 10/16 refs/iterator: provide infrastructure to re-seek iteratorsPatrick Steinhardt, Mar 12, 2025
  157. 09/16 refs/iterator: separate lifecycle from iterationPatrick Steinhardt, Mar 12, 2025
  158. 12/16 refs/iterator: implement seeking for reftable iteratorsPatrick Steinhardt, Mar 12, 2025
  159. 14/16 refs/iterator: implement seeking for packed-ref iteratorsPatrick Steinhardt, Mar 12, 2025
  160. Elijah NewrenApr 3, 2025
  161. brian m. carlsonApr 3, 2025
  162. shejialuoApr 4, 2025
  163. Patrick SteinhardtApr 4, 2025
  164. Patrick SteinhardtApr 4, 2025
  165. Patrick SteinhardtApr 4, 2025
  166. 13/16 refs/iterator: implement seeking for ref-cache iteratorsPatrick Steinhardt, Mar 12, 2025
  167. 15/16 refs/iterator: implement seeking for files iteratorsPatrick Steinhardt, Mar 12, 2025
  168. 16/16 refs: reuse iterators when determining refname availabilityPatrick Steinhardt, Mar 12, 2025
  169. shejialuoMar 13, 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.