[PATCH] builtin/reflog: expire --all and named refs in one loop

From
Laveesh Bansal <hidden>
Date
2026-11-08 01:22:38
"git reflog expire" sets up the call to refs_reflog_expire() twice,
once for --all and once for refs named on the command line.
d1536ac3e2 (builtin/reflog: say "would prune" for named refs with
--dry-run, 2026-10-23) fixed the named-ref copy, which was missing
dry_run. Junio suggested a single loop in the review of that fix [1].

Collect the refs from both sources into one list and expire them in a
single loop. The names given on the command line are still looked up
in that loop, so the output and the exit status stay the same.

[1] https://lore.kernel.org/git/xmqqqzhdy7pi.fsf@gitster.g/ (local)

Assisted-by: Claude Sonnet 5.5
Signed-off-by: Laveesh Bansal <redacted>
---

Notes:
    The lookup stays in the loop. Doing it while collecting would report an
    unknown name before any expiry output, and make "expire --expire=now
    HEAD @{-1}" succeed.
    
    I ran the full test suite, and the reflog tests with reftable, sha256
    and SANITIZE=leak. Output, exit status and the resulting reflogs match
    the base for the cases I tried, including @{-1} and unknown names.

 builtin/reflog.c | 50 +++++++++++++++++++++++-------------------------
 1 file changed, 24 insertions(+), 26 deletions(-)
diff --git a/builtin/reflog.c b/builtin/reflog.c
index 49e5453dd9..42d37a3724 100644
--- a/builtin/reflog.c
+++ b/builtin/reflog.c
@@ -187,6 +187,10 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix,
 	unsigned int flags = 0;
 	int verbose = 0;
 	reflog_expiry_should_prune_fn *should_prune_fn = should_expire_reflog_ent;
+	struct worktree_reflogs collected = {
+		.reflogs = STRING_LIST_INIT_DUP,
+	};
+	struct string_list_item *item;
 	const struct option options[] = {
 		OPT_BIT('n', "dry-run", &flags, N_("do not actually prune any entries"),
 			EXPIRE_REFLOGS_DRY_RUN),
@@ -244,10 +248,6 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix,
 	}
 
 	if (do_all) {
-		struct worktree_reflogs collected = {
-			.reflogs = STRING_LIST_INIT_DUP,
-		};
-		struct string_list_item *item;
 		struct worktree **worktrees, **p;
 
 		worktrees = get_worktrees(the_repository);
@@ -259,44 +259,42 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix,
 					     collect_reflog, &collected);
 		}
 		free_worktrees(worktrees);
-
-		for_each_string_list_item(item, &collected.reflogs) {
-			struct expire_reflog_policy_cb cb = {
-				.opts = opts,
-				.dry_run = !!(flags & EXPIRE_REFLOGS_DRY_RUN),
-			};
-
-			reflog_expire_options_set_refname(&cb.opts,  item->string);
-			status |= refs_reflog_expire(get_main_ref_store(the_repository),
-						     item->string, flags,
-						     reflog_expiry_prepare,
-						     should_prune_fn,
-						     reflog_expiry_cleanup,
-						     &cb);
-		}
-		string_list_clear(&collected.reflogs, 0);
 	}
 
+	/* util marks the names that still have to be looked up */
 	for (i = 0; i < argc; i++) {
-		char *ref;
+		item = string_list_append(&collected.reflogs, argv[i]);
+		item->util = (void *)1;
+	}
+
+	for_each_string_list_item(item, &collected.reflogs) {
 		struct expire_reflog_policy_cb cb = {
 			.opts = opts,
 			.dry_run = !!(flags & EXPIRE_REFLOGS_DRY_RUN),
 		};
-
-		if (!repo_dwim_log(the_repository, argv[i], strlen(argv[i]), NULL, &ref)) {
-			status |= error(_("reflog could not be found: '%s'"), argv[i]);
+		const char *refname = item->string;
+		char *ref = NULL;
+
+		if (item->util &&
+		    !repo_dwim_log(the_repository, item->string,
+				   strlen(item->string), NULL, &ref)) {
+			status |= error(_("reflog could not be found: '%s'"),
+					item->string);
 			continue;
 		}
-		reflog_expire_options_set_refname(&cb.opts, ref);
+		if (ref)
+			refname = ref;
+
+		reflog_expire_options_set_refname(&cb.opts, refname);
 		status |= refs_reflog_expire(get_main_ref_store(the_repository),
-					     ref, flags,
+					     refname, flags,
 					     reflog_expiry_prepare,
 					     should_prune_fn,
 					     reflog_expiry_cleanup,
 					     &cb);
 		free(ref);
 	}
+	string_list_clear(&collected.reflogs, 0);
 
 	reflog_clear_expire_config(&opts);
 
-- 
2.54.0
Keyboard shortcuts
hback out one level
jnext message in thread / next series-diff position
kprevious message in thread / previous series-diff position
ldrill in
Escclose help / fold thread tree
?toggle this help