* [GSoC][RFC PATCH 0/2] Add refs list subcommand
@ 2025-06-14 7:05 Meet Soni
2025-06-14 7:05 ` [GSoC][RFC PATCH 1/2] builtin/refs: add " Meet Soni
` (2 more replies)
0 siblings, 3 replies; 5+ messages in thread
From: Meet Soni @ 2025-06-14 7:05 UTC (permalink / raw)
To: git; +Cc: Meet Soni
This patch series introduces the git refs list subcommand, as part of a
longer-term goal to consolidate and modernize ref listing functionality
currently split between git-show-ref(1) and git-for-each-ref(1).
The initial implementation focuses on mirroring the behavior of
git-show-ref, providing support for filtering by --branches, --tags, and
--head, and implementing pattern matching similar to the legacy command.
This ensures backward compatibility.
That said, git-for-each-ref(1) offers more flexible pattern matching and
we acknowledge that its style may be a better fit in the long run. As
such, this RFC deliberately starts with the show-ref matching semantics
to solicit feedback on whether to switch to for-each-ref style matching
as the default, with a compatibility flag to preserve legacy behavior.
It's also worth highlighting that several options from git-show-ref are
intended to be supported in the git refs list subcommand. These include
flags such as '--abbrev', '--quiet', '--dereference', '--hash', and
'--exclude-existing'. While this series focuses on core functionality
and pattern matching, these additional options are within scope for
future patches.
Additionally, the git-for-each-ref(1) command offers a rich set of
features that would be valuable to incorporate into git refs list. At
this point, all of its existing options appear to provide meaningful
functionality, and my current thinking is to support them incrementally
as part of expanding this subcommand. I'd appreciate feedback on whether
there are any options that should be reconsidered or excluded in this
consolidation effort.
This RFC is meant to start a broader discussion on:
- The desired default behavior of pattern matching in git refs list
- Which features from both git-show-ref and git-for-each-ref should be
preserved, rethought, or dropped
- How much backward compatibility we want to offer, and through what
interface (e.g., compatibility flags)
Feedback and thoughts on these topics would be very welcome.
Meet Soni (2):
builtin/refs: add list subcommand
t: add tests for refs list subcommand
Documentation/git-refs.adoc | 25 ++++++++
builtin/refs.c | 110 ++++++++++++++++++++++++++++++++++++
t/meson.build | 1 +
t/t1461-refs-list.sh | 95 +++++++++++++++++++++++++++++++
4 files changed, 231 insertions(+)
create mode 100755 t/t1461-refs-list.sh
--
2.34.1
^ permalink raw reply [flat|nested] 5+ messages in thread
* [GSoC][RFC PATCH 1/2] builtin/refs: add list subcommand
2025-06-14 7:05 [GSoC][RFC PATCH 0/2] Add refs list subcommand Meet Soni
@ 2025-06-14 7:05 ` Meet Soni
2025-06-14 7:05 ` [GSoC][RFC PATCH 2/2] t: add tests for refs " Meet Soni
2025-06-14 23:45 ` [GSoC][RFC PATCH 0/2] Add " Junio C Hamano
2 siblings, 0 replies; 5+ messages in thread
From: Meet Soni @ 2025-06-14 7:05 UTC (permalink / raw)
To: git
Cc: Meet Soni, Patrick Steinhardt, shejialuo, Karthik Nayak,
Junio C Hamano, John Cai
Git's reference management is distributed across multiple
commands and as part of an ongoing effort to streamline and modernize
reference handling, we are beginning to consolidate these operations
into a cohesive `git refs` command.
Add a `list` subcommand to `git refs` as a modern replacement for
`git show-ref`, consolidating ref listing functionality under the
unified `git refs` command.
The initial implementation supports the following options from
`git show-ref`:
- --head
- --tags
- --branches
- patterns argument
For large changes, this patch limits itself to the basic ref listing and
commonly used flags. Remaining options will be added incrementally in
follow-up patches, guided by feedback from the mailing list.
Mentored-by: Patrick Steinhardt <ps@pks.im>
Mentored-by: shejialuo <shejialuo@gmail.com>
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Signed-off-by: Meet Soni <meetsoni3017@gmail.com>
---
Documentation/git-refs.adoc | 25 ++++++++
builtin/refs.c | 110 ++++++++++++++++++++++++++++++++++++
2 files changed, 135 insertions(+)
diff --git a/Documentation/git-refs.adoc b/Documentation/git-refs.adoc
index 4d6dc994f9..397c3ceb01 100644
--- a/Documentation/git-refs.adoc
+++ b/Documentation/git-refs.adoc
@@ -11,6 +11,7 @@ SYNOPSIS
[synopsis]
git refs migrate --ref-format=<format> [--no-reflog] [--dry-run]
git refs verify [--strict] [--verbose]
+git refs list [--head] [--branches] [--tag] [--] [<pattern>...]
DESCRIPTION
-----------
@@ -26,6 +27,12 @@ migrate::
verify::
Verify reference database consistency.
+list::
+ Displays references available in a local repository along with the associated
+ commit IDs. Results can be filtered using a pattern.
+
+ By default, shows the tags, heads, and remote refs.
+
OPTIONS
-------
@@ -57,6 +64,24 @@ The following options are specific to 'git refs verify':
--verbose::
When verifying the reference database consistency, be chatty.
+The following options are specific to 'git refs list':
+
+--head::
+ Show the HEAD reference, even if it would normally be filtered out.
+
+--branches::
+--tags::
+ Limit to local branches and local tags, respectively. These options
+ are not mutually exclusive; when given both, references stored in
+ "refs/heads" and "refs/tags" are displayed.
+
+<pattern>...::
+ Show references matching one or more patterns. Patterns are matched from
+ the end of the full name, and only complete parts are matched, e.g.
+ 'master' matches 'refs/heads/master', 'refs/remotes/origin/master',
+ 'refs/tags/jedi/master' but not 'refs/heads/mymaster' or
+ 'refs/remotes/master/jedi'.
+
KNOWN LIMITATIONS
-----------------
diff --git a/builtin/refs.c b/builtin/refs.c
index 998d2a2c1c..c098132191 100644
--- a/builtin/refs.c
+++ b/builtin/refs.c
@@ -2,6 +2,9 @@
#include "builtin.h"
#include "config.h"
#include "fsck.h"
+#include "hex.h"
+#include "object-name.h"
+#include "object-store.h"
#include "parse-options.h"
#include "refs.h"
#include "strbuf.h"
@@ -13,6 +16,9 @@
#define REFS_VERIFY_USAGE \
N_("git refs verify [--strict] [--verbose]")
+#define REFS_LIST_USAGE \
+ N_("git refs list [--head] [--branches] [--tag] [--] [<pattern>...]")
+
static int cmd_refs_migrate(int argc, const char **argv, const char *prefix,
struct repository *repo UNUSED)
{
@@ -101,6 +107,108 @@ static int cmd_refs_verify(int argc, const char **argv, const char *prefix,
return ret;
}
+struct list_options {
+ unsigned int show_head;
+ unsigned int filter_branches;
+ unsigned int filter_tags;
+ unsigned int found_match;
+ const char **patterns;
+};
+
+static void print_ref(const char *refname, const struct object_id *oid)
+{
+ const char *hex;
+
+ hex = oid_to_hex(oid);
+ if (!has_object(the_repository, oid,
+ HAS_OBJECT_RECHECK_PACKED | HAS_OBJECT_FETCH_PROMISOR))
+ die("git refs list: bad ref %s (%s)", refname,
+ hex);
+
+ printf("%s %s\n", hex, refname);
+}
+
+static int list_ref(const char *refname, const char *referent UNUSED,
+ const struct object_id *oid, int flag UNUSED, void *cbdata)
+{
+ struct list_options *data = cbdata;
+
+ if (data->show_head && !strcmp(refname, "HEAD"))
+ goto match;
+
+ if (data->patterns) {
+ int reflen = strlen(refname);
+ const char **pattern_ptr = data->patterns, *pattern;
+ while ((pattern = *pattern_ptr++) != NULL) {
+ int pattern_len = strlen(pattern);
+ if (pattern_len > reflen)
+ continue;
+ if (memcmp(pattern, refname + reflen - pattern_len, pattern_len))
+ continue;
+ if (pattern_len == reflen)
+ goto match;
+ if (refname[reflen - pattern_len - 1] == '/')
+ goto match;
+ }
+ return 0;
+ }
+
+match:
+ data->found_match++;
+
+ print_ref(refname, oid);
+
+ return 0;
+}
+
+static int cmd_refs_list(int argc, const char **argv, const char *prefix,
+ struct repository *repo UNUSED)
+{
+ struct list_options list_opts = {0};
+ const char * const list_usage[] = {
+ REFS_LIST_USAGE,
+ NULL,
+ };
+ struct option options[] = {
+ OPT_BOOL(0, "head", &list_opts.show_head,
+ N_("show the HEAD reference, even if it would be filtered out")),
+ OPT_BOOL(0, "tags", &list_opts.filter_tags,
+ N_("only show tags (can be combined with --branches)")),
+ OPT_BOOL(0, "branches", &list_opts.filter_branches,
+ N_("only show branches (can be combined with --tags)")),
+ OPT_END(),
+ };
+
+ argc = parse_options(argc, argv, prefix, options, list_usage, 0);
+
+ if (argv && *argv)
+ list_opts.patterns = argv;
+
+ if (list_opts.show_head)
+ refs_head_ref(get_main_ref_store(the_repository), list_ref,
+ &list_opts);
+
+ if (list_opts.filter_tags || list_opts.filter_branches) {
+ if (list_opts.filter_branches)
+ refs_for_each_fullref_in(get_main_ref_store(the_repository),
+ "refs/heads/", NULL,
+ list_ref, &list_opts);
+
+ if (list_opts.filter_tags)
+ refs_for_each_fullref_in(get_main_ref_store(the_repository),
+ "refs/tags/", NULL,
+ list_ref, &list_opts);
+ } else {
+ refs_for_each_ref(get_main_ref_store(the_repository),
+ list_ref, &list_opts);
+ }
+
+ if (!list_opts.found_match)
+ return 1;
+
+ return 0;
+}
+
int cmd_refs(int argc,
const char **argv,
const char *prefix,
@@ -109,12 +217,14 @@ int cmd_refs(int argc,
const char * const refs_usage[] = {
REFS_MIGRATE_USAGE,
REFS_VERIFY_USAGE,
+ REFS_LIST_USAGE,
NULL,
};
parse_opt_subcommand_fn *fn = NULL;
struct option opts[] = {
OPT_SUBCOMMAND("migrate", &fn, cmd_refs_migrate),
OPT_SUBCOMMAND("verify", &fn, cmd_refs_verify),
+ OPT_SUBCOMMAND("list", &fn, cmd_refs_list),
OPT_END(),
};
--
2.34.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [GSoC][RFC PATCH 2/2] t: add tests for refs list subcommand
2025-06-14 7:05 [GSoC][RFC PATCH 0/2] Add refs list subcommand Meet Soni
2025-06-14 7:05 ` [GSoC][RFC PATCH 1/2] builtin/refs: add " Meet Soni
@ 2025-06-14 7:05 ` Meet Soni
2025-06-14 23:45 ` [GSoC][RFC PATCH 0/2] Add " Junio C Hamano
2 siblings, 0 replies; 5+ messages in thread
From: Meet Soni @ 2025-06-14 7:05 UTC (permalink / raw)
To: git; +Cc: Meet Soni, Patrick Steinhardt, shejialuo, Karthik Nayak,
Junio C Hamano
Test the implemented functionality of `git refs list` and verify
backward compatibility with `git show-ref` for the supported flags
and patterns.
Mentored-by: Patrick Steinhardt <ps@pks.im>
Mentored-by: shejialuo <shejialuo@gmail.com>
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Signed-off-by: Meet Soni <meetsoni3017@gmail.com>
---
t/meson.build | 1 +
t/t1461-refs-list.sh | 95 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 96 insertions(+)
create mode 100755 t/t1461-refs-list.sh
diff --git a/t/meson.build b/t/meson.build
index d052fc3e23..c9d0863490 100644
--- a/t/meson.build
+++ b/t/meson.build
@@ -224,6 +224,7 @@ integration_tests = [
't1450-fsck.sh',
't1451-fsck-buffer.sh',
't1460-refs-migrate.sh',
+ 't1461-refs-list.sh',
't1500-rev-parse.sh',
't1501-work-tree.sh',
't1502-rev-parse-parseopt.sh',
diff --git a/t/t1461-refs-list.sh b/t/t1461-refs-list.sh
new file mode 100755
index 0000000000..d628a193fc
--- /dev/null
+++ b/t/t1461-refs-list.sh
@@ -0,0 +1,95 @@
+#!/bin/sh
+
+test_description='Verify git refs list functionality and compatibility with git show-ref'
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+
+. ./test-lib.sh
+
+test_expect_success setup '
+ test_commit --annotate A &&
+ git checkout -b side &&
+ test_commit --annotate B &&
+ git checkout main &&
+ test_commit C &&
+ git branch B A^0
+'
+
+test_expect_success 'refs list --branches, --tags, --head, pattern' '
+ for branch in B main side
+ do
+ echo $(git rev-parse refs/heads/$branch) refs/heads/$branch || return 1
+ done >expect.branches &&
+ git refs list --branches >actual &&
+ test_cmp expect.branches actual &&
+
+ for tag in A B C
+ do
+ echo $(git rev-parse refs/tags/$tag) refs/tags/$tag || return 1
+ done >expect.tags &&
+ git refs list --tags >actual &&
+ test_cmp expect.tags actual &&
+
+ cat expect.branches expect.tags >expect &&
+ git refs list --branches --tags >actual &&
+ test_cmp expect actual &&
+
+ {
+ echo $(git rev-parse HEAD) HEAD &&
+ cat expect.branches expect.tags
+ } >expect &&
+ git refs list --branches --tags --head >actual &&
+ test_cmp expect actual &&
+
+ {
+ echo $(git rev-parse HEAD) HEAD &&
+ echo $(git rev-parse refs/heads/B) refs/heads/B &&
+ echo $(git rev-parse refs/tags/B) refs/tags/B
+ } >expect &&
+ git refs list --head B >actual &&
+ test_cmp expect actual &&
+
+ {
+ echo $(git rev-parse refs/heads/B) refs/heads/B &&
+ echo $(git rev-parse refs/tags/A) refs/tags/A &&
+ echo $(git rev-parse refs/tags/B) refs/tags/B
+ } >expect &&
+ git refs list A B >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'Backward compatibility with show-ref' '
+ git show-ref >expect&&
+ git refs list >actual&&
+ test_cmp expect actual &&
+
+ git show-ref --branches >expect &&
+ git refs list --branches >actual &&
+ test_cmp expect actual &&
+
+ git show-ref --tags >expect &&
+ git refs list --tags >actual &&
+ test_cmp expect actual &&
+
+ git show-ref --head >expect &&
+ git refs list --head >actual &&
+ test_cmp expect actual &&
+
+ git show-ref --branches --tags --head >expect &&
+ git refs list --branches --tags --head >actual &&
+ test_cmp expect actual &&
+
+ git show-ref B >expect &&
+ git refs list B >actual &&
+ test_cmp expect actual &&
+
+ git show-ref --head B >expect &&
+ git refs list --head B >actual &&
+ test_cmp expect actual &&
+
+ git show-ref A B >expect &&
+ git refs list A B >actual &&
+ test_cmp expect actual
+'
+
+test_done
--
2.34.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [GSoC][RFC PATCH 0/2] Add refs list subcommand
2025-06-14 7:05 [GSoC][RFC PATCH 0/2] Add refs list subcommand Meet Soni
2025-06-14 7:05 ` [GSoC][RFC PATCH 1/2] builtin/refs: add " Meet Soni
2025-06-14 7:05 ` [GSoC][RFC PATCH 2/2] t: add tests for refs " Meet Soni
@ 2025-06-14 23:45 ` Junio C Hamano
2025-06-17 11:51 ` Meet Soni
2 siblings, 1 reply; 5+ messages in thread
From: Junio C Hamano @ 2025-06-14 23:45 UTC (permalink / raw)
To: Meet Soni; +Cc: git
Meet Soni <meetsoni3017@gmail.com> writes:
> This RFC is meant to start a broader discussion on:
>
> - The desired default behavior of pattern matching in git refs list
>
> - Which features from both git-show-ref and git-for-each-ref should be
> preserved, rethought, or dropped
>
> - How much backward compatibility we want to offer, and through what
> interface (e.g., compatibility flags)
>
> Feedback and thoughts on these topics would be very welcome.
In addition to these three points, 0th point perhaps is "Is it
desirable to unify these two commands in the first place?"
I only use "show-ref" when I care about a single ref in a script,
expecting to be able to switch on its exit status. Everything else
I'd use for-each-ref.
But then that particular unique advantage of show-ref over for-each-ref
can be done with "rev-parse --verify".
So, I'd rather not to see yet another command to do the same thing.
Rather, is it insufficient to just use for-each-ref or rev-parse,
let the sleeping show-ref alone, and be happy?
> Meet Soni (2):
> builtin/refs: add list subcommand
> t: add tests for refs list subcommand
>
> Documentation/git-refs.adoc | 25 ++++++++
> builtin/refs.c | 110 ++++++++++++++++++++++++++++++++++++
> t/meson.build | 1 +
> t/t1461-refs-list.sh | 95 +++++++++++++++++++++++++++++++
> 4 files changed, 231 insertions(+)
> create mode 100755 t/t1461-refs-list.sh
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [GSoC][RFC PATCH 0/2] Add refs list subcommand
2025-06-14 23:45 ` [GSoC][RFC PATCH 0/2] Add " Junio C Hamano
@ 2025-06-17 11:51 ` Meet Soni
0 siblings, 0 replies; 5+ messages in thread
From: Meet Soni @ 2025-06-17 11:51 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
On Sun, 15 Jun 2025 at 05:15, Junio C Hamano <gitster@pobox.com> wrote:
>
> Meet Soni <meetsoni3017@gmail.com> writes:
>
> > This RFC is meant to start a broader discussion on:
> >
> > - The desired default behavior of pattern matching in git refs list
> >
> > - Which features from both git-show-ref and git-for-each-ref should be
> > preserved, rethought, or dropped
> >
> > - How much backward compatibility we want to offer, and through what
> > interface (e.g., compatibility flags)
> >
> > Feedback and thoughts on these topics would be very welcome.
>
> In addition to these three points, 0th point perhaps is "Is it
> desirable to unify these two commands in the first place?"
>
> I only use "show-ref" when I care about a single ref in a script,
> expecting to be able to switch on its exit status. Everything else
> I'd use for-each-ref.
>
> But then that particular unique advantage of show-ref over for-each-ref
> can be done with "rev-parse --verify".
>
> So, I'd rather not to see yet another command to do the same thing.
> Rather, is it insufficient to just use for-each-ref or rev-parse,
> let the sleeping show-ref alone, and be happy?
The broader motivation behind this effort (and the overarching GSoC project)
has been to reduce fragmentation in ref-related functionality by gradually
consolidating it under the git refs umbrella, aiming for consistency and
discoverability.
Your point about rev-parse --verify covering show-ref's main utility is well
taken. If that truly makes show-ref redundant, then perhaps it makes more sense
to focus consolidation efforts around for-each-ref instead.
One concern I have is that if we simply replicate for-each-ref under a new
name, we may still face the same question: what does this new command add that
the old one doesn't already handle?
I'd love to hear thoughts on what a modernized or simplified ref-listing
interface could look like. Are there features or changes worth exploring that
could justify the consolidation?
Thanks,
Meet
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2025-06-17 11:51 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-06-14 7:05 [GSoC][RFC PATCH 0/2] Add refs list subcommand Meet Soni
2025-06-14 7:05 ` [GSoC][RFC PATCH 1/2] builtin/refs: add " Meet Soni
2025-06-14 7:05 ` [GSoC][RFC PATCH 2/2] t: add tests for refs " Meet Soni
2025-06-14 23:45 ` [GSoC][RFC PATCH 0/2] Add " Junio C Hamano
2025-06-17 11:51 ` Meet Soni
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).