From: "John Cai via GitGitGadget" <gitgitgadget@gmail.com>
To: git@vger.kernel.org
Cc: "Phillip Wood" <phillip.wood123@gmail.com>,
"Kristoffer Haugsbakk" <code@khaugsbakk.name>,
"Jeff King" <peff@peff.net>, "Patrick Steinhardt" <ps@pks.im>,
"Jean-Noël Avila" <avila.jn@gmail.com>,
"John Cai" <johncai86@gmail.com>
Subject: [PATCH v2 0/3] show-ref: add --symbolic-name option
Date: Mon, 08 Apr 2024 17:38:10 +0000 [thread overview]
Message-ID: <pull.1684.v2.git.git.1712597893.gitgitgadget@gmail.com> (raw)
In-Reply-To: <pull.1684.git.git.1709592718743.gitgitgadget@gmail.com>
For reftable development, it would be handy to have a tool to provide the
direct value of any ref whether it be a symbolic ref or not. Currently there
is git-symbolic-ref, which only works for symbolic refs, and git-rev-parse,
which will resolve the ref. Let's add a --symbolic-name option that will
print out the value the ref directly points to without dereferencing it.
Changes since V1:
* changed output format to print out values as a third column
* made plumbing changes to enable the value of a symbolic ref to be read
from the iterator
* changed the name of the flag
John Cai (3):
refs: keep track of unresolved reference value in iterator
refs: add referent to each_repo_ref_fn
show-ref: add --symbolic-name option
Documentation/git-show-ref.txt | 21 ++++++++++++++++++-
builtin/replace.c | 1 +
builtin/show-ref.c | 38 ++++++++++++++++++++++++----------
builtin/submodule--helper.c | 2 +-
refs.c | 31 ++++++++++++++++++---------
refs.h | 6 ++++--
refs/files-backend.c | 20 ++++++++++--------
refs/iterator.c | 3 ++-
refs/ref-cache.c | 3 +++
refs/ref-cache.h | 2 ++
refs/refs-internal.h | 1 +
refs/reftable-backend.c | 13 ++++++++----
remote.c | 2 +-
replace-object.c | 1 +
sequencer.c | 4 ++--
t/helper/test-ref-store.c | 2 +-
t/t1403-show-ref.sh | 20 ++++++++++++++++++
worktree.c | 4 +++-
18 files changed, 130 insertions(+), 44 deletions(-)
base-commit: 7774cfed6261ce2900c84e55906da708c711d601
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-1684%2Fjohn-cai%2Fjc%2Fshow-ref-direct-v2
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-1684/john-cai/jc/show-ref-direct-v2
Pull-Request: https://github.com/git/git/pull/1684
Range-diff vs v1:
-: ----------- > 1: 6adc9dd26da refs: keep track of unresolved reference value in iterator
-: ----------- > 2: b60e78560e0 refs: add referent to each_repo_ref_fn
1: c32572a8d0b ! 3: a9e6644327a show-ref: add --unresolved option
@@ Metadata
Author: John Cai <johncai86@gmail.com>
## Commit message ##
- show-ref: add --unresolved option
+ show-ref: add --symbolic-name option
For reftable development, it would be handy to have a tool to provide
the direct value of any ref whether it be a symbolic ref or not.
Currently there is git-symbolic-ref, which only works for symbolic refs,
- and git-rev-parse, which will resolve the ref. Let's add a --unresolved
- option that will only take one ref and return whatever it points to
- without dereferencing it.
+ and git-rev-parse, which will resolve the ref. Let's teach show-ref a
+ --symbolic-name option that will cause git-show-ref(1) to print out the
+ value symbolic references points to.
Signed-off-by: John Cai <johncai86@gmail.com>
## Documentation/git-show-ref.txt ##
@@ Documentation/git-show-ref.txt: SYNOPSIS
+ [verse]
+ 'git show-ref' [--head] [-d | --dereference]
+ [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]
+- [--heads] [--] [<pattern>...]
++ [--heads] [--symbolic-name] [--] [<pattern>...]
+ 'git show-ref' --verify [-q | --quiet] [-d | --dereference]
+ [-s | --hash[=<n>]] [--abbrev[=<n>]]
[--] [<ref>...]
- 'git show-ref' --exclude-existing[=<pattern>]
- 'git show-ref' --exists <ref>
-+'git show-ref' --unresolved <ref>
-
- DESCRIPTION
- -----------
@@ Documentation/git-show-ref.txt: OPTIONS
- 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.
+ Dereference tags into object IDs as well. They will be shown with `^{}`
+ appended.
+
++--symbolic-name::
++
++ Print out the value the reference points to without dereferencing. This
++ is useful to know the reference that a symbolic ref is pointing to.
++
+ -s::
+ --hash[=<n>]::
+
+@@ Documentation/git-show-ref.txt: $ git show-ref --heads --hash
+ ...
+ -----------------------------------------------------------------------------
-+--unresolved::
++When using `--symbolic-name`, the output is in the format:
++
++-----------
++<oid> SP <ref> SP <symbolic-name>
++-----------
+
-+ Prints out what the reference points to without resolving it. 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.
++For example,
+
- --abbrev[=<n>]::
++-----------------------------------------------------------------------------
++$ git show-ref --symbolic-name
++b75428bae1d090f60bdd4b67185f814bc8f0819d refs/heads/SYMBOLIC_REF ref:refs/heads/main
++...
++-----------------------------------------------------------------------------
++
+ EXAMPLES
+ --------
- Abbreviate the object name. When using `--hash`, you do
## builtin/show-ref.c ##
-@@ builtin/show-ref.c: static const char * const show_ref_usage[] = {
+@@
+ static const char * const show_ref_usage[] = {
+ N_("git show-ref [--head] [-d | --dereference]\n"
+ " [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]\n"
+- " [--heads] [--] [<pattern>...]"),
++ " [--heads] [--symbolic-name] [--] [<pattern>...]"),
+ N_("git show-ref --verify [-q | --quiet] [-d | --dereference]\n"
+ " [-s | --hash[=<n>]] [--abbrev[=<n>]]\n"
" [--] [<ref>...]"),
- N_("git show-ref --exclude-existing[=<pattern>]"),
- N_("git show-ref --exists <ref>"),
-+ N_("git show-ref --unresolved <ref>"),
- NULL
+@@ builtin/show-ref.c: struct show_one_options {
+ int hash_only;
+ int abbrev;
+ int deref_tags;
++ int symbolic_name;
};
-@@ builtin/show-ref.c: static int cmd_show_ref__patterns(const struct patterns_options *opts,
- return 0;
- }
+ static void show_one(const struct show_one_options *opts,
+- const char *refname, const struct object_id *oid)
++ const char *refname,
++ const char *referent,
++ const struct object_id *oid, const int is_symref)
+ {
+ const char *hex;
+ struct object_id peeled;
+@@ builtin/show-ref.c: static void show_one(const struct show_one_options *opts,
+ hex = repo_find_unique_abbrev(the_repository, oid, opts->abbrev);
+ if (opts->hash_only)
+ printf("%s\n", hex);
+- else
++ else if (opts->symbolic_name & is_symref) {
++ printf("%s %s ref:%s\n", hex, refname, referent);
++ } else
+ printf("%s %s\n", hex, refname);
--static int cmd_show_ref__exists(const char **refs)
-+static int cmd_show_ref__raw(const char **refs, int show)
+ if (!opts->deref_tags)
+@@ builtin/show-ref.c: struct show_ref_data {
+ int show_head;
+ };
+
+-static int show_ref(const char *refname, const struct object_id *oid,
+- int flag UNUSED, void *cbdata)
++static int show_ref_referent(struct repository *repo UNUSED,
++ const char *refname,
++ const char *referent,
++ const struct object_id *oid,
++ int flag, void *cbdata)
{
-- struct strbuf unused_referent = STRBUF_INIT;
-- struct object_id unused_oid;
-- unsigned int unused_type;
-+ struct strbuf referent = STRBUF_INIT;
-+ struct object_id oid;
-+ unsigned int type;
- int failure_errno = 0;
- const char *ref;
- int ret = 0;
-@@ builtin/show-ref.c: static int cmd_show_ref__exists(const char **refs)
- die("--exists requires exactly one reference");
-
- if (refs_read_raw_ref(get_main_ref_store(the_repository), ref,
-- &unused_oid, &unused_referent, &unused_type,
-+ &oid, &referent, &type,
- &failure_errno)) {
- if (failure_errno == ENOENT || failure_errno == EISDIR) {
- error(_("reference does not exist"));
-@@ builtin/show-ref.c: static int cmd_show_ref__exists(const char **refs)
- goto out;
- }
+ struct show_ref_data *data = cbdata;
-+ if (!show)
-+ goto out;
-+
-+ if (type & REF_ISSYMREF)
-+ printf("ref: %s\n", referent.buf);
-+ else
-+ printf("ref: %s\n", oid_to_hex(&oid));
-+
- out:
-- strbuf_release(&unused_referent);
-+ strbuf_release(&referent);
- return ret;
+@@ builtin/show-ref.c: static int show_ref(const char *refname, const struct object_id *oid,
+ match:
+ data->found_match++;
+
+- show_one(data->show_one_opts, refname, oid);
++ show_one(data->show_one_opts, refname, referent, oid, flag & REF_ISSYMREF);
+
+ return 0;
}
++static int show_ref(const char *refname, const struct object_id *oid,
++ int flag, void *cbdata)
++{
++ return show_ref_referent(NULL, refname, NULL, oid, flag, cbdata);
++}
++
+ static int add_existing(const char *refname,
+ const struct object_id *oid UNUSED,
+ int flag UNUSED, void *cbdata)
+@@ builtin/show-ref.c: static int cmd_show_ref__verify(const struct show_one_options *show_one_opts,
+
+ while (*refs) {
+ struct object_id oid;
++ int flags = 0;
+
+ if ((starts_with(*refs, "refs/") || refname_is_safe(*refs)) &&
+- !read_ref(*refs, &oid)) {
+- show_one(show_one_opts, *refs, &oid);
++ !read_ref_full(*refs, 0, &oid, &flags)) {
++ show_one(show_one_opts, *refs, NULL, &oid, flags & REF_ISSYMREF);
+ }
+ else if (!show_one_opts->quiet)
+ die("'%s' - not a valid ref", *refs);
+@@ builtin/show-ref.c: static int cmd_show_ref__patterns(const struct patterns_options *opts,
+ head_ref(show_ref, &show_ref_data);
+ if (opts->heads_only || opts->tags_only) {
+ if (opts->heads_only)
+- for_each_fullref_in("refs/heads/", show_ref, &show_ref_data);
++ for_each_ref_all("refs/heads/", show_ref_referent, &show_ref_data);
+ if (opts->tags_only)
+- for_each_fullref_in("refs/tags/", show_ref, &show_ref_data);
++ for_each_ref_all("refs/tags/", show_ref_referent, &show_ref_data);
+ } else {
+- for_each_ref(show_ref, &show_ref_data);
++ for_each_ref_all("", show_ref_referent, &show_ref_data);
+ }
+ if (!show_ref_data.found_match)
+ return 1;
@@ builtin/show-ref.c: int cmd_show_ref(int argc, const char **argv, const char *prefix)
- struct exclude_existing_options exclude_existing_opts = {0};
- struct patterns_options patterns_opts = {0};
- struct show_one_options show_one_opts = {0};
-- int verify = 0, exists = 0;
-+ int verify = 0, exists = 0, unresolved = 0;
- const struct option show_ref_options[] = {
OPT_BOOL(0, "tags", &patterns_opts.tags_only, N_("only show tags (can be combined with heads)")),
OPT_BOOL(0, "heads", &patterns_opts.heads_only, N_("only show heads (can be combined with tags)")),
OPT_BOOL(0, "exists", &exists, N_("check for reference existence without resolving")),
-+ OPT_BOOL(0, "unresolved", &unresolved, N_("print out unresolved value of reference")),
++ OPT_BOOL(0, "symbolic-name", &show_one_opts.symbolic_name, N_("print out symbolic reference values")),
OPT_BOOL(0, "verify", &verify, N_("stricter reference checking, "
"requires exact ref path")),
OPT_HIDDEN_BOOL('h', NULL, &patterns_opts.show_head,
-@@ builtin/show-ref.c: int cmd_show_ref(int argc, const char **argv, const char *prefix)
- argc = parse_options(argc, argv, prefix, show_ref_options,
- show_ref_usage, 0);
-
-- die_for_incompatible_opt3(exclude_existing_opts.enabled, "--exclude-existing",
-+ die_for_incompatible_opt4(exclude_existing_opts.enabled, "--exclude-existing",
- verify, "--verify",
-- exists, "--exists");
-+ exists, "--exists",
-+ unresolved, "--unresolved");
-
- if (exclude_existing_opts.enabled)
- return cmd_show_ref__exclude_existing(&exclude_existing_opts);
- else if (verify)
- return cmd_show_ref__verify(&show_one_opts, argv);
-- else if (exists)
-- return cmd_show_ref__exists(argv);
-+ else if (exists || unresolved)
-+ return cmd_show_ref__raw(argv, unresolved);
- else
- return cmd_show_ref__patterns(&patterns_opts, &show_one_opts, argv);
- }
- ## t/t1403-show-ref.sh ##
-@@ t/t1403-show-ref.sh: test_expect_success 'show-ref sub-modes are mutually exclusive' '
- test_must_fail git show-ref --exclude-existing --exists 2>err &&
- grep "exclude-existing" err &&
- grep "exists" err &&
-+ grep "cannot be used together" err &&
-+
-+ test_must_fail git show-ref --exclude-existing --unresolved 2>err &&
-+ grep "exclude-existing" err &&
-+ grep "unresolved" err &&
-+ grep "cannot be used together" err &&
+ ## refs.c ##
+@@ refs.c: int for_each_replace_ref(struct repository *r, each_repo_ref_fn fn, void *cb_dat
+ DO_FOR_EACH_INCLUDE_BROKEN, cb_data);
+ }
+
++int for_each_ref_all(const char *prefix, each_repo_ref_fn fn, void *cb_data)
++{
++ return do_for_each_repo_ref(the_repository, prefix, fn, 0,
++ 0, cb_data);
++}
+
-+ test_must_fail git show-ref --verify --unresolved 2>err &&
-+ grep "verify" err &&
-+ grep "unresolved" err &&
- grep "cannot be used together" err
- '
+ int for_each_namespaced_ref(const char **exclude_patterns,
+ each_ref_fn fn, void *cb_data)
+ {
+
+ ## refs.h ##
+@@ refs.h: int refs_for_each_branch_ref(struct ref_store *refs,
+ each_ref_fn fn, void *cb_data);
+ int refs_for_each_remote_ref(struct ref_store *refs,
+ each_ref_fn fn, void *cb_data);
+-
+ /* just iterates the head ref. */
+ int head_ref(each_ref_fn fn, void *cb_data);
+
+@@ refs.h: int for_each_tag_ref(each_ref_fn fn, void *cb_data);
+ int for_each_branch_ref(each_ref_fn fn, void *cb_data);
+ int for_each_remote_ref(each_ref_fn fn, void *cb_data);
+ int for_each_replace_ref(struct repository *r, each_repo_ref_fn fn, void *cb_data);
++int for_each_ref_all(const char *prefix, each_repo_ref_fn fn, void *cb_data);
+ /* iterates all refs that match the specified glob pattern. */
+ int for_each_glob_ref(each_ref_fn fn, const char *pattern, void *cb_data);
+
+ ## t/t1403-show-ref.sh ##
@@ t/t1403-show-ref.sh: test_expect_success '--exists with existing special ref' '
git show-ref --exists FETCH_HEAD
'
-+test_expect_success '--unresolved with existing reference' '
++test_expect_success '--symbolic-name with a non symbolic ref' '
+ commit_oid=$(git rev-parse refs/heads/$GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME) &&
+ cat >expect <<-EOF &&
-+ ref: $commit_oid
-+ EOF
-+ git show-ref --unresolved refs/heads/$GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME >actual &&
-+ test_cmp expect actual
-+'
-+
-+test_expect_success '--unresolved with symbolic ref' '
-+ test_when_finished "git symbolic-ref -d SYMBOLIC_REF_A" &&
-+ cat >expect <<-EOF &&
-+ ref: refs/heads/$GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
++ $commit_oid refs/heads/$GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+ EOF
-+ git symbolic-ref SYMBOLIC_REF_A refs/heads/$GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME &&
-+ git show-ref --unresolved SYMBOLIC_REF_A >actual &&
++ git show-ref --symbolic-name refs/heads/$GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME >actual &&
+ test_cmp expect actual
+'
+
-+test_expect_success '--unresolved with nonexistent object ID' '
-+ oid=$(test_oid 002) &&
-+ test-tool ref-store main update-ref msg refs/heads/missing-oid-2 $oid $ZERO_OID REF_SKIP_OID_VERIFICATION &&
++test_expect_success '--symbolic-name with symbolic ref' '
++ test_when_finished "git symbolic-ref -d refs/heads/SYMBOLIC_REF_A" &&
++ commit_oid=$(git rev-parse refs/heads/$GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME) &&
+ cat >expect <<-EOF &&
-+ ref: $oid
++ $commit_oid refs/heads/SYMBOLIC_REF_A ref:refs/heads/$GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+ EOF
-+ git show-ref --unresolved refs/heads/missing-oid-2 >actual &&
++ git symbolic-ref refs/heads/SYMBOLIC_REF_A refs/heads/$GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME &&
++ git show-ref --symbolic-name SYMBOLIC_REF_A >actual &&
+ test_cmp expect actual
+'
-+
-+test_expect_success '--unresolved with nonexistent reference' '
-+ cat >expect <<-EOF &&
-+ error: reference does not exist
-+ EOF
-+ test_expect_code 2 git show-ref --unresolved refs/heads/not-exist 2>err &&
-+ test_cmp expect err
-+'
+
test_done
--
gitgitgadget
next prev parent reply other threads:[~2024-04-08 17:38 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-03-04 22:51 [PATCH] show-ref: add --unresolved option John Cai via GitGitGadget
2024-03-04 23:23 ` Junio C Hamano
2024-03-05 20:56 ` John Cai
2024-03-05 21:29 ` Junio C Hamano
2024-03-05 15:30 ` Phillip Wood
2024-03-05 17:01 ` Kristoffer Haugsbakk
2024-03-06 0:33 ` Jeff King
2024-03-06 2:19 ` Junio C Hamano
2024-03-06 0:41 ` Jeff King
2024-03-06 7:31 ` Patrick Steinhardt
2024-03-06 7:51 ` Jeff King
2024-03-06 16:48 ` Junio C Hamano
2024-03-06 9:36 ` Jean-Noël Avila
2024-04-08 17:38 ` John Cai via GitGitGadget [this message]
2024-04-08 17:38 ` [PATCH v2 1/3] refs: keep track of unresolved reference value in iterator John Cai via GitGitGadget
2024-04-08 23:02 ` Junio C Hamano
2024-04-09 20:29 ` John Cai
2024-04-10 6:52 ` Patrick Steinhardt
2024-04-10 15:26 ` Junio C Hamano
2024-04-11 9:11 ` Patrick Steinhardt
2024-04-08 17:38 ` [PATCH v2 2/3] refs: add referent to each_repo_ref_fn John Cai via GitGitGadget
2024-04-08 17:38 ` [PATCH v2 3/3] show-ref: add --symbolic-name option John Cai via GitGitGadget
2024-04-09 15:25 ` Phillip Wood
2024-04-11 19:57 ` John Cai
2024-04-12 9:37 ` phillip.wood123
2024-04-10 6:53 ` Patrick Steinhardt
2024-04-10 15:27 ` Junio C Hamano
2024-04-12 15:23 ` John Cai
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=pull.1684.v2.git.git.1712597893.gitgitgadget@gmail.com \
--to=gitgitgadget@gmail.com \
--cc=avila.jn@gmail.com \
--cc=code@khaugsbakk.name \
--cc=git@vger.kernel.org \
--cc=johncai86@gmail.com \
--cc=peff@peff.net \
--cc=phillip.wood123@gmail.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 read-only IMAP folder(s) and NNTP newsgroup(s).