git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Karthik Nayak <karthik.188@gmail.com>
To: git@vger.kernel.org
Cc: Karthik Nayak <karthik.188@gmail.com>, gitster@pobox.com, ps@pks.im
Subject: [PATCH v2 4/4] for-each-ref: introduce a '--skip-until' option
Date: Fri, 04 Jul 2025 15:02:32 +0200	[thread overview]
Message-ID: <20250704-306-git-for-each-ref-pagination-v2-4-bcde14acdd81@gmail.com> (raw)
In-Reply-To: <20250704-306-git-for-each-ref-pagination-v2-0-bcde14acdd81@gmail.com>

The `git-for-each-ref(1)` command is used to iterate over references
present in a repository. In large repositories with millions of
references, it would be optimal to paginate this output such that we
can start iteration from a given reference. This would avoid having to
iterate over all references from the beginning each time when paginating
through results.

The previous commit added 'seek' functionality to the reference
backends. Utilize this and expose a '--skip-until' option in
'git-for-each-ref(1)'. When used, the reference iteration seeks to the
first matching reference and iterates from there onward.

This enables efficient pagination workflows like:
    git for-each-ref --count=100
    git for-each-ref --count=100 --skip-until=refs/heads/branch-100
    git for-each-ref --count=100 --skip-until=refs/heads/branch-200

Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
 Documentation/git-for-each-ref.adoc |   6 +-
 builtin/for-each-ref.c              |   8 ++
 ref-filter.c                        |  61 ++++++++----
 ref-filter.h                        |   1 +
 t/t6302-for-each-ref-filter.sh      | 188 ++++++++++++++++++++++++++++++++++++
 5 files changed, 243 insertions(+), 21 deletions(-)

diff --git a/Documentation/git-for-each-ref.adoc b/Documentation/git-for-each-ref.adoc
index 5ef89fc0fe..e369fee9a1 100644
--- a/Documentation/git-for-each-ref.adoc
+++ b/Documentation/git-for-each-ref.adoc
@@ -14,7 +14,7 @@ SYNOPSIS
 		   [--points-at=<object>]
 		   [--merged[=<object>]] [--no-merged[=<object>]]
 		   [--contains[=<object>]] [--no-contains[=<object>]]
-		   [--exclude=<pattern> ...]
+		   [--exclude=<pattern> ...] [--skip-until=<pattern>]
 
 DESCRIPTION
 -----------
