{"thread":{"id":"64190","subject":"[GSoC][PATCH] builtin/refs: add 'get' subcommand","startedAt":"2025-09-23T10:45:40Z","lastAt":"2025-09-25T18:43:50Z","messageCount":11,"participants":["Meet Soni","Ben Knoble","Junio C Hamano","Patrick Steinhardt","D. Ben Knoble"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"527068","messageId":"20250923104533.21165-1-meetsoni3017@gmail.com","threadId":"64190","inReplyTo":null,"subject":"[GSoC][PATCH] builtin/refs: add 'get' subcommand","fromName":"Meet Soni","fromEmail":"meetsoni3017@gmail.com","sentAt":"2025-09-23T10:45:33Z","receivedAt":"2025-09-23T10:45:40Z","isPatch":true,"sender":{"key":"meetsoni3017@gmail.com","avatar":"https://avatars.githubusercontent.com/u/92802561?v=4"},"body":"While `git-rev-parse(1)` and `git-show-ref(1)` can be used to read\nreference values, they have drawbacks for scripting and discoverability.\n`rev-parse` performs DWIM expansion which is unpredictable for scripts,\nand `show-ref --verify` is difficult to discover and cannot read the\ndirect target of a symbolic reference.\n\nTo address this, introduce a new plumbing command, `git refs get <ref>`.\nThis new command provides three key advantages:\n\n  - It requires an exact refname and does not perform expansion, making\n    it safer and more predictable for scripting.\n\n  - Its name clearly states its purpose and it lives in the logical `git\n    refs` namespace, unlike the `--verify` flag which lives in\n    `git-show-ref`.\n\n  - It provides a clean, dedicated way to read the direct target of a\n    symbolic reference (e.g., `HEAD`) without recursively dereferencing\n    it to an object ID.\n\nAdd documentation for the new subcommand to the `git-refs(1)` man page\nand a comprehensive test suite to verify its behavior.\n\nMentored-by: Patrick Steinhardt <ps@pks.im>\nMentored-by: shejialuo <shejialuo@gmail.com>\nSigned-off-by: Meet Soni <meetsoni3017@gmail.com>\n---\n Documentation/git-refs.adoc |  7 ++++\n builtin/refs.c              | 43 ++++++++++++++++++++++++\n t/meson.build               |  1 +\n t/t1464-refs-get.sh         | 66 +++++++++++++++++++++++++++++++++++++\n 4 files changed, 117 insertions(+)\n create mode 100755 t/t1464-refs-get.sh\n\ndiff --git a/Documentation/git-refs.adoc b/Documentation/git-refs.adoc\nindex bfa9b3ea2d..f07fe8c864 100644\n--- a/Documentation/git-refs.adoc\n+++ b/Documentation/git-refs.adoc\n@@ -19,6 +19,7 @@ git refs list [--count=<count>] [--shell|--perl|--python|--tcl]\n \t\t   [(--exclude=<pattern>)...] [--start-after=<marker>]\n \t\t   [ --stdin | (<pattern>...)]\n git refs exists <ref>\n+git refs get <ref>\n \n DESCRIPTION\n -----------\n@@ -45,6 +46,12 @@ exists::\n \tfailed with an error other than the reference being missing. This does\n \tnot verify whether the reference resolves to an actual object.\n \n+get::\n+\tReads the raw value of a single, exact reference. Instead of\n+\trecursively dereferencing symbolic references, this command prints the\n+\tdirect target of the symref (e.g., ref: refs/heads/main). For regular\n+\treferences, it prints the object ID (SHA-1) they point to.\n+\n OPTIONS\n -------\n \ndiff --git a/builtin/refs.c b/builtin/refs.c\nindex 91548783b7..b473a78e18 100644\n--- a/builtin/refs.c\n+++ b/builtin/refs.c\n@@ -2,6 +2,7 @@\n #include \"builtin.h\"\n #include \"config.h\"\n #include \"fsck.h\"\n+#include \"hex.h\"\n #include \"parse-options.h\"\n #include \"refs.h\"\n #include \"strbuf.h\"\n@@ -18,6 +19,9 @@\n #define REFS_EXISTS_USAGE \\\n \tN_(\"git refs exists <ref>\")\n \n+#define REFS_GET_USAGE \\\n+\tN_(\"git refs get <ref>\")\n+\n static int cmd_refs_migrate(int argc, const char **argv, const char *prefix,\n \t\t\t    struct repository *repo UNUSED)\n {\n@@ -159,6 +163,43 @@ static int cmd_refs_exists(int argc, const char **argv, const char *prefix,\n \treturn ret;\n }\n \n+static int cmd_refs_get(int argc, const char **argv, const char *prefix,\n+\t\t\tstruct repository *repo UNUSED)\n+{\n+\tconst char *refname;\n+\tstruct object_id oid;\n+\tunsigned int type;\n+\tint failure_errno = 0;\n+\tstruct strbuf referent = STRBUF_INIT;\n+\n+\tconst char * const exists_usage[] = {\n+\t\tREFS_EXISTS_USAGE,\n+\t\tNULL,\n+\t};\n+\tstruct option options[] = {\n+\t\tOPT_END(),\n+\t};\n+\n+\targc = parse_options(argc, argv, prefix, options, exists_usage, 0);\n+\tif (argc != 1)\n+\t\tdie(\"refs get requires exactly one reference\");\n+\n+\trefname = *argv++;\n+\tif (refs_read_raw_ref(get_main_ref_store(the_repository), refname,\n+\t\t\t      &oid, &referent, &type, &failure_errno)) {\n+\t\tdie(\"'%s' - not a valid ref\", refname);\n+\t}\n+\n+\tif (type & REF_ISSYMREF) {\n+\t\tprintf(\"ref: %s\\n\", referent.buf);\n+\t} else {\n+\t\tprintf(\"%s\\n\", oid_to_hex(&oid));\n+\t}\n+\n+\tstrbuf_release(&referent);\n+\treturn 0;\n+}\n+\n int cmd_refs(int argc,\n \t     const char **argv,\n \t     const char *prefix,\n@@ -169,6 +210,7 @@ int cmd_refs(int argc,\n \t\tREFS_VERIFY_USAGE,\n \t\t\"git refs list \" COMMON_USAGE_FOR_EACH_REF,\n \t\tREFS_EXISTS_USAGE,\n+\t\tREFS_GET_USAGE,\n \t\tNULL,\n \t};\n \tparse_opt_subcommand_fn *fn = NULL;\n@@ -177,6 +219,7 @@ int cmd_refs(int argc,\n \t\tOPT_SUBCOMMAND(\"verify\", &fn, cmd_refs_verify),\n \t\tOPT_SUBCOMMAND(\"list\", &fn, cmd_refs_list),\n \t\tOPT_SUBCOMMAND(\"exists\", &fn, cmd_refs_exists),\n+\t\tOPT_SUBCOMMAND(\"get\", &fn, cmd_refs_get),\n \t\tOPT_END(),\n \t};\n \ndiff --git a/t/meson.build b/t/meson.build\nindex 7974795fe4..0c8067c69d 100644\n--- a/t/meson.build\n+++ b/t/meson.build\n@@ -213,6 +213,7 @@ integration_tests = [\n   't1460-refs-migrate.sh',\n   't1461-refs-list.sh',\n   't1462-refs-exists.sh',\n+  't1464-refs-get.sh',\n   't1500-rev-parse.sh',\n   't1501-work-tree.sh',\n   't1502-rev-parse-parseopt.sh',\ndiff --git a/t/t1464-refs-get.sh b/t/t1464-refs-get.sh\nnew file mode 100755\nindex 0000000000..166176c881\n--- /dev/null\n+++ b/t/t1464-refs-get.sh\n@@ -0,0 +1,66 @@\n+#!/bin/sh\n+\n+test_description='git refs get'\n+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main\n+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n+\n+. ./test-lib.sh\n+\n+test_expect_success 'setup repository' '\n+\ttest_commit one &&\n+\tgit tag -a -m \"tagging one\" my-tag one &&\n+\tgit symbolic-ref refs/my-symref refs/heads/main &&\n+\tgit symbolic-ref refs/dangling-symref refs/heads/no-such-branch\n+'\n+\n+test_expect_success 'fails with no arguments' '\n+\ttest_must_fail git refs get >out 2>err &&\n+\ttest_grep \"refs get requires exactly one reference\" err\n+'\n+\n+test_expect_success 'fails with too many arguments' '\n+\ttest_must_fail git refs get HEAD HEAD >out 2>err &&\n+\ttest_grep \"refs get requires exactly one reference\" err\n+'\n+\n+test_expect_success 'get a branch head' '\n+\tgit rev-parse main >expect &&\n+\tgit refs get refs/heads/main >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'get an annotated tag' '\n+\tgit rev-parse my-tag >expect &&\n+\tgit refs get refs/tags/my-tag >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'get HEAD (a symbolic ref)' '\n+\techo \"ref: refs/heads/main\" >expect &&\n+\tgit refs get HEAD >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'get a custom symbolic ref' '\n+\techo \"ref: refs/heads/main\" >expect &&\n+\tgit refs get refs/my-symref >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'get a dangling symbolic ref' '\n+\techo \"ref: refs/heads/no-such-branch\" >expect &&\n+\tgit refs get refs/dangling-symref >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'get a non-existent ref' '\n+\ttest_must_fail git refs get refs/heads/no-such-branch 2>err &&\n+\ttest_grep \"not a valid ref\" err\n+'\n+\n+test_expect_success 'get does not perform DWIM' '\n+\ttest_must_fail git refs get main 2>err &&\n+\ttest_grep \"not a valid ref\" err\n+'\n+\n+test_done\n\nbase-commit: ca2559c1d630eb4f04cdee2328aaf1c768907a9e\n-- \n2.34.1\n\n"},{"id":"527106","messageId":"ABB734D1-EAB4-429C-9A36-C00E114E4207@gmail.com","threadId":"64190","inReplyTo":"20250923104533.21165-1-meetsoni3017@gmail.com","subject":"Re: [GSoC][PATCH] builtin/refs: add 'get' subcommand","fromName":"Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2025-09-23T16:57:04Z","receivedAt":"2025-09-23T16:57:17Z","isPatch":true,"sender":{"key":"ben.knoble@gmail.com","avatar":"https://avatars.githubusercontent.com/u/22802209?v=4"},"body":"With apologies if I cover well-trodden ground, as I haven’t been closely following this effort.\n\n> Le 23 sept. 2025 à 06:47, Meet Soni <meetsoni3017@gmail.com> a écrit :\n> \n> ﻿While `git-rev-parse(1)` and `git-show-ref(1)` can be used to read\n> reference values, they have drawbacks for scripting and discoverability.\n> `rev-parse` performs DWIM expansion which is unpredictable for scripts,\n\n[snip]\n\n> To address this, introduce a new plumbing command, `git refs get <ref>`.\n> This new command provides three key advantages:\n> \n>  - It requires an exact refname and does not perform expansion, making\n>    it safer and more predictable for scripting.\n\nWhat are the disadvantages of rev-parse’s DWIMmery in scripts? I would think it makes handling user input easier (e.g., my custom script can take a local branch name without writing « refs/heads/ » on the command-line). OTOH, a script that wants to precisely identify a ref can do so already, no?\n\nSince rev-parse presumably won’t go away, it might be ok to have 2 ways of parsing (one with magic and one without), but that might be back to the same boat of not having a unified interface 😅\n\nPerhaps later we can add a « --dwim » flag for looser parsing, giving scripteds flexibility but strictness by default?"},{"id":"527158","messageId":"xmqqecrwon2h.fsf@gitster.g","threadId":"64190","inReplyTo":"20250923104533.21165-1-meetsoni3017@gmail.com","subject":"Re: [GSoC][PATCH] builtin/refs: add 'get' subcommand","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-09-23T21:50:46Z","receivedAt":"2025-09-23T21:50:48Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Meet Soni <meetsoni3017@gmail.com> writes:\n\n> While `git-rev-parse(1)` and `git-show-ref(1)` can be used to read\n> reference values, they have drawbacks for scripting and discoverability.\n> `rev-parse` performs DWIM expansion which is unpredictable for scripts,\n> and `show-ref --verify` is difficult to discover and cannot read the\n> direct target of a symbolic reference.\n\nWell \"refs get\" is even harder to discover (it is not even in Git\n2.50's manual that is available everywhere on the net), so difficult\nto discover is not a good excuse.  In a sense show-ref was invented\nexactly to serve as something like \"refs get\" you are writing, so I\nwonder if a better approach is to extend it instead of introducing\na new subcommand in a distant place from it?\n\nPerhaps \"show-ref --verify --no-deref\" or something that does not\ndereference but works directly on a symbolic ref?\n\n"},{"id":"527181","messageId":"aNOQgLmVTZ0JRzOm@pks.im","threadId":"64190","inReplyTo":"ABB734D1-EAB4-429C-9A36-C00E114E4207@gmail.com","subject":"Re: [GSoC][PATCH] builtin/refs: add 'get' subcommand","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-09-24T06:32:32Z","receivedAt":"2025-09-24T06:32:39Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Tue, Sep 23, 2025 at 12:57:04PM -0400, Ben Knoble wrote:\n> With apologies if I cover well-trodden ground, as I haven’t been closely following this effort.\n> \n> > Le 23 sept. 2025 à 06:47, Meet Soni <meetsoni3017@gmail.com> a écrit :\n> > \n> > ﻿While `git-rev-parse(1)` and `git-show-ref(1)` can be used to read\n> > reference values, they have drawbacks for scripting and discoverability.\n> > `rev-parse` performs DWIM expansion which is unpredictable for scripts,\n> \n> [snip]\n> \n> > To address this, introduce a new plumbing command, `git refs get <ref>`.\n> > This new command provides three key advantages:\n> > \n> >  - It requires an exact refname and does not perform expansion, making\n> >    it safer and more predictable for scripting.\n> \n> What are the disadvantages of rev-parse’s DWIMmery in scripts? I would\n> think it makes handling user input easier (e.g., my custom script can\n> take a local branch name without writing « refs/heads/ » on the\n> command-line). OTOH, a script that wants to precisely identify a ref\n> can do so already, no?\n> \n> Since rev-parse presumably won’t go away, it might be ok to have 2\n> ways of parsing (one with magic and one without), but that might be\n> back to the same boat of not having a unified interface 😅\n> \n> Perhaps later we can add a « --dwim » flag for looser parsing, giving\n> scripteds flexibility but strictness by default?\n\nI think having such a \"--dwim\" flag at a later point could be a good\nidea, yeah.\n\nPatrick\n"},{"id":"527182","messageId":"aNOQhncjwYCwCaZ3@pks.im","threadId":"64190","inReplyTo":"xmqqecrwon2h.fsf@gitster.g","subject":"Re: [GSoC][PATCH] builtin/refs: add 'get' subcommand","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-09-24T06:32:38Z","receivedAt":"2025-09-24T06:32:43Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Tue, Sep 23, 2025 at 02:50:46PM -0700, Junio C Hamano wrote:\n> Meet Soni <meetsoni3017@gmail.com> writes:\n> \n> > While `git-rev-parse(1)` and `git-show-ref(1)` can be used to read\n> > reference values, they have drawbacks for scripting and discoverability.\n> > `rev-parse` performs DWIM expansion which is unpredictable for scripts,\n> > and `show-ref --verify` is difficult to discover and cannot read the\n> > direct target of a symbolic reference.\n> \n> Well \"refs get\" is even harder to discover (it is not even in Git\n> 2.50's manual that is available everywhere on the net), so difficult\n> to discover is not a good excuse.  In a sense show-ref was invented\n> exactly to serve as something like \"refs get\" you are writing, so I\n> wonder if a better approach is to extend it instead of introducing\n> a new subcommand in a distant place from it?\n> \n> Perhaps \"show-ref --verify --no-deref\" or something that does not\n> dereference but works directly on a symbolic ref?\n\nFor now: yes, it's more difficult to discover for sure. But users will\nadjust over time as they get more familiar with git-refs(1), and from\nthereon I think it will become significantly easier to discover that\nsubcommand.\n\ngit-refs(1) already hosts everything needed to handle references, so\nfrom my point of view it is only natural to also provide an easy way to\nread a single reference to complete the picture.\n\nPatrick\n"},{"id":"527183","messageId":"aNOQi04mS0uXD4iv@pks.im","threadId":"64190","inReplyTo":"20250923104533.21165-1-meetsoni3017@gmail.com","subject":"Re: [GSoC][PATCH] builtin/refs: add 'get' subcommand","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-09-24T06:32:43Z","receivedAt":"2025-09-24T06:32:48Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Tue, Sep 23, 2025 at 04:15:33PM +0530, Meet Soni wrote:\n> diff --git a/Documentation/git-refs.adoc b/Documentation/git-refs.adoc\n> index bfa9b3ea2d..f07fe8c864 100644\n> --- a/Documentation/git-refs.adoc\n> +++ b/Documentation/git-refs.adoc\n> @@ -19,6 +19,7 @@ git refs list [--count=<count>] [--shell|--perl|--python|--tcl]\n>  \t\t   [(--exclude=<pattern>)...] [--start-after=<marker>]\n>  \t\t   [ --stdin | (<pattern>...)]\n>  git refs exists <ref>\n> +git refs get <ref>\n>  \n>  DESCRIPTION\n>  -----------\n> @@ -45,6 +46,12 @@ exists::\n>  \tfailed with an error other than the reference being missing. This does\n>  \tnot verify whether the reference resolves to an actual object.\n>  \n> +get::\n> +\tReads the raw value of a single, exact reference. Instead of\n\nLet's say \"fully qualified\" instead of \"exact\".\n\n> +\trecursively dereferencing symbolic references, this command prints the\n> +\tdirect target of the symref (e.g., ref: refs/heads/main). For regular\n> +\treferences, it prints the object ID (SHA-1) they point to.\n\nI'd drop the reference to SHA1 here, as it may be any object hash.\n\n> diff --git a/builtin/refs.c b/builtin/refs.c\n> index 91548783b7..b473a78e18 100644\n> --- a/builtin/refs.c\n> +++ b/builtin/refs.c\n> @@ -159,6 +163,43 @@ static int cmd_refs_exists(int argc, const char **argv, const char *prefix,\n>  \treturn ret;\n>  }\n>  \n> +static int cmd_refs_get(int argc, const char **argv, const char *prefix,\n> +\t\t\tstruct repository *repo UNUSED)\n> +{\n> +\tconst char *refname;\n> +\tstruct object_id oid;\n> +\tunsigned int type;\n> +\tint failure_errno = 0;\n> +\tstruct strbuf referent = STRBUF_INIT;\n\nTiny nit: we typically order variables that aren't accessed by options\nafter the options array.\n\n> +\tconst char * const exists_usage[] = {\n> +\t\tREFS_EXISTS_USAGE,\n> +\t\tNULL,\n> +\t};\n> +\tstruct option options[] = {\n> +\t\tOPT_END(),\n> +\t};\n> +\n> +\targc = parse_options(argc, argv, prefix, options, exists_usage, 0);\n> +\tif (argc != 1)\n> +\t\tdie(\"refs get requires exactly one reference\");\n\nThis should be translatable. Furthermore, we can probably use `usagef()`\ninstead to have a \"usage:\" prefix instead of \"fatal:\".\n\n> +\trefname = *argv++;\n> +\tif (refs_read_raw_ref(get_main_ref_store(the_repository), refname,\n> +\t\t\t      &oid, &referent, &type, &failure_errno)) {\n> +\t\tdie(\"'%s' - not a valid ref\", refname);\n\nWe should discern by `failure_errno` here. Most importantly, I think we\nshould handle `ENOENT` and `EISDIR` specially to both mean that the\nreference does not exist. So, e.g.:\n\n\tif (refs_read_raw_ref(get_main_ref_store(the_repository), refname,\n\t\t\t      &oid, &referent, &type, &failure_errno)) {\n\t\tif (failure_errno == ENOENT || failure_errno == EISDIR)\n\t\t\tdie(_(\"reference does not exist\"));\n\t\telse\n\t\t\tdie_errno(_(\"failed to look up reference\"));\n\t}\n\n> +\t}\n> +\n> +\tif (type & REF_ISSYMREF) {\n> +\t\tprintf(\"ref: %s\\n\", referent.buf);\n> +\t} else {\n> +\t\tprintf(\"%s\\n\", oid_to_hex(&oid));\n> +\t}\n\nWe can drop the curly braces around single-line bodies.\n\nPatrick\n"},{"id":"527225","messageId":"4FEB2B85-FC32-4076-9DA6-F47AAB096CB0@gmail.com","threadId":"64190","inReplyTo":"aNOQhncjwYCwCaZ3@pks.im","subject":"Re: [GSoC][PATCH] builtin/refs: add 'get' subcommand","fromName":"Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2025-09-24T15:29:11Z","receivedAt":"2025-09-24T15:29:24Z","isPatch":true,"sender":{"key":"ben.knoble@gmail.com","avatar":"https://avatars.githubusercontent.com/u/22802209?v=4"},"body":"\n> Le 24 sept. 2025 à 02:37, Patrick Steinhardt <ps@pks.im> a écrit :\n> \n> ﻿On Tue, Sep 23, 2025 at 02:50:46PM -0700, Junio C Hamano wrote:\n>> Meet Soni <meetsoni3017@gmail.com> writes:\n>> \n>>> While `git-rev-parse(1)` and `git-show-ref(1)` can be used to read\n>>> reference values, they have drawbacks for scripting and discoverability.\n>>> `rev-parse` performs DWIM expansion which is unpredictable for scripts,\n>>> and `show-ref --verify` is difficult to discover and cannot read the\n>>> direct target of a symbolic reference.\n>> \n>> Well \"refs get\" is even harder to discover (it is not even in Git\n>> 2.50's manual that is available everywhere on the net), so difficult\n>> to discover is not a good excuse.  In a sense show-ref was invented\n>> exactly to serve as something like \"refs get\" you are writing, so I\n>> wonder if a better approach is to extend it instead of introducing\n>> a new subcommand in a distant place from it?\n>> \n>> Perhaps \"show-ref --verify --no-deref\" or something that does not\n>> dereference but works directly on a symbolic ref?\n> \n> For now: yes, it's more difficult to discover for sure. But users will\n> adjust over time as they get more familiar with git-refs(1), and from\n> thereon I think it will become significantly easier to discover that\n> subcommand.\n\nI think this goes to perhaps some of my unasked questions: who is the target audience? My experience suggest that most mostly-porcelain users don’t acquire familiarity with scripting commands, so it sounds like we’re talking about script-writers here (and in the commit message).\n\nBut how do we encourage script writers to discover these things? 🤔 Hm. "},{"id":"527233","messageId":"xmqq7bxnn5cj.fsf@gitster.g","threadId":"64190","inReplyTo":"4FEB2B85-FC32-4076-9DA6-F47AAB096CB0@gmail.com","subject":"Re: [GSoC][PATCH] builtin/refs: add 'get' subcommand","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-09-24T17:11:08Z","receivedAt":"2025-09-24T17:11:11Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ben Knoble <ben.knoble@gmail.com> writes:\n\n>>> Perhaps \"show-ref --verify --no-deref\" or something that does not\n>>> dereference but works directly on a symbolic ref?\n>> \n>> For now: yes, it's more difficult to discover for sure. But users will\n>> adjust over time as they get more familiar with git-refs(1), and from\n>> thereon I think it will become significantly easier to discover that\n>> subcommand.\n\nBut unfortunately, that is a tautology, isn't it?  With the same\neffort to advertise git-refs to make it more familiar to the\n\"users\", you can make \"show-ref\" familiar to the same \"users\", and\nproblem solved, without a need to do anything to \"git-refs\"?\n\n> I think this goes to perhaps some of my unasked questions: who is\n> the target audience? My experience suggest that most\n> mostly-porcelain users don’t acquire familiarity with scripting\n> commands, so it sounds like we’re talking about script-writers\n> here (and in the commit message).\n>\n> But how do we encourage script writers to discover these things? 🤔 Hm. \n\nGreat question.  I understand what the patch author is trying to\nachieve (i.e. \"consolidate ref-related functionality into git-refs\",\nwhich is the title of GSoC project [*]), but what are we, as Git\nproject, trying to achive by \"consolidating\"?  I often cannot shake\nthe feeling that it may a make-work job without a clear answer to\nthat question.  Or perhps xkcd.com/927/?\n\nPerhaps the hope is to have a single kitchen sink \"git refs\" command\nthat does anything related to \"refs\", so that they only need to\nlearn this single command (and unlearn all the previous experiences\nthey gained) and after that, they do not have to \"discover\" more\nthings?\n\n\n\n\n[Reference]\n\n* https://summerofcode.withgoogle.com/programs/2025/projects/xVrT5e2q\n"},{"id":"527287","messageId":"aNTgRGeaPajVz1dv@pks.im","threadId":"64190","inReplyTo":"xmqq7bxnn5cj.fsf@gitster.g","subject":"Re: [GSoC][PATCH] builtin/refs: add 'get' subcommand","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-09-25T06:25:08Z","receivedAt":"2025-09-25T06:25:15Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Wed, Sep 24, 2025 at 10:11:08AM -0700, Junio C Hamano wrote:\n> Ben Knoble <ben.knoble@gmail.com> writes:\n> \n> >>> Perhaps \"show-ref --verify --no-deref\" or something that does not\n> >>> dereference but works directly on a symbolic ref?\n> >> \n> >> For now: yes, it's more difficult to discover for sure. But users will\n> >> adjust over time as they get more familiar with git-refs(1), and from\n> >> thereon I think it will become significantly easier to discover that\n> >> subcommand.\n> \n> But unfortunately, that is a tautology, isn't it?  With the same\n> effort to advertise git-refs to make it more familiar to the\n> \"users\", you can make \"show-ref\" familiar to the same \"users\", and\n> problem solved, without a need to do anything to \"git-refs\"?\n\nI don't quite think so. The problem is that we have so many different\ntools that relate to refs, and you have to remember all of them:\n\n  - `git show-refs --verify` to read a single reference, unless it's a\n    symbolic reference.\n\n  - `git symbolic-ref` to read symbolic refs.\n\n  - `git show-refs --exists` to check a reference for existence.\n\n  - `git show-ref` and `git for-each-ref` to list references.\n\n  - `git pack-refs` to optimize references.\n\n  - `git update-refs` to update references`\n\nI'd claim that this is quite hard to remember. So...\n\n> > I think this goes to perhaps some of my unasked questions: who is\n> > the target audience? My experience suggest that most\n> > mostly-porcelain users don’t acquire familiarity with scripting\n> > commands, so it sounds like we’re talking about script-writers\n> > here (and in the commit message).\n> >\n> > But how do we encourage script writers to discover these things? 🤔 Hm. \n> \n> Great question.  I understand what the patch author is trying to\n> achieve (i.e. \"consolidate ref-related functionality into git-refs\",\n> which is the title of GSoC project [*]), but what are we, as Git\n> project, trying to achive by \"consolidating\"?  I often cannot shake\n> the feeling that it may a make-work job without a clear answer to\n> that question.  Or perhps xkcd.com/927/?\n> \n> Perhaps the hope is to have a single kitchen sink \"git refs\" command\n> that does anything related to \"refs\", so that they only need to\n> learn this single command (and unlearn all the previous experiences\n> they gained) and after that, they do not have to \"discover\" more\n> things?\n\n... yes, this is exactly the goal of this exercise. You basically only\nneed to know about the entrypoint git-refs(1). Once you know about it,\nyou don't have to discover all the other commands, as it is now way\neasier to discover what ref-related functionality you have available.\nYou can easily use tab completion (well, once it's wired up), type `git\nrefs -h` to learn about evertyhing refs, and we now have a single\nmanpage that will tell you everything about ref-related use commands.\n\nYou could partially address that problem by providing a gitrefs(5)\nmanpage that gives an overview. And maybe that's still something one\ncould do, also to paint a bit of a broader picture. But documentation is\nonly part of the solution -- with git-refs(1) we get some \"natural\"\ndiscoverability.\n\nThat's also where the \"git refs get\" proposal comes from. Sure, you can\nuse `git show-refs --verify`, potentially with a `--no-dereference` flag\nif you want to read normal refs. But I would claim that this is almost\nimpossible to discover without searching through our manpages.\n\nPatrick\n"},{"id":"527345","messageId":"CALnO6CD0fCF15Vdh7_AtuWiKeXUFbU_kqV=+wAMkmABzchV=Tw@mail.gmail.com","threadId":"64190","inReplyTo":"aNTgRGeaPajVz1dv@pks.im","subject":"Re: [GSoC][PATCH] builtin/refs: add 'get' subcommand","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2025-09-25T18:08:11Z","receivedAt":"2025-09-25T18:08:24Z","isPatch":true,"sender":{"key":"ben.knoble@gmail.com","avatar":"https://avatars.githubusercontent.com/u/22802209?v=4"},"body":"On Thu, Sep 25, 2025 at 2:25 AM Patrick Steinhardt <ps@pks.im> wrote:\n>\n> On Wed, Sep 24, 2025 at 10:11:08AM -0700, Junio C Hamano wrote:\n> > Ben Knoble <ben.knoble@gmail.com> writes:\n> >\n> > >>> Perhaps \"show-ref --verify --no-deref\" or something that does not\n> > >>> dereference but works directly on a symbolic ref?\n> > >>\n> > >> For now: yes, it's more difficult to discover for sure. But users will\n> > >> adjust over time as they get more familiar with git-refs(1), and from\n> > >> thereon I think it will become significantly easier to discover that\n> > >> subcommand.\n> >\n> > But unfortunately, that is a tautology, isn't it?  With the same\n> > effort to advertise git-refs to make it more familiar to the\n> > \"users\", you can make \"show-ref\" familiar to the same \"users\", and\n> > problem solved, without a need to do anything to \"git-refs\"?\n>\n> I don't quite think so. The problem is that we have so many different\n> tools that relate to refs, and you have to remember all of them:\n>\n>   - `git show-refs --verify` to read a single reference, unless it's a\n>     symbolic reference.\n>\n>   - `git symbolic-ref` to read symbolic refs.\n>\n>   - `git show-refs --exists` to check a reference for existence.\n>\n>   - `git show-ref` and `git for-each-ref` to list references.\n>\n>   - `git pack-refs` to optimize references.\n>\n>   - `git update-refs` to update references`\n>\n> I'd claim that this is quite hard to remember. So...\n\nAgreed! To be clear: me asking questions should be taken as support\nfor this exercise :)\n\n> > > I think this goes to perhaps some of my unasked questions: who is\n> > > the target audience? My experience suggest that most\n> > > mostly-porcelain users don’t acquire familiarity with scripting\n> > > commands, so it sounds like we’re talking about script-writers\n> > > here (and in the commit message).\n> > >\n> > > But how do we encourage script writers to discover these things? 🤔 Hm.\n> >\n> > Great question.  I understand what the patch author is trying to\n> > achieve (i.e. \"consolidate ref-related functionality into git-refs\",\n> > which is the title of GSoC project [*]), but what are we, as Git\n> > project, trying to achive by \"consolidating\"?  I often cannot shake\n> > the feeling that it may a make-work job without a clear answer to\n> > that question.  Or perhps xkcd.com/927/?\n> >\n> > Perhaps the hope is to have a single kitchen sink \"git refs\" command\n> > that does anything related to \"refs\", so that they only need to\n> > learn this single command (and unlearn all the previous experiences\n> > they gained) and after that, they do not have to \"discover\" more\n> > things?\n>\n> ... yes, this is exactly the goal of this exercise. You basically only\n> need to know about the entrypoint git-refs(1). Once you know about it,\n> you don't have to discover all the other commands, as it is now way\n> easier to discover what ref-related functionality you have available.\n> You can easily use tab completion (well, once it's wired up), type `git\n> refs -h` to learn about evertyhing refs, and we now have a single\n> manpage that will tell you everything about ref-related use commands.\n\nAh, but here's perhaps my question: tab-completion suggests primarily\nporcelain users over plumbing users, to me ;)\n\nI admit I blur the line quite a bit myself, being unafraid to string\ntogether plumbing commands at a live shell (or make abominations like\ngit-greb [1]).\n\nAt any rate, the target audience need not be precise now. I hope my\nconfusion is clear, though :)\n\n[1]: https://benknoble.github.io/blog/2025/09/17/blame/\n\n> You could partially address that problem by providing a gitrefs(5)\n> manpage that gives an overview. And maybe that's still something one\n> could do, also to paint a bit of a broader picture. But documentation is\n> only part of the solution -- with git-refs(1) we get some \"natural\"\n> discoverability.\n>\n> That's also where the \"git refs get\" proposal comes from. Sure, you can\n> use `git show-refs --verify`, potentially with a `--no-dereference` flag\n> if you want to read normal refs. But I would claim that this is almost\n> impossible to discover without searching through our manpages.\n>\n> Patrick\n\nThis all makes sense to me.\n\n-- \nD. Ben Knoble\n"},{"id":"527349","messageId":"xmqqtt0qfk4c.fsf@gitster.g","threadId":"64190","inReplyTo":"CALnO6CD0fCF15Vdh7_AtuWiKeXUFbU_kqV=+wAMkmABzchV=Tw@mail.gmail.com","subject":"Re: [GSoC][PATCH] builtin/refs: add 'get' subcommand","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-09-25T18:43:47Z","receivedAt":"2025-09-25T18:43:50Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"D. Ben Knoble\" <ben.knoble@gmail.com> writes:\n\n>> I don't quite think so. The problem is that we have so many different\n>> tools that relate to refs, and you have to remember all of them:\n\nYup, but ...\n\n>>   - `git show-refs --verify` to read a single reference, unless it's a\n>>     symbolic reference.\n>>\n>>   - `git symbolic-ref` to read symbolic refs.\n>>\n>>   - `git show-refs --exists` to check a reference for existence.\n>>\n>>   - `git show-ref` and `git for-each-ref` to list references.\n>>\n>>   - `git pack-refs` to optimize references.\n>>\n>>   - `git update-refs` to update references`\n>>\n>> I'd claim that this is quite hard to remember. So...\n>\n> Agreed! To be clear: me asking questions should be taken as support\n> for this exercise :)\n\n... the same thing can be said about subcommands of \"git refs\", all\nof which you have to remember.  I am not sure if this \"everything\nunder \"git refs\" really makes much difference.\n\n>> That's also where the \"git refs get\" proposal comes from. Sure, you can\n>> use `git show-refs --verify`, potentially with a `--no-dereference` flag\n>> if you want to read normal refs. But I would claim that this is almost\n>> impossible to discover without searching through our manpages.\n\nSo?  That still does not indicate adding yet another command to do\nit is the right solution to the discover-ability problem.  Instead\nof shifting and moving things around, reimplementing things to risk\nintroducing new bugs, wouldn't it be more productive to spend effort\non improving the documentation and possibly filling the gaps of\nfeatures?\n\nThanks.\n"}]}