As part of the ongoing effort to consolidate reference handling, introduce a new `exists` subcommand. This command provides the same functionality and exit-code behavior as `git show-ref --exists`, serving as its modern replacement. The logic for `show-ref --exists` is minimal. Rather than creating a shared helper function which would be overkill for ~20 lines of code, its implementation is intentionally duplicated here. This contrasts with `git refs list`, where sharing the larger implementation of `for-each-ref` was necessary. Documentation for the new subcommand is also added to the `git-refs(1)` man page. Mentored-by: Patrick Steinhardt <ps@xxxxxx> Mentored-by: shejialuo <shejialuo@xxxxxxxxx> Signed-off-by: Meet Soni <meetsoni3017@xxxxxxxxx> --- Documentation/git-refs.adoc | 7 ++++++ builtin/refs.c | 48 +++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/Documentation/git-refs.adoc b/Documentation/git-refs.adoc index d462953fb5..bfa9b3ea2d 100644 --- a/Documentation/git-refs.adoc +++ b/Documentation/git-refs.adoc @@ -18,6 +18,7 @@ git refs list [--count=<count>] [--shell|--perl|--python|--tcl] [--contains[=<object>]] [--no-contains[=<object>]] [(--exclude=<pattern>)...] [--start-after=<marker>] [ --stdin | (<pattern>...)] +git refs exists <ref> DESCRIPTION ----------- @@ -38,6 +39,12 @@ list:: formatting, and sorting. This subcommand is an alias for linkgit:git-for-each-ref[1] and offers identical functionality. +exists:: + Check whether the given reference exists. Returns an exit code of 0 if + it does, 2 if it is missing, and 1 in case looking up the reference + failed with an error other than the reference being missing. This does + not verify whether the reference resolves to an actual object. + OPTIONS ------- diff --git a/builtin/refs.c b/builtin/refs.c index 76224feba4..617d8ab138 100644 --- a/builtin/refs.c +++ b/builtin/refs.c @@ -7,6 +7,7 @@ #include "strbuf.h" #include "worktree.h" #include "for-each-ref.h" +#include "refs/refs-internal.h" #define REFS_MIGRATE_USAGE \ N_("git refs migrate --ref-format=<format> [--no-reflog] [--dry-run]") @@ -14,6 +15,9 @@ #define REFS_VERIFY_USAGE \ N_("git refs verify [--strict] [--verbose]") +#define REFS_EXISTS_USAGE \ + N_("git refs exists <ref>") + static int cmd_refs_migrate(int argc, const char **argv, const char *prefix, struct repository *repo UNUSED) { @@ -113,6 +117,48 @@ static int cmd_refs_list(int argc, const char **argv, const char *prefix, return for_each_ref_core(argc, argv, prefix, repo, refs_list_usage); } +static int cmd_refs_exists(int argc, const char **argv, const char *prefix, + struct repository *repo UNUSED) +{ + struct strbuf unused_referent = STRBUF_INIT; + struct object_id unused_oid; + unsigned int unused_type; + int failure_errno = 0; + const char *ref; + + const char * const exists_usage[] = { + REFS_EXISTS_USAGE, + NULL, + }; + struct option options[] = { + OPT_END(), + }; + + argc = parse_options(argc, argv, prefix, options, exists_usage, 0); + if (!argc) + die("'git refs exists' requires a reference"); + + ref = *argv++; + if (*argv) + die("'git refs exists' requires exactly one reference"); + + if (refs_read_raw_ref(get_main_ref_store(the_repository), ref, + &unused_oid, &unused_referent, &unused_type, + &failure_errno)) { + if (failure_errno == ENOENT || failure_errno == EISDIR) { + error(_("reference does not exist")); + return 2; + } else { + errno = failure_errno; + error_errno(_("failed to look up reference")); + return 1; + } + } + + strbuf_release(&unused_referent); + return 0; +} + int cmd_refs(int argc, const char **argv, const char *prefix, @@ -122,6 +168,7 @@ int cmd_refs(int argc, REFS_MIGRATE_USAGE, REFS_VERIFY_USAGE, "git refs list " COMMON_USAGE_FOR_EACH_REF, + REFS_EXISTS_USAGE, NULL, }; parse_opt_subcommand_fn *fn = NULL; @@ -129,6 +176,7 @@ int cmd_refs(int argc, OPT_SUBCOMMAND("migrate", &fn, cmd_refs_migrate), OPT_SUBCOMMAND("verify", &fn, cmd_refs_verify), OPT_SUBCOMMAND("list", &fn, cmd_refs_list), + OPT_SUBCOMMAND("exists", &fn, cmd_refs_exists), OPT_END(), }; -- 2.34.1