@@ -108,6 +108,10 @@ TAB %(refname)`.
 --include-root-refs::
 	List root refs (HEAD and pseudorefs) apart from regular refs.
 
+--skip-until::
+    Skip references up to but excluding the specified pattern. Cannot be used
+    with general pattern matching or custom sort options.
+
 FIELD NAMES
 -----------
 
diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c
index 3d2207ec77..aee2e7489a 100644
--- a/builtin/for-each-ref.c
+++ b/builtin/for-each-ref.c
@@ -13,6 +13,7 @@ static char const * const for_each_ref_usage[] = {
 	N_("git for-each-ref [--points-at <object>]"),
 	N_("git for-each-ref [--merged [<commit>]] [--no-merged [<commit>]]"),
 	N_("git for-each-ref [--contains [<commit>]] [--no-contains [<commit>]]"),
+	N_("git for-each-ref [--skip-until <pattern>]"),
 	NULL
 };
 
@@ -44,6 +45,7 @@ int cmd_for_each_ref(int argc,
 		OPT_GROUP(""),
 		OPT_INTEGER( 0 , "count", &format.array_opts.max_count, N_("show only <n> matched refs")),
 		OPT_STRING(  0 , "format", &format.format, N_("format"), N_("format to use for the output")),
+		OPT_STRING(  0 , "skip-until", &filter.seek, N_("skip-until"), N_("skip references until")),
 		OPT__COLOR(&format.use_color, N_("respect format colors")),
 		OPT_REF_FILTER_EXCLUDE(&filter),
 		OPT_REF_SORT(&sorting_options),
@@ -79,6 +81,9 @@ int cmd_for_each_ref(int argc,
 	if (verify_ref_format(&format))
 		usage_with_options(for_each_ref_usage, opts);
 
+	if (filter.seek && sorting_options.nr > 1)
+		die(_("cannot use --skip-until custom sort options"));
+
 	sorting = ref_sorting_options(&sorting_options);
 	ref_sorting_set_sort_flags_all(sorting, REF_SORTING_ICASE, icase);
 	filter.ignore_case = icase;
@@ -100,6 +105,9 @@ int cmd_for_each_ref(int argc,
 		filter.name_patterns = argv;
 	}
 
+	if (filter.seek && filter.name_patterns && filter.name_patterns[0])
+		die(_("cannot use --skip-until with patterns"));
+
 	if (include_root_refs)
 		flags |= FILTER_REFS_ROOT_REFS | FILTER_REFS_DETACHED_HEAD;
 
diff --git a/ref-filter.c b/ref-filter.c
index 7a274633cf..56bb5312bd 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -2692,10 +2692,13 @@ static int for_each_fullref_in_pattern(struct ref_filter *filter,
 				       each_ref_fn cb,
 				       void *cb_data)
 {
+	struct ref_iterator *iter;
+	int flags = 0, ret = 0;
+
 	if (filter->kind & FILTER_REFS_ROOT_REFS) {
 		/* In this case, we want to print all refs including root refs. */
-		return refs_for_each_include_root_refs(get_main_ref_store(the_repository),
-						       cb, cb_data);
+		flags |= DO_FOR_EACH_INCLUDE_ROOT_REFS;
+		goto non_prefix_iter;
 	}
 
 	if (!filter->match_as_path) {
@@ -2704,8 +2707,7 @@ static int for_each_fullref_in_pattern(struct ref_filter *filter,
 		 * prefixes like "refs/heads/" etc. are stripped off,
 		 * so we have to look at everything:
 		 */
-		return refs_for_each_fullref_in(get_main_ref_store(the_repository),
-						"", NULL, cb, cb_data);
+		goto non_prefix_iter;
 	}
 
 	if (filter->ignore_case) {
@@ -2714,20 +2716,28 @@ static int for_each_fullref_in_pattern(struct ref_filter *filter,
 		 * so just return everything and let the caller
 		 * sort it out.
 		 */
-		return refs_for_each_fullref_in(get_main_ref_store(the_repository),
-						"", NULL, cb, cb_data);
+		goto non_prefix_iter;
 	}
 
 	if (!filter->name_patterns[0]) {
 		/* no patterns; we have to look at everything */
-		return refs_for_each_fullref_in(get_main_ref_store(the_repository),
-						 "", filter->exclude.v, cb, cb_data);
+		goto non_prefix_iter;
 	}
 
 	return refs_for_each_fullref_in_prefixes(get_main_ref_store(the_repository),
 						 NULL, filter->name_patterns,
 						 filter->exclude.v,
 						 cb, cb_data);
+
+non_prefix_iter:
+	iter = refs_ref_iterator_begin(get_main_ref_store(the_repository), "",
+				       NULL, 0, flags);
+	if (filter->seek)
+		ret = ref_iterator_seek(iter, filter->seek, 0);
+	if (ret)
+		return ret;
+
+	return do_for_each_ref_iterator(iter, cb, cb_data);
 }
 
 /*
@@ -3197,9 +3207,11 @@ static int do_filter_refs(struct ref_filter *filter, unsigned int type, each_ref
 	init_contains_cache(&filter->internal.no_contains_cache);
 
 	/*  Simple per-ref filtering */
-	if (!filter->kind)
+	if (!filter->kind) {
 		die("filter_refs: invalid type");
-	else {
+	} else {
+		const char *prefix = NULL;
+
 		/*
 		 * For common cases where we need only branches or remotes or tags,
 		 * we only iterate through those refs. If a mix of refs is needed,
@@ -3207,19 +3219,28 @@ static int do_filter_refs(struct ref_filter *filter, unsigned int type, each_ref
 		 * of filter_ref_kind().
 		 */
 		if (filter->kind == FILTER_REFS_BRANCHES)
-			ret = refs_for_each_fullref_in(get_main_ref_store(the_repository),
-						       "refs/heads/", NULL,
-						       fn, cb_data);
+			prefix = "refs/heads/";
 		else if (filter->kind == FILTER_REFS_REMOTES)
-			ret = refs_for_each_fullref_in(get_main_ref_store(the_repository),
-						       "refs/remotes/", NULL,
-						       fn, cb_data);
+			prefix = "refs/remotes/";
 		else if (filter->kind == FILTER_REFS_TAGS)
-			ret = refs_for_each_fullref_in(get_main_ref_store(the_repository),
-						       "refs/tags/", NULL, fn,
-						       cb_data);
-		else if (filter->kind & FILTER_REFS_REGULAR)
+			prefix = "refs/tags/";
+
+		if (prefix) {
+			struct ref_iterator *iter;
+
+			iter = refs_ref_iterator_begin(get_main_ref_store(the_repository),
+						       "", NULL, 0, 0);
+
+			if (filter->seek)
+				ret = ref_iterator_seek(iter, filter->seek, 0);
+			else if (prefix)
+				ret = ref_iterator_seek(iter, prefix, 1);
+
+			if (!ret)
+				ret = do_for_each_ref_iterator(iter, fn, cb_data);
+		} else if (filter->kind & FILTER_REFS_REGULAR) {
 			ret = for_each_fullref_in_pattern(filter, fn, cb_data);
+		}
 
 		/*
 		 * When printing all ref types, HEAD is already included,
diff --git a/ref-filter.h b/ref-filter.h
index c98c4fbd4c..9e97c65bc2 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -64,6 +64,7 @@ struct ref_array {
 
 struct ref_filter {
 	const char **name_patterns;
+	const char *seek;
 	struct strvec exclude;
 	struct oid_array points_at;
 	struct commit_list *with_commit;
diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh
index bb02b86c16..3f1823e95b 100755
--- a/t/t6302-for-each-ref-filter.sh
+++ b/t/t6302-for-each-ref-filter.sh
@@ -541,4 +541,192 @@ test_expect_success 'validate worktree atom' '
 	test_cmp expect actual
 '
 
+test_expect_success 'skip until with empty value' '
+	cat >expect <<-\EOF &&
+	refs/heads/main
+	refs/heads/main_worktree
+	refs/heads/side
+	refs/odd/spot
+	refs/tags/annotated-tag
+	refs/tags/doubly-annotated-tag
+	refs/tags/doubly-signed-tag
+	refs/tags/foo1.10
+	refs/tags/foo1.3
+	refs/tags/foo1.6
+	refs/tags/four
+	refs/tags/one
+	refs/tags/signed-tag
+	refs/tags/three
+	refs/tags/two
+	EOF
+	git for-each-ref --format="%(refname)" --skip-until="" >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'skip until to a specific reference' '
+	cat >expect <<-\EOF &&
+	refs/odd/spot
+	refs/tags/annotated-tag
+	refs/tags/doubly-annotated-tag
+	refs/tags/doubly-signed-tag
+	refs/tags/foo1.10
+	refs/tags/foo1.3
+	refs/tags/foo1.6
+	refs/tags/four
+	refs/tags/one
+	refs/tags/signed-tag
+	refs/tags/three
+	refs/tags/two
+	EOF
+	git for-each-ref --format="%(refname)" --skip-until=refs/odd/spot >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'skip until to a specific reference with partial match' '
+	cat >expect <<-\EOF &&
+	refs/odd/spot
+	refs/tags/annotated-tag
+	refs/tags/doubly-annotated-tag
+	refs/tags/doubly-signed-tag
+	refs/tags/foo1.10
+	refs/tags/foo1.3
+	refs/tags/foo1.6
+	refs/tags/four
+	refs/tags/one
+	refs/tags/signed-tag
+	refs/tags/three
+	refs/tags/two
+	EOF
+	git for-each-ref --format="%(refname)" --skip-until=refs/odd/sp >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'skip until just behind a specific reference' '
+	cat >expect <<-\EOF &&
+	refs/odd/spot
+	refs/tags/annotated-tag
+	refs/tags/doubly-annotated-tag
+	refs/tags/doubly-signed-tag
+	refs/tags/foo1.10
+	refs/tags/foo1.3
+	refs/tags/foo1.6
+	refs/tags/four
+	refs/tags/one
+	refs/tags/signed-tag
+	refs/tags/three
+	refs/tags/two
+	EOF
+	git for-each-ref --format="%(refname)" --skip-until=refs/odd/parrot >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'skip until to specific directory' '
+	cat >expect <<-\EOF &&
+	refs/odd/spot
+	refs/tags/annotated-tag
+	refs/tags/doubly-annotated-tag
+	refs/tags/doubly-signed-tag
+	refs/tags/foo1.10
+	refs/tags/foo1.3
+	refs/tags/foo1.6
+	refs/tags/four
+	refs/tags/one
+	refs/tags/signed-tag
+	refs/tags/three
+	refs/tags/two
+	EOF
+	git for-each-ref --format="%(refname)" --skip-until=refs/odd >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'skip until to specific directory with trailing slash' '
+	cat >expect <<-\EOF &&
+	refs/odd/spot
+	refs/tags/annotated-tag
+	refs/tags/doubly-annotated-tag
+	refs/tags/doubly-signed-tag
+	refs/tags/foo1.10
+	refs/tags/foo1.3
+	refs/tags/foo1.6
+	refs/tags/four
+	refs/tags/one
+	refs/tags/signed-tag
+	refs/tags/three
+	refs/tags/two
+	EOF
+	git for-each-ref --format="%(refname)" --skip-until=refs/lost >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'skip until just behind a specific directory' '
+	cat >expect <<-\EOF &&
+	refs/odd/spot
+	refs/tags/annotated-tag
+	refs/tags/doubly-annotated-tag
+	refs/tags/doubly-signed-tag
+	refs/tags/foo1.10
+	refs/tags/foo1.3
+	refs/tags/foo1.6
+	refs/tags/four
+	refs/tags/one
+	refs/tags/signed-tag
+	refs/tags/three
+	refs/tags/two
+	EOF
+	git for-each-ref --format="%(refname)" --skip-until=refs/odd/ >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'skip until overflow specific reference length' '
+	cat >expect <<-\EOF &&
+	refs/tags/annotated-tag
+	refs/tags/doubly-annotated-tag
+	refs/tags/doubly-signed-tag
+	refs/tags/foo1.10
+	refs/tags/foo1.3
+	refs/tags/foo1.6
+	refs/tags/four
+	refs/tags/one
+	refs/tags/signed-tag
+	refs/tags/three
+	refs/tags/two
+	EOF
+	git for-each-ref --format="%(refname)" --skip-until=refs/odd/spotnew >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'skip until overflow specific reference path' '
+	cat >expect <<-\EOF &&
+	refs/tags/annotated-tag
+	refs/tags/doubly-annotated-tag
+	refs/tags/doubly-signed-tag
+	refs/tags/foo1.10
+	refs/tags/foo1.3
+	refs/tags/foo1.6
+	refs/tags/four
+	refs/tags/one
+	refs/tags/signed-tag
+	refs/tags/three
+	refs/tags/two
+	EOF
+	git for-each-ref --format="%(refname)" --skip-until=refs/odd/spot/new >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'skip until used with a pattern' '
+	cat >expect <<-\EOF &&
+	fatal: cannot use --skip-until with patterns
+	EOF
+	test_must_fail git for-each-ref --format="%(refname)" --skip-until=refs/odd/spot refs/tags 2>actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'skip until used with custom sort order' '
+	cat >expect <<-\EOF &&
+	fatal: cannot use --skip-until custom sort options
+	EOF
+	test_must_fail git for-each-ref --format="%(refname)" --skip-until=refs/odd/spot --sort=author 2>actual &&
+	test_cmp expect actual
+'
+
 test_done

-- 
2.49.0


  parent reply	other threads:[~2025-07-04 13:02 UTC|newest]

Thread overview: 102+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-07-01 15:03 [PATCH 0/4] for-each-ref: introduce seeking functionality via '--skip-until' Karthik Nayak
2025-07-01 15:03 ` [PATCH 1/4] refs: expose `ref_iterator` via 'refs.h' Karthik Nayak
2025-07-01 15:03 ` [PATCH 2/4] ref-cache: remove unused function 'find_ref_entry()' Karthik Nayak
2025-07-14 15:46   ` Junio C Hamano
2025-07-01 15:03 ` [PATCH 3/4] refs: selectively set prefix in the seek functions Karthik Nayak
2025-07-03  5:55   ` Patrick Steinhardt
2025-07-03  9:40     ` Karthik Nayak
2025-07-01 15:03 ` [PATCH 4/4] for-each-ref: introduce a '--skip-until' option Karthik Nayak
2025-07-03  5:55   ` Patrick Steinhardt
2025-07-03 10:02     ` Karthik Nayak
2025-07-03 10:59       ` Patrick Steinhardt
2025-07-01 17:08 ` [PATCH 0/4] for-each-ref: introduce seeking functionality via '--skip-until' Junio C Hamano
2025-07-02 16:45   ` Karthik Nayak
2025-07-01 21:37 ` Junio C Hamano
2025-07-02 18:19   ` Karthik Nayak
2025-07-03  8:41     ` Karthik Nayak
2025-07-02 14:14 ` Phillip Wood
2025-07-02 20:33   ` Karthik Nayak
2025-07-03  5:18     ` Patrick Steinhardt
2025-07-03  5:56       ` Junio C Hamano
2025-07-03  8:19         ` Patrick Steinhardt
2025-07-03  8:48           ` Karthik Nayak
2025-07-04 13:02 ` [PATCH v2 " Karthik Nayak
2025-07-04 13:02   ` [PATCH v2 1/4] refs: expose `ref_iterator` via 'refs.h' Karthik Nayak
2025-07-04 13:02   ` [PATCH v2 2/4] ref-cache: remove unused function 'find_ref_entry()' Karthik Nayak
2025-07-04 13:02   ` [PATCH v2 3/4] refs: selectively set prefix in the seek functions Karthik Nayak
2025-07-04 13:02   ` Karthik Nayak [this message]
2025-07-07 15:30     ` [PATCH v2 4/4] for-each-ref: introduce a '--skip-until' option Junio C Hamano
2025-07-07 18:31       ` Karthik Nayak
2025-07-04 13:41   ` [PATCH v2 0/4] for-each-ref: introduce seeking functionality via '--skip-until' Andreas Schwab
2025-07-04 14:02     ` Karthik Nayak
2025-07-04 14:52       ` Andreas Schwab
2025-07-04 14:58         ` Karthik Nayak
2025-07-04 15:55           ` Andreas Schwab
2025-07-07  8:52             ` Karthik Nayak
2025-07-04 16:39       ` Junio C Hamano
2025-07-07  8:59         ` Karthik Nayak
2025-07-07  9:45           ` Phillip Wood
2025-07-08 11:39             ` Karthik Nayak
2025-07-08 13:47 ` [PATCH v3 0/4] for-each-ref: introduce seeking functionality via '--start-after' Karthik Nayak
2025-07-08 13:47   ` [PATCH v3 1/4] refs: expose `ref_iterator` via 'refs.h' Karthik Nayak
2025-07-08 13:47   ` [PATCH v3 2/4] ref-cache: remove unused function 'find_ref_entry()' Karthik Nayak
2025-07-08 13:47   ` [PATCH v3 3/4] refs: selectively set prefix in the seek functions Karthik Nayak
2025-07-10  6:44     ` Patrick Steinhardt
2025-07-11  9:44       ` Karthik Nayak
2025-07-14 16:09       ` Junio C Hamano
2025-07-15  9:49         ` Karthik Nayak
2025-07-15 16:35           ` Junio C Hamano
2025-07-16 14:40             ` Karthik Nayak
2025-07-16 15:39               ` Junio C Hamano
2025-07-16 20:02               ` Junio C Hamano
2025-07-17  9:01                 ` Karthik Nayak
2025-07-17 17:31                   ` Junio C Hamano
2025-07-08 13:47   ` [PATCH v3 4/4] for-each-ref: introduce a '--start-after' option Karthik Nayak
2025-07-08 20:25     ` Junio C Hamano
2025-07-09  9:53       ` Karthik Nayak
2025-07-11 16:18 ` [PATCH v4 0/4] for-each-ref: introduce seeking functionality via '--start-after' Karthik Nayak
2025-07-11 16:18   ` [PATCH v4 1/4] refs: expose `ref_iterator` via 'refs.h' Karthik Nayak
2025-07-11 16:18   ` [PATCH v4 2/4] ref-cache: remove unused function 'find_ref_entry()' Karthik Nayak
2025-07-11 16:18   ` [PATCH v4 3/4] refs: selectively set prefix in the seek functions Karthik Nayak
2025-07-14 10:34     ` Christian Couder
2025-07-15  8:19       ` Karthik Nayak
2025-07-11 16:18   ` [PATCH v4 4/4] for-each-ref: introduce a '--start-after' option Karthik Nayak
2025-07-14 16:04     ` Christian Couder
2025-07-14 16:42       ` Junio C Hamano
2025-07-15  8:42       ` Karthik Nayak
2025-07-14 16:34   ` [PATCH v4 0/4] for-each-ref: introduce seeking functionality via '--start-after' Christian Couder
2025-07-14 16:49     ` Junio C Hamano
2025-07-15  9:49       ` Karthik Nayak
2025-07-15 11:28 ` [PATCH v5 0/5] " Karthik Nayak
2025-07-15 11:28   ` [PATCH v5 1/5] refs: expose `ref_iterator` via 'refs.h' Karthik Nayak
2025-07-15 11:28   ` [PATCH v5 2/5] ref-cache: remove unused function 'find_ref_entry()' Karthik Nayak
2025-07-17 14:48     ` Junio C Hamano
2025-07-17 19:31       ` Karthik Nayak
2025-07-17 20:32         ` Junio C Hamano
2025-07-15 11:28   ` [PATCH v5 3/5] refs: selectively set prefix in the seek functions Karthik Nayak
2025-07-17  2:09     ` Jeff King
2025-07-17 19:49       ` Karthik Nayak
2025-07-17 21:55         ` Jeff King
2025-07-15 11:28   ` [PATCH v5 4/5] ref-filter: remove unnecessary else clause Karthik Nayak
2025-07-15 11:28   ` [PATCH v5 5/5] for-each-ref: introduce a '--start-after' option Karthik Nayak
2025-07-17 15:31     ` Junio C Hamano
2025-07-22  8:07       ` Karthik Nayak
2025-07-15 19:00   ` [PATCH v5 0/5] for-each-ref: introduce seeking functionality via '--start-after' Junio C Hamano
2025-07-17  1:19     ` Kyle Lippincott
2025-07-17  1:54       ` Jeff King
2025-07-17 17:08         ` Kyle Lippincott
2025-07-17 19:26           ` Karthik Nayak
2025-07-17 19:35             ` Kyle Lippincott
2025-07-17 22:09               ` Jeff King
2025-07-17 22:16                 ` Jeff King
2025-07-21 14:27                 ` Karthik Nayak
2025-07-21 21:22                   ` Jeff King
2025-07-22  8:44                     ` Karthik Nayak
2025-07-17 22:21             ` Junio C Hamano
2025-07-23 21:51   ` [PATCH] ref-iterator-seek: correctly initialize the prefix_state for a new level Junio C Hamano
2025-07-23 21:57     ` Kyle Lippincott
2025-07-23 23:52     ` Jeff King
2025-07-24  8:12     ` Karthik Nayak
2025-07-24 17:01       ` Junio C Hamano
2025-07-24 22:11         ` [PATCH] ref-cache: set prefix_state when seeking Karthik Nayak
2025-07-24 22:30           ` Junio C Hamano

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250704-306-git-for-each-ref-pagination-v2-4-bcde14acdd81@gmail.com \
    --to=karthik.188@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    --cc=ps@pks.im \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).