* [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; 9+ 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] 9+ 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; 9+ 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] 9+ 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; 9+ 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] 9+ 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; 9+ 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] 9+ 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; 9+ 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] 9+ messages in thread
* [GSoC][RFC PATCH 0/2] Add refs list subcommand
@ 2025-06-27 7:49 Meet Soni
2025-06-27 7:49 ` [GSoC][RFC PATCH 1/2] builtin/refs: add " Meet Soni
0 siblings, 1 reply; 9+ messages in thread
From: Meet Soni @ 2025-06-27 7:49 UTC (permalink / raw)
To: git; +Cc: ps, shejialuo, karthik.188, Meet Soni
This patch series introduces `git refs list` as a modern replacement for
`git for-each-ref`, as part of an effort to consolidate ref-related
functionality under a unified `git refs` command.
Git's ref-related operations are currently handled by several distinct
commands, such as `git show-ref`, `git for-each-ref`, `git update-ref`,
`git pack-refs`, etc. This distribution has a few practical drawbacks:
- Users need to rely on multiple commands for related tasks involving
refs.
- The commands may differ slightly in behavior and option syntax,
leading to inconsistency.
We propose a long-term consolidation effort to bring ref-related
subcommands under the umbrella of a single command: `git refs`.
The implementation of `git refs list` is functionally identical to `git
for-each-ref`. It reuses the same internal logic (cmd_for_each_ref) to
ensure complete backward compatibility. The purpose of this patch is not
to introduce new behavior but to provide an alternate entry point under
the consolidated `git refs` namespace.
The motivation behind this change is twofold:
- Consolidation: Centralizing ref-related operations makes them easier
to discover, use, and maintain.
- Evolution: While the initial goal is parity with existing commands,
this consolidation allows for careful reconsideration of which
features are essential. Over time, we can:
- Remove legacy or obscure options that are no longer needed.
- Add improvements that wouldn't make sense to bolt onto legacy
commands.
- Offering a more consistent and user-friendly surface.
To verify backward compatibility, this patch also includes a test
`t/t1461-refs-list.sh`, which runs the full `t6300-for-each-ref.sh` test
using `git refs list`. The test uses ${GIT_REFS_LIST_CMD:-for-each-ref}
to allow substitution without duplicating tests.
This patch is deliberately conservative: it introduces no behavioral
changes and leaves `for-each-ref` untouched. The goal is to lay
groundwork and demonstrate viability of ref consolidation within `git
refs`.
Going forward, I'd like to initiate a discussion on what the ideal
surface of `git refs list` should look like. Which options and features
from `for-each-ref` should be carried over? Are there any that are
obsolete or overly niche? What improvements might be worth considering
now that we have a new, consolidated interface?
Feedback on this, especially from those who rely on `for-each-ref` in
scripts or tooling would be very helpful.
Meet Soni (2):
builtin/refs: add list subcommand
t: add test for git refs list subcommand
Documentation/git-refs.adoc | 95 ++++++++++
builtin/refs.c | 110 ++++++++++++
t/meson.build | 1 +
t/t1461-refs-list.sh | 8 +
t/t6300-for-each-ref.sh | 333 ++++++++++++++++++------------------
5 files changed, 384 insertions(+), 163 deletions(-)
create mode 100755 t/t1461-refs-list.sh
base-commit: cb3b40381e1d5ee32dde96521ad7cfd68eb308a6
--
2.34.1
^ permalink raw reply [flat|nested] 9+ messages in thread* [GSoC][RFC PATCH 1/2] builtin/refs: add list subcommand 2025-06-27 7:49 Meet Soni @ 2025-06-27 7:49 ` Meet Soni 2025-06-27 16:27 ` Jean-Noël Avila 0 siblings, 1 reply; 9+ messages in thread From: Meet Soni @ 2025-06-27 7:49 UTC (permalink / raw) To: git; +Cc: ps, shejialuo, karthik.188, Meet Soni, Junio C Hamano, John Cai Git's reference management is distributed across multiple commands. As part of an ongoing effort to consolidate and modernize reference handling, introduce a `list` subcommand under the `git refs` umbrella as a replacement for `git for-each-ref`. For now, cmd_refs_list is effectively a copy of cmd_for_each_ref, allowing us to reuse the existing filtering and formatting logic while avoiding any backward compatibility issues. The core implementation continues to reside in shared modules. This duplication is temporary and intentional: future enhancements will be added exclusively to `git refs list`, providing a gradual path forward without disrupting existing workflows. 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 | 95 +++++++++++++++++++++++++++++++ builtin/refs.c | 110 ++++++++++++++++++++++++++++++++++++ 2 files changed, 205 insertions(+) diff --git a/Documentation/git-refs.adoc b/Documentation/git-refs.adoc index 4d6dc994f9..d8f81eaabd 100644 --- a/Documentation/git-refs.adoc +++ b/Documentation/git-refs.adoc @@ -11,6 +11,13 @@ SYNOPSIS [synopsis] git refs migrate --ref-format=<format> [--no-reflog] [--dry-run] git refs verify [--strict] [--verbose] +git refs list [--count=<count>] [--shell|--perl|--python|--tcl] + [(--sort=<key>)...] [--format=<format>] + [--include-root-refs] [ --stdin | <pattern>... ] + [--points-at=<object>] + [--merged[=<object>]] [--no-merged[=<object>]] + [--contains[=<object>]] [--no-contains[=<object>]] + [--exclude=<pattern> ...] DESCRIPTION ----------- @@ -26,6 +33,11 @@ migrate:: verify:: Verify reference database consistency. +list:: + List references in the repository with support for filtering, formatting, + and sorting. This subcommand uses the same core logic as + linkgit:git-for-each-ref[1] and offers equivalent functionality. + OPTIONS ------- @@ -57,6 +69,89 @@ 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': + +<pattern>...:: + If one or more patterns are given, only refs are shown that + match against at least one pattern, either using fnmatch(3) or + literally, in the latter case matching completely or from the + beginning up to a slash. + +--stdin:: + If `--stdin` is supplied, then the list of patterns is read from + standard input instead of from the argument list. + +--count=<count>:: + By default the command shows all refs that match + `<pattern>`. This option makes it stop after showing + that many refs. + +--sort=<key>:: + A field name to sort on. Prefix `-` to sort in + descending order of the value. When unspecified, + `refname` is used. You may use the --sort=<key> option + multiple times, in which case the last key becomes the primary + key. + +--format=<format>:: + A string that interpolates `%(fieldname)` from a ref being shown and + the object it points at. In addition, the string literal `%%` + renders as `%` and `%xx` - where `xx` are hex digits - renders as + the character with hex code `xx`. For example, `%00` interpolates to + `\0` (NUL), `%09` to `\t` (TAB), and `%0a` to `\n` (LF). ++ +When unspecified, `<format>` defaults to `%(objectname) SPC %(objecttype) +TAB %(refname)`. + +--color[=<when>]:: + Respect any colors specified in the `--format` option. The + `<when>` field must be one of `always`, `never`, or `auto` (if + `<when>` is absent, behave as if `always` was given). + +--shell:: +--perl:: +--python:: +--tcl:: + If given, strings that substitute `%(fieldname)` + placeholders are quoted as string literals suitable for + the specified host language. This is meant to produce + a scriptlet that can directly be `eval`ed. + +--points-at=<object>:: + Only list refs which points at the given object. + +--merged[=<object>]:: + Only list refs whose tips are reachable from the + specified commit (HEAD if not specified). + +--no-merged[=<object>]:: + Only list refs whose tips are not reachable from the + specified commit (HEAD if not specified). + +--contains[=<object>]:: + Only list refs which contain the specified commit (HEAD if not + specified). + +--no-contains[=<object>]:: + Only list refs which don't contain the specified commit (HEAD + if not specified). + +--ignore-case:: + Sorting and filtering refs are case insensitive. + +--omit-empty:: + Do not print a newline after formatted refs where the format expands + to the empty string. + +--exclude=<pattern>:: + If one or more patterns are given, only refs which do not match + any excluded pattern(s) are shown. Matching is done using the + same rules as `<pattern>` above. + +--include-root-refs:: + List root refs (HEAD and pseudorefs) apart from regular refs. + + KNOWN LIMITATIONS ----------------- diff --git a/builtin/refs.c b/builtin/refs.c index 998d2a2c1c..70e1757791 100644 --- a/builtin/refs.c +++ b/builtin/refs.c @@ -3,6 +3,7 @@ #include "config.h" #include "fsck.h" #include "parse-options.h" +#include "ref-filter.h" #include "refs.h" #include "strbuf.h" #include "worktree.h" @@ -13,6 +14,15 @@ #define REFS_VERIFY_USAGE \ N_("git refs verify [--strict] [--verbose]") +#define REFS_LIST_USAGE \ + N_("git refs list [--count=<count>] [--shell|--perl|--python|--tcl]\n" \ + " [(--sort=<key>)...] [--format=<format>]\n" \ + " [--include-root-refs] [ --stdin | <pattern>... ]\n" \ + " [--points-at=<object>]\n" \ + " [--merged[=<object>]] [--no-merged[=<object>]]\n" \ + " [--contains[=<object>]] [--no-contains[=<object>]]\n" \ + " [--exclude=<pattern> ...]") + static int cmd_refs_migrate(int argc, const char **argv, const char *prefix, struct repository *repo UNUSED) { @@ -101,6 +111,104 @@ static int cmd_refs_verify(int argc, const char **argv, const char *prefix, return ret; } +static int cmd_refs_list(int argc, const char **argv, const char *prefix, + struct repository *repo) +{ + struct ref_sorting *sorting; + struct string_list sorting_options = STRING_LIST_INIT_DUP; + int icase = 0, include_root_refs = 0, from_stdin = 0; + struct ref_filter filter = REF_FILTER_INIT; + struct ref_format format = REF_FORMAT_INIT; + unsigned int flags = FILTER_REFS_REGULAR; + struct strvec vec = STRVEC_INIT; + const char * const list_usage[] = { + REFS_LIST_USAGE, + NULL + }; + + struct option opts[] = { + OPT_BIT('s', "shell", &format.quote_style, + N_("quote placeholders suitably for shells"), QUOTE_SHELL), + OPT_BIT('p', "perl", &format.quote_style, + N_("quote placeholders suitably for perl"), QUOTE_PERL), + OPT_BIT(0 , "python", &format.quote_style, + N_("quote placeholders suitably for python"), QUOTE_PYTHON), + OPT_BIT(0 , "tcl", &format.quote_style, + N_("quote placeholders suitably for Tcl"), QUOTE_TCL), + OPT_BOOL(0, "omit-empty", &format.array_opts.omit_empty, + N_("do not output a newline after empty formatted refs")), + + 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__COLOR(&format.use_color, N_("respect format colors")), + OPT_REF_FILTER_EXCLUDE(&filter), + OPT_REF_SORT(&sorting_options), + OPT_CALLBACK(0, "points-at", &filter.points_at, + N_("object"), N_("print only refs which points at the given object"), + parse_opt_object_name), + OPT_MERGED(&filter, N_("print only refs that are merged")), + OPT_NO_MERGED(&filter, N_("print only refs that are not merged")), + OPT_CONTAINS(&filter.with_commit, N_("print only refs which contain the commit")), + OPT_NO_CONTAINS(&filter.no_commit, N_("print only refs which don't contain the commit")), + OPT_BOOL(0, "ignore-case", &icase, N_("sorting and filtering are case insensitive")), + OPT_BOOL(0, "stdin", &from_stdin, N_("read reference patterns from stdin")), + OPT_BOOL(0, "include-root-refs", &include_root_refs, N_("also include HEAD ref and pseudorefs")), + OPT_END(), + }; + + format.format = "%(objectname) %(objecttype)\t%(refname)"; + + repo_config(repo, git_default_config, NULL); + + /* Default to sorting by refname unless overridden by --sort= */ + string_list_append(&sorting_options, "refname"); + + parse_options(argc, argv, prefix, opts, list_usage, 0); + if (format.array_opts.max_count < 0) { + error("invalid --count value: `%d'", format.array_opts.max_count); + usage_with_options(list_usage, opts); + } + if (HAS_MULTI_BITS(format.quote_style)) { + error("more than one quoting style?"); + usage_with_options(list_usage, opts); + } + if (verify_ref_format(&format)) + usage_with_options(list_usage, opts); + + sorting = ref_sorting_options(&sorting_options); + ref_sorting_set_sort_flags_all(sorting, REF_SORTING_ICASE, icase); + filter.ignore_case = icase; + + if (from_stdin) { + struct strbuf line = STRBUF_INIT; + + if (argv[0]) + die(_("unknown arguments supplied with --stdin")); + + while (strbuf_getline(&line, stdin) != EOF) + strvec_push(&vec, line.buf); + + strbuf_release(&line); + + /* vec.v is NULL-terminated, just like 'argv'. */ + filter.name_patterns = vec.v; + } else { + filter.name_patterns = argv; + } + + if (include_root_refs) + flags |= FILTER_REFS_ROOT_REFS | FILTER_REFS_DETACHED_HEAD; + + filter.match_as_path = 1; + filter_and_format_refs(&filter, flags, sorting, &format); + + ref_filter_clear(&filter); + ref_sorting_release(sorting); + strvec_clear(&vec); + 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] 9+ messages in thread
* Re: [GSoC][RFC PATCH 1/2] builtin/refs: add list subcommand 2025-06-27 7:49 ` [GSoC][RFC PATCH 1/2] builtin/refs: add " Meet Soni @ 2025-06-27 16:27 ` Jean-Noël Avila 2025-06-27 18:13 ` Junio C Hamano 2025-06-30 4:28 ` Meet Soni 0 siblings, 2 replies; 9+ messages in thread From: Jean-Noël Avila @ 2025-06-27 16:27 UTC (permalink / raw) To: Meet Soni, git; +Cc: ps, shejialuo, karthik.188, Junio C Hamano, John Cai Hello, I'm only focusing on the documentation part. Le 27/06/2025 à 09:49, Meet Soni a écrit : > > --- > Documentation/git-refs.adoc | 95 +++++++++++++++++++++++++++++++ > builtin/refs.c | 110 ++++++++++++++++++++++++++++++++++++ > 2 files changed, 205 insertions(+) > > diff --git a/Documentation/git-refs.adoc b/Documentation/git-refs.adoc > index 4d6dc994f9..d8f81eaabd 100644 > --- a/Documentation/git-refs.adoc > +++ b/Documentation/git-refs.adoc > @@ -11,6 +11,13 @@ SYNOPSIS > [synopsis] > git refs migrate --ref-format=<format> [--no-reflog] [--dry-run] > git refs verify [--strict] [--verbose] > +git refs list [--count=<count>] [--shell|--perl|--python|--tcl] please use spaces around '|' in alternative options: [--shell | --perl | --python | --tcl] > + [(--sort=<key>)...] [--format=<format>] This "[(--sort=<key>)...]" form is new to me. It abides by the synopsis syntax. As I understand it, the user can specify a number of --sort=<key> on the command line. From the description below, it seems that for --format, the actual syntax should be: [--format[=<format>]] > + [--include-root-refs] [ --stdin | <pattern>... ] Here no spaces, after '[' or before ']': [--stdin | <pattern>...] For syntax precedence, we have not documented anything, but the obvious meaning is "--stdin or a number of <pattern>. OK > + [--points-at=<object>] > + [--merged[=<object>]] [--no-merged[=<object>]] > + [--contains[=<object>]] [--no-contains[=<object>]] > + [--exclude=<pattern> ...] What are the ... meaning here ? Is it --exclude= followed by a number of <pattern>? What is the separator then? Or is it like for --sort? Maybe use another placeholder name to differentiate from the <pattern> alternative to --stdin > > DESCRIPTION > ----------- > @@ -26,6 +33,11 @@ migrate:: > verify:: > Verify reference database consistency. > > +list:: OK, synopsis is used in the first part, but this man page has not been fully converted. Let's stick to the previous style. > + List references in the repository with support for filtering, formatting, > + and sorting. This subcommand uses the same core logic as > + linkgit:git-for-each-ref[1] and offers equivalent functionality. > + > OPTIONS > ------- > > @@ -57,6 +69,89 @@ 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': > + > +<pattern>...:: > + If one or more patterns are given, only refs are shown that > + match against at least one pattern, either using fnmatch(3) or > + literally, in the latter case matching completely or from the > + beginning up to a slash. > +> +--stdin:: > + If `--stdin` is supplied, then the list of patterns is read from > + standard input instead of from the argument list.> + > +--count=<count>:: > + By default the command shows all refs that match > + `<pattern>`. This option makes it stop after showing > + that many refs. Please revert the sentences and remove the "this option makes it". The option description should state first the action of the option, then talk about default values, behavior, ... > + > +--sort=<key>:: > + A field name to sort on. Prefix `-` to sort in Use a verb in imperative mood as much as possible. > + descending order of the value. When unspecified, > + `refname` is used. You may use the --sort=<key> option > + multiple times, in which case the last key becomes the primary > + key. > + > +--format=<format>:: Cite the form with optional param > + A string that interpolates `%(fieldname)` from a ref being shown and > + the object it points at. In addition, the string literal `%%` > + renders as `%` and `%xx` - where `xx` are hex digits - renders as > + the character with hex code `xx`. For example, `%00` interpolates to the ASCII character only I guess: encoding matters here as we are usually in UTF-8. > + `\0` (NUL), `%09` to `\t` (TAB), and `%0a` to `\n` (LF). > ++ > +When unspecified, `<format>` defaults to `%(objectname) SPC %(objecttype) > +TAB %(refname)`. > + > +--color[=<when>]:: > + Respect any colors specified in the `--format` option. The > + `<when>` field must be one of `always`, `never`, or `auto` (if > + `<when>` is absent, behave as if `always` was given). > + > +--shell:: > +--perl:: > +--python:: > +--tcl:: > + If given, strings that substitute `%(fieldname)` Personal taste: "If given" is useless here. > + placeholders are quoted as string literals suitable for > + the specified host language. This is meant to produce > + a scriptlet that can directly be `eval`ed. > + > +--points-at=<object>:: > + Only list refs which points at the given object. > + > +--merged[=<object>]:: > + Only list refs whose tips are reachable from the > + specified commit (HEAD if not specified). > + > +--no-merged[=<object>]:: > + Only list refs whose tips are not reachable from the > + specified commit (HEAD if not specified). > + > +--contains[=<object>]:: > + Only list refs which contain the specified commit (HEAD if not > + specified). > + > +--no-contains[=<object>]:: > + Only list refs which don't contain the specified commit (HEAD > + if not specified). > + > +--ignore-case:: > + Sorting and filtering refs are case insensitive. > + > +--omit-empty:: > + Do not print a newline after formatted refs where the format expands > + to the empty string. > + > +--exclude=<pattern>:: > + If one or more patterns are given, only refs which do not match > + any excluded pattern(s) are shown. Matching is done using the > + same rules as `<pattern>` above. > + > +--include-root-refs:: > + List root refs (HEAD and pseudorefs) apart from regular refs. The description seems a bit off. Did you really mean "apart from", not "along with"? Thanks Jean-Noël ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [GSoC][RFC PATCH 1/2] builtin/refs: add list subcommand 2025-06-27 16:27 ` Jean-Noël Avila @ 2025-06-27 18:13 ` Junio C Hamano 2025-06-30 4:28 ` Meet Soni 1 sibling, 0 replies; 9+ messages in thread From: Junio C Hamano @ 2025-06-27 18:13 UTC (permalink / raw) To: Jean-Noël Avila; +Cc: Meet Soni, git, ps, shejialuo, karthik.188, John Cai Jean-Noël Avila <jn.avila@free.fr> writes: > Hello, > > I'm only focusing on the documentation part. > > Le 27/06/2025 à 09:49, Meet Soni a écrit : >> >> --- >> Documentation/git-refs.adoc | 95 +++++++++++++++++++++++++++++++ >> builtin/refs.c | 110 ++++++++++++++++++++++++++++++++++++ >> 2 files changed, 205 insertions(+) >> >> diff --git a/Documentation/git-refs.adoc b/Documentation/git-refs.adoc >> index 4d6dc994f9..d8f81eaabd 100644 >> --- a/Documentation/git-refs.adoc >> +++ b/Documentation/git-refs.adoc >> @@ -11,6 +11,13 @@ SYNOPSIS >> [synopsis] >> git refs migrate --ref-format=<format> [--no-reflog] [--dry-run] >> git refs verify [--strict] [--verbose] >> +git refs list [--count=<count>] [--shell|--perl|--python|--tcl] > > please use spaces around '|' in alternative options: > [--shell | --perl | --python | --tcl] As this seems to be copied and pasted with minimum modification, perhaps we are better off if you sent a "here is how you should do it" patch against Documentation/git-for-each-ref.adoc file where this was copied from. ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [GSoC][RFC PATCH 1/2] builtin/refs: add list subcommand 2025-06-27 16:27 ` Jean-Noël Avila 2025-06-27 18:13 ` Junio C Hamano @ 2025-06-30 4:28 ` Meet Soni 1 sibling, 0 replies; 9+ messages in thread From: Meet Soni @ 2025-06-30 4:28 UTC (permalink / raw) To: Jean-Noël Avila Cc: git, ps, shejialuo, karthik.188, Junio C Hamano, John Cai Thanks for the review, and apologies. I should've clarified earlier that the current documentation was meant as a placeholder until the feature direction is finalized. The intention was to help reviewers get a sense of the intended usage, and I plan to revise it more thoroughly once there's consensus on the interface. Also, noted the follow-up patch to improve the git-for-each-ref documentation. Thanks for taking that initiative! Thanks, Meet ^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2025-06-30 4:29 UTC | newest] Thread overview: 9+ 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 -- strict thread matches above, loose matches on Subject: below -- 2025-06-27 7:49 Meet Soni 2025-06-27 7:49 ` [GSoC][RFC PATCH 1/2] builtin/refs: add " Meet Soni 2025-06-27 16:27 ` Jean-Noël Avila 2025-06-27 18:13 ` Junio C Hamano 2025-06-30 4:28 ` 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).