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(+)
Show changes to 2 files +135 −0
Documentation/git-refs.adoc, builtin/refs.c
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(),
};