{"thread":{"id":"60645","subject":"[RFC 0/2] Initial changes to support printing all refs","startedAt":"2023-12-21T17:07:21Z","lastAt":"2024-01-04T23:59:25Z","messageCount":27,"participants":["Karthik Nayak","Junio C Hamano","Patrick Steinhardt","Taylor Blau"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"485944","messageId":"20231221170715.110565-1-karthik.188@gmail.com","threadId":"60645","inReplyTo":null,"subject":"[RFC 0/2] Initial changes to support printing all refs","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2023-12-21T17:07:13Z","receivedAt":"2023-12-21T17:07:21Z","isPatch":false,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"With the upcoming introduction of the reftable backend, it becomes ever\nso important to provide the necessary tooling for printing all refs\nassociated with a repository.\n\nWhile regular refs stored within the \"refs/\" namespace are currently\nsupported by multiple commands like git-for-each-ref(1),\ngit-show-ref(1). Neither support printing all the operational refs\nwithin the repository.\n\nThis is crucial because with the reftable backend, all these refs will\nalso move to reftable. It would be necessary to identify all the refs\nthat are stored within the reftable since there is no easy way to do so\notherwise. This is because the reftable itself is a binary format and\nall access will be via git. Unlike the filesystem backend, which allows\naccess directly via the filesystem.\n\nThis patch series is an RFC to discuss the intent and direction to be\ntaken to implement tooling for printing all refs in a repository. The\npatches in this series implement a rather simple way to do this, by\niterating over a static list of operational refs. The drawback of this\napproach is that this could still miss refs in the reftable/files\nbackend which are not in \"refs\" namespace or part of the list. The\npositive being that this is ref backend agnostic.\n\nThe alternate approach would be to patch this inside individual backends\nrespectively, in the reftable backend this is rather simple, since we\nsimply iterate over all refs and not filter for \"refs\" namespace. In the\nfiles backend, this can be done in two ways:\n\n1. static approach: similar to this patch series, the files backend\nwould iterate over a static list of operational refs apart from the\n\"refs\" directory.\n\n2. dynamic approach: iterate over all files in `.git` folder and print\nany refs if encountered. This is rather tedious and error prone, since\nany file could be mistaken for a reference if the content is reference\nlike.\n\nPersonally, I'm leaning towards implementing this functionality inside\nindividual backends respectively, because that would allow the reftable\nbackend to print all its refs while the current approach might miss some\nrefs. But with the files backend, it would be best to still use a static\nlist.\n\nOver this, I'm also curious on what the mailing list thinks about\nexposing this to the client side. Would an `--all` option for\ngit-for-each-ref(1) be sufficient?\n\nKarthik Nayak (2):\n  refs: introduce the `refs_single_ref` function\n  ref-filter: support filtering of operational refs\n\n ref-filter.c | 12 ++++++++++++\n ref-filter.h |  4 +++-\n refs.c       | 26 +++++++++++++++++++++++---\n refs.h       |  5 +++++\n 4 files changed, 43 insertions(+), 4 deletions(-)\n\n-- \n2.43.GIT\n\n"},{"id":"485945","messageId":"20231221170715.110565-2-karthik.188@gmail.com","threadId":"60645","inReplyTo":"20231221170715.110565-1-karthik.188@gmail.com","subject":"[PATCH 1/2] refs: introduce the `refs_single_ref` function","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2023-12-21T17:07:14Z","receivedAt":"2023-12-21T17:07:23Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"We currently provide the functionality to iterate over refs and call a\nspecific callback. This functionality currently supports iterating over\nthe entire \"refs/*\" space or directly the \"HEAD\" ref. This leaves\noperational refs \"ORIG_HEAD\", \"REBASE_HEAD\" and so forth behind.\n\nIn the following commit, we introduce a mechanism to process all the\noperational refs outside the \"refs/*\" space. To do this, we require a\nfunction similar `refs_head_ref`, which can process a single specified\nreference. This commit introduces `refs_single_ref` to fill in that gap.\n\nSigned-off-by: Karthik Nayak <karthik.188@gmail.com>\n---\n refs.c | 12 +++++++++---\n refs.h |  2 ++\n 2 files changed, 11 insertions(+), 3 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 59fea0d44b..cebc5458d3 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1549,18 +1549,24 @@ const char *find_descendant_ref(const char *dirname,\n \treturn NULL;\n }\n \n-int refs_head_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)\n+int refs_single_ref(struct ref_store *refs, const char *refname,\n+\t\t\t\t\teach_ref_fn fn, void *cb_data)\n {\n \tstruct object_id oid;\n \tint flag;\n \n-\tif (refs_resolve_ref_unsafe(refs, \"HEAD\", RESOLVE_REF_READING,\n+\tif (refs_resolve_ref_unsafe(refs, refname, RESOLVE_REF_READING,\n \t\t\t\t    &oid, &flag))\n-\t\treturn fn(\"HEAD\", &oid, flag, cb_data);\n+\t\treturn fn(refname, &oid, flag, cb_data);\n \n \treturn 0;\n }\n \n+int refs_head_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)\n+{\n+\treturn refs_single_ref(refs, \"HEAD\", fn, cb_data);\n+}\n+\n int head_ref(each_ref_fn fn, void *cb_data)\n {\n \treturn refs_head_ref(get_main_ref_store(the_repository), fn, cb_data);\ndiff --git a/refs.h b/refs.h\nindex 4816e46846..e147f13a85 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -324,6 +324,8 @@ typedef int each_repo_ref_fn(struct repository *r,\n  * modifies the reference also returns a nonzero value to immediately\n  * stop the iteration. Returned references are sorted.\n  */\n+int refs_single_ref(struct ref_store *refs, const char *refname,\n+\t\t\t\t\teach_ref_fn fn, void *cb_data);\n int refs_head_ref(struct ref_store *refs,\n \t\t  each_ref_fn fn, void *cb_data);\n int refs_for_each_ref(struct ref_store *refs,\n-- \n2.43.GIT\n\n"},{"id":"485946","messageId":"20231221170715.110565-3-karthik.188@gmail.com","threadId":"60645","inReplyTo":"20231221170715.110565-1-karthik.188@gmail.com","subject":"[PATCH 2/2] ref-filter: support filtering of operational refs","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2023-12-21T17:07:15Z","receivedAt":"2023-12-21T17:07:23Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"With the upcoming introduction of the reftable backend, it becomes ever\nso important to provide the necessary tooling for printing all refs\nassociated with a repository.\n\nWhile regular refs stored within the \"refs/\" namespace are currently\nsupported by multiple commands like git-for-each-ref(1),\ngit-show-ref(1). Neither support printing all the operational refs\nwithin the repository.\n\nThis is crucial because with the reftable backend, all these refs will\nalso move to reftable. It would be necessary to identify all the refs\nthat are stored within the reftable since there is no easy way to do so\notherwise. This is because the reftable itself is a binary format and\nall access will be via git. Unlike the filesystem backend, which allows\naccess directly via the filesystem.\n\nThis commit adds the necessary code to iterate over operational refs\npresent in a repository and provides a new filter flag\n'FILTER_REFS_OPERATIONAL' to iterate over operational refs.\n\nThis flag can now be used to extend existing git commands to print\noperational refs.\n\nSigned-off-by: Karthik Nayak <karthik.188@gmail.com>\n---\n ref-filter.c | 12 ++++++++++++\n ref-filter.h |  4 +++-\n refs.c       | 14 ++++++++++++++\n refs.h       |  3 +++\n 4 files changed, 32 insertions(+), 1 deletion(-)\n\ndiff --git a/ref-filter.c b/ref-filter.c\nindex fdaabb5bb4..307a512c27 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -2756,6 +2756,10 @@ static int filter_ref_kind(struct ref_filter *filter, const char *refname)\n \t    filter->kind == FILTER_REFS_REMOTES ||\n \t    filter->kind == FILTER_REFS_TAGS)\n \t\treturn filter->kind;\n+\n+\tif (filter->kind & FILTER_REFS_OPERATIONAL)\n+\t\treturn filter->kind;\n+\n \treturn ref_kind_from_refname(refname);\n }\n \n@@ -3032,6 +3036,14 @@ static int do_filter_refs(struct ref_filter *filter, unsigned int type, each_ref\n \tif (!filter->kind)\n \t\tdie(\"filter_refs: invalid type\");\n \telse {\n+\t\tsize_t i;\n+\t\tif (filter->kind & FILTER_REFS_OPERATIONAL) {\n+\t\t\tfor (i = 0; i < operational_refs_max; i++) {\n+\t\t\t\trefs_single_ref(get_main_ref_store(the_repository),\n+\t\t\t\t\t\t\t\toperational_refs[i], fn, cb_data);\n+\t\t\t}\n+\t\t}\n+\n \t\t/*\n \t\t * For common cases where we need only branches or remotes or tags,\n \t\t * we only iterate through those refs. If a mix of refs is needed,\ndiff --git a/ref-filter.h b/ref-filter.h\nindex 0ce5af58ab..eec1d29514 100644\n--- a/ref-filter.h\n+++ b/ref-filter.h\n@@ -23,7 +23,9 @@\n #define FILTER_REFS_ALL            (FILTER_REFS_TAGS | FILTER_REFS_BRANCHES | \\\n \t\t\t\t    FILTER_REFS_REMOTES | FILTER_REFS_OTHERS)\n #define FILTER_REFS_DETACHED_HEAD  0x0020\n-#define FILTER_REFS_KIND_MASK      (FILTER_REFS_ALL | FILTER_REFS_DETACHED_HEAD)\n+#define FILTER_REFS_OPERATIONAL    0x0040\n+#define FILTER_REFS_KIND_MASK      (FILTER_REFS_ALL | FILTER_REFS_DETACHED_HEAD | \\\n+\t\t\t\t    FILTER_REFS_OPERATIONAL)\n \n struct atom_value;\n struct ref_sorting;\ndiff --git a/refs.c b/refs.c\nindex cebc5458d3..70f6854301 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -82,6 +82,20 @@ static unsigned char refname_disposition[256] = {\n \t0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 4, 4\n };\n \n+const char *operational_refs[] = {\n+\t\"HEAD\",\n+\t\"ORIG_HEAD\",\n+\t\"REBASE_HEAD\",\n+\t\"REVERT_HEAD\",\n+\t\"CHERRY_PICK_HEAD\",\n+\t\"BISECT_HEAD\",\n+\t\"BISECT_EXPECTED_REV\",\n+\t\"NOTES_MERGE_PARTIAL\",\n+\t\"NOTES_MERGE_REF\",\n+};\n+\n+const int operational_refs_max = ARRAY_SIZE(operational_refs) - 1;\n+\n struct ref_namespace_info ref_namespace[] = {\n \t[NAMESPACE_HEAD] = {\n \t\t.ref = \"HEAD\",\ndiff --git a/refs.h b/refs.h\nindex e147f13a85..b01938a91a 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -15,6 +15,9 @@ int default_ref_storage_format(void);\n int ref_storage_format_by_name(const char *name);\n const char *ref_storage_format_to_name(int ref_storage_format);\n \n+extern const char *operational_refs[];\n+extern const int operational_refs_max;\n+\n /*\n  * Resolve a reference, recursively following symbolic refererences.\n  *\n-- \n2.43.GIT\n\n"},{"id":"485951","messageId":"xmqqzfy3l270.fsf@gitster.g","threadId":"60645","inReplyTo":"20231221170715.110565-3-karthik.188@gmail.com","subject":"Re: [PATCH 2/2] ref-filter: support filtering of operational refs","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-12-21T20:40:03Z","receivedAt":"2023-12-21T20:40:08Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Karthik Nayak <karthik.188@gmail.com> writes:\n\n> With the upcoming introduction of the reftable backend, it becomes ever\n> so important to provide the necessary tooling for printing all refs\n> associated with a repository.\n\nWe have pseudoref (those all caps files outside the refs/ hierarchy)\nas an official term defined in the glossary, and Patrick's reftable\nwork based on Han-Wen's work revealed the need to treat FETCH_HEAD\nand MERGE_HEAD as \"even more pecurilar than pseudorefs\" that need\ndifferent term (tentatively called \"special refs\").  Please avoid\ncoming up with yet another random name \"operational\" without\ndiscussing.\n\nWith a quick look at the table in this patch, \"pseudorefs\" appears\nto be the closest word that people are already familiar with, I\nthink.  A lot more reasonable thing to do may be to scan the\n$GIT_DIR for files whose name satisfy refs.c:is_pseudoref_syntax()\nand list them, instead of having a hardcoded list of these special\nrefs.  In addition, when reftable and other backends that can\nnatively store things outside refs/ hierarchy is in use, they ought\nto know what they have so enumerating these would not be an issue\nfor them without having such a hardcoded table of names.\n\n\n"},{"id":"485978","messageId":"CAOLa=ZRedfBUjukbN8dFT9CZETe4pz1UR+eWfJwORWuMHSk0Rw@mail.gmail.com","threadId":"60645","inReplyTo":"xmqqzfy3l270.fsf@gitster.g","subject":"Re: [PATCH 2/2] ref-filter: support filtering of operational refs","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2023-12-22T14:05:08Z","receivedAt":"2023-12-22T14:05:09Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n> We have pseudoref (those all caps files outside the refs/ hierarchy)\n> as an official term defined in the glossary, and Patrick's reftable\n> work based on Han-Wen's work revealed the need to treat FETCH_HEAD\n> and MERGE_HEAD as \"even more pecurilar than pseudorefs\" that need\n> different term (tentatively called \"special refs\").  Please avoid\n> coming up with yet another random name \"operational\" without\n> discussing.\n>\n\nI totally agree with the term usage and will switch to \"pseudorefs\".\n\n> With a quick look at the table in this patch, \"pseudorefs\" appears\n> to be the closest word that people are already familiar with, I\n> think.  A lot more reasonable thing to do may be to scan the\n> $GIT_DIR for files whose name satisfy refs.c:is_pseudoref_syntax()\n> and list them, instead of having a hardcoded list of these special\n> refs.  In addition, when reftable and other backends that can\n> natively store things outside refs/ hierarchy is in use, they ought\n> to know what they have so enumerating these would not be an issue\n> for them without having such a hardcoded table of names.\n\nThanks for that, I did play around with trying to find files which\ncould be refs in the $GIT_DIR, but the issue is that there will be\nfalse positives. e.g. `COMMIT_EDITMSG` could be confused for a\npseudoref (passes is_pseudoref_syntax()) and it could potentially also\ncontain a commit-ish value.\n\nWhile you're here, I wonder if you have any thoughts on the last block\nof my first mail.\n\n> Over this, I'm also curious on what the mailing list thinks about\n> exposing this to the client side. Would an `--all` option for\n> git-for-each-ref(1) be sufficient?\n>\n\nThanks\n- Karthik\n"},{"id":"486026","messageId":"xmqqsf3oj3u8.fsf@gitster.g","threadId":"60645","inReplyTo":"CAOLa=ZRedfBUjukbN8dFT9CZETe4pz1UR+eWfJwORWuMHSk0Rw@mail.gmail.com","subject":"Re: [PATCH 2/2] ref-filter: support filtering of operational refs","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-12-26T17:01:03Z","receivedAt":"2023-12-26T17:01:14Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Karthik Nayak <karthik.188@gmail.com> writes:\n\n> Thanks for that, I did play around with trying to find files which\n> could be refs in the $GIT_DIR, but the issue is that there will be\n> false positives. e.g. `COMMIT_EDITMSG` could be confused for a\n> pseudoref (passes is_pseudoref_syntax()) and it could potentially also\n> contain a commit-ish value.\n\nIt would not begin with 40-hex, though.  If I were doing this,\nperhaps I'd say we should first split is_pseudoref_syntax() that is\noverly loose into to classes (e.g. \"caps with underscores that ends\nwith HEAD\" and everything else), silently reject false positives\namong the latter class.  Then we rename those that are misnamed\n(there should be only few, like AUTO_MERGE that should be a\npseudoref but named without _HEAD; I do not think of anything that\nends with _HEAD that is not a ref) over time and drop the latter\nclass.\n\n> While you're here, I wonder if you have any thoughts on the last block\n> of my first mail.\n>\n>> Over this, I'm also curious on what the mailing list thinks about\n>> exposing this to the client side. Would an `--all` option for\n>> git-for-each-ref(1) be sufficient?\n\n\"list pseudorefs in addition to things below refs/\"?  Sounds OK to\nme as a feature.\n\nHowever, \"--all\" does not mean that in the context of \"git log\"\nfamily of commands.  Over there, it means \"not just --branches,\n--tags, and --remotes, but everything\" which is still limited below\n\"refs/\".\n\nAs \"git for-each-ref\" takes pattern that is prefix match, e.g.,\n\n    $ git for-each-ref refs/remotes/\n\nshows everything like refs/remotes/origin/main that begins with\nrefs/remotes/, I wonder if\n\n    $ git for-each-ref \"\"\n\nshould mean what you are asking for.  After all, \"git for-each-ref\"\ndoes *not* take \"--branches\" and others like \"git log\" family to\nlimit its operation to subhierarchy of \"refs/\" to begin with.\n\n\n\n\n"},{"id":"486114","messageId":"ZY1PLtPue4PgbhwU@tanuki","threadId":"60645","inReplyTo":"xmqqzfy3l270.fsf@gitster.g","subject":"Re: [PATCH 2/2] ref-filter: support filtering of operational refs","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2023-12-28T10:34:22Z","receivedAt":"2023-12-28T10:34:27Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Thu, Dec 21, 2023 at 12:40:03PM -0800, Junio C Hamano wrote:\n> Karthik Nayak <karthik.188@gmail.com> writes:\n> > With the upcoming introduction of the reftable backend, it becomes ever\n> > so important to provide the necessary tooling for printing all refs\n> > associated with a repository.\n> \n> We have pseudoref (those all caps files outside the refs/ hierarchy)\n> as an official term defined in the glossary, and Patrick's reftable\n> work based on Han-Wen's work revealed the need to treat FETCH_HEAD\n> and MERGE_HEAD as \"even more pecurilar than pseudorefs\" that need\n> different term (tentatively called \"special refs\").  Please avoid\n> coming up with yet another random name \"operational\" without\n> discussing.\n> \n> With a quick look at the table in this patch, \"pseudorefs\" appears\n> to be the closest word that people are already familiar with, I\n> think.\n\nAgreed, this thought also crossed my mind while reading through the\npatches.\n\n> A lot more reasonable thing to do may be to scan the\n> $GIT_DIR for files whose name satisfy refs.c:is_pseudoref_syntax()\n> and list them, instead of having a hardcoded list of these special\n> refs.\n\nAgreed, as well. Despite the reasons mentioned below, the chance for\nsuch a hardcoded list to grow stale is also quite high. And while it\ncertainly feels very hacky to iterate over the files one by one and\ncheck for each of them whether it could be a pseudo ref, it is the best\nwe can do to dynamically detect any such reference.\n\nOne interesting question is how we should treat files that look like a\npseudoref, but which really aren't. I'm not aware of any such files\nwritten by Git itself, but it could certainly be that a user wrote such\na file into the repository manually. But given that we're adding new\nbehaviour that will be opt-in (e.g. via a new switch) I'd rather err on\nthe side of caution and mark any such file as broken instead of silently\nignoring them.\n\n> In addition, when reftable and other backends that can\n> natively store things outside refs/ hierarchy is in use, they ought\n> to know what they have so enumerating these would not be an issue\n> for them without having such a hardcoded table of names.\n\nYup, for the reftable we don't have the issue of \"How do we detect refs\ndynamically\" at all. So I would love for there to be a way to print all\nrefs in the refdb, regardless of whether they start with `refs/` or look\nlike a pseudoref or whatever else. Otherwise it wouldn't be possible for\na user to delete anything stored in the refdb that may have a funny\nname, be it intentionally, by accident or due to a bug.\n\nIn the reftable backend, the ref iterator's `_advance()` function has a\nhardcoded `starts_with(refname, \"refs/\")` check. If false, then we'd\nskip the ref in order to retain the same behaviour that the files\nbackend has. So maybe what we should be doing is to introduce a new flag\n`DO_FOR_EACH_ALL_REFS` and expose it via git-for-each-ref(1) or\ngit-show-ref(1). So:\n\n  - For the reftable backend we'd skip the `starts_with()` check and\n    simply return all refs.\n\n  - For the files backend we'd also iterate through all files in\n    $GIT_DIR and check whether they are pseudoref-like.\n\nPatrick\n"},{"id":"486195","messageId":"CAOLa=ZTPxWXnZ8kpBB7=cybNfdEv6d6O37Em7Vpmcw=enpY1_w@mail.gmail.com","threadId":"60645","inReplyTo":"xmqqsf3oj3u8.fsf@gitster.g","subject":"Re: [PATCH 2/2] ref-filter: support filtering of operational refs","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2024-01-02T15:18:48Z","receivedAt":"2024-01-02T15:18:50Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n>\n> It would not begin with 40-hex, though.  If I were doing this,\n> perhaps I'd say we should first split is_pseudoref_syntax() that is\n> overly loose into to classes (e.g. \"caps with underscores that ends\n> with HEAD\" and everything else), silently reject false positives\n> among the latter class.  Then we rename those that are misnamed\n> (there should be only few, like AUTO_MERGE that should be a\n> pseudoref but named without _HEAD; I do not think of anything that\n> ends with _HEAD that is not a ref) over time and drop the latter\n> class.\n>\n\nI agree about checking the contents of the files to filter out false\npositives around the filenames. Alright, this seems like a good way to\ngo.\n\nSummarizing, we'll change `is_pseudoref_syntax()` to\n1. Check for filename to be UPPERCASE including '-', '_'.\n   a. If the filename ends with _HEAD, we return as positive\n   b. Else check the file content for SHA1/SHA256 hex\n\nThis still leaves out HEAD ref, which is not a pseudo ref (since it can\nbe a symref at times). I'll figure out something there.\n\n>\n>> While you're here, I wonder if you have any thoughts on the last block\n>> of my first mail.\n>>\n>>> Over this, I'm also curious on what the mailing list thinks about\n>>> exposing this to the client side. Would an `--all` option for\n>>> git-for-each-ref(1) be sufficient?\n>\n> \"list pseudorefs in addition to things below refs/\"?  Sounds OK to\n> me as a feature.\n>\n> However, \"--all\" does not mean that in the context of \"git log\"\n> family of commands.  Over there, it means \"not just --branches,\n> --tags, and --remotes, but everything\" which is still limited below\n> \"refs/\".\n>\n\nGood point, I agree, usage of \"--all\" would clash here.\n\n> As \"git for-each-ref\" takes pattern that is prefix match, e.g.,\n>\n>     $ git for-each-ref refs/remotes/\n>\n> shows everything like refs/remotes/origin/main that begins with\n> refs/remotes/, I wonder if\n>\n>     $ git for-each-ref \"\"\n>\n> should mean what you are asking for.  After all, \"git for-each-ref\"\n> does *not* take \"--branches\" and others like \"git log\" family to\n> limit its operation to subhierarchy of \"refs/\" to begin with.\n\nBut I don't think using an empty pattern is the best way to go forward.\nThis would break the pattern matching feature. For instance, what if the\nuser wanted to print all refs, but pattern match \"*_HEAD\"?\n\nWould that be\n\n      $ git for-each-ref \"\" \"*_HEAD\"\n\nI think this would be confusing, since the first pattern is now acting\nas an option, since its not really filtering rather its changing the\nsearch space.\n\nMaybe \"--all-refs\" or \"--all-ref-types\" instead?\n"},{"id":"486196","messageId":"CAOLa=ZSzmmLTNRX_muNGP7tG65mkpKXfUG9sbNZBL3qv930B8g@mail.gmail.com","threadId":"60645","inReplyTo":"ZY1PLtPue4PgbhwU@tanuki","subject":"Re: [PATCH 2/2] ref-filter: support filtering of operational refs","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2024-01-02T15:23:48Z","receivedAt":"2024-01-02T15:23:50Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"Patrick Steinhardt <ps@pks.im> writes:\n> One interesting question is how we should treat files that look like a\n> pseudoref, but which really aren't. I'm not aware of any such files\n> written by Git itself, but it could certainly be that a user wrote such\n> a file into the repository manually. But given that we're adding new\n> behaviour that will be opt-in (e.g. via a new switch) I'd rather err on\n> the side of caution and mark any such file as broken instead of silently\n> ignoring them.\n>\n\nThis is definitely tricky, especially since something like\n`COMMIT_EDITMSG` passes the `is_pseudoref_syntax()` check and could\nsimply contain a commit-ish object ID. Here identifying that this is not\na pseudoref is hard when it satisfies both:\n1. The general pseudoref syntax\n2. Contains the expected file content type\n\n>\n> Yup, for the reftable we don't have the issue of \"How do we detect refs\n> dynamically\" at all. So I would love for there to be a way to print all\n> refs in the refdb, regardless of whether they start with `refs/` or look\n> like a pseudoref or whatever else. Otherwise it wouldn't be possible for\n> a user to delete anything stored in the refdb that may have a funny\n> name, be it intentionally, by accident or due to a bug.\n>\n> In the reftable backend, the ref iterator's `_advance()` function has a\n> hardcoded `starts_with(refname, \"refs/\")` check. If false, then we'd\n> skip the ref in order to retain the same behaviour that the files\n> backend has. So maybe what we should be doing is to introduce a new flag\n> `DO_FOR_EACH_ALL_REFS` and expose it via git-for-each-ref(1) or\n> git-show-ref(1). So:\n>\n>   - For the reftable backend we'd skip the `starts_with()` check and\n>     simply return all refs.\n>\n>   - For the files backend we'd also iterate through all files in\n>     $GIT_DIR and check whether they are pseudoref-like.\n>\n\nThis makes sense to me and is along what I was considering for the\ndynamic approach, thanks for writing it down, clarifies my thoughts.\n"},{"id":"486200","messageId":"xmqq4jfvfzo0.fsf@gitster.g","threadId":"60645","inReplyTo":"CAOLa=ZTPxWXnZ8kpBB7=cybNfdEv6d6O37Em7Vpmcw=enpY1_w@mail.gmail.com","subject":"Re: [PATCH 2/2] ref-filter: support filtering of operational refs","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2024-01-02T16:49:51Z","receivedAt":"2024-01-02T16:49:58Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Karthik Nayak <karthik.188@gmail.com> writes:\n\n>> As \"git for-each-ref\" takes pattern that is prefix match, e.g.,\n>>\n>>     $ git for-each-ref refs/remotes/\n>>\n>> shows everything like refs/remotes/origin/main that begins with\n>> refs/remotes/, I wonder if\n>>\n>>     $ git for-each-ref \"\"\n>>\n>> should mean what you are asking for.  After all, \"git for-each-ref\"\n>> does *not* take \"--branches\" and others like \"git log\" family to\n>> limit its operation to subhierarchy of \"refs/\" to begin with.\n>\n> But I don't think using an empty pattern is the best way to go forward.\n> This would break the pattern matching feature. For instance, what if the\n> user wanted to print all refs, but pattern match \"*_HEAD\"?\n>\n> Would that be\n>\n>       $ git for-each-ref \"\" \"*_HEAD\"\n\nBecause you do not omit the leading hierarchy when using globs:\n\n    $ git for-each-ref v2.4\\?.\\* ;# nothing\n    $ git for-each-ref tags/v2.4\\?.\\* ;# nothing\n    $ git for-each-ref refs/tags/v2.4\\?.\\* ;# gives tags in v2.40 and onwards\n\nI would expect that it would be more like\n\n\t$ git for-each-ref \"*_HEAD\"\n\nAnd because you can have two or more patterns, e.g.,\n\n    $ git for-each-ref refs/tags/v2.4\\?.\\* refs/heads/m\\*\n\nto get those recent tags and branches whose name begins with 'm', I\nwould expect your\n\n    $ git for-each-ref \"\" \"*_HEAD\"\n\nwould probably be equivalent to\n\n    $ git for-each-ref \"\"\n\n"},{"id":"486204","messageId":"ZZRaOhK869S1Sg1h@nand.local","threadId":"60645","inReplyTo":"CAOLa=ZTPxWXnZ8kpBB7=cybNfdEv6d6O37Em7Vpmcw=enpY1_w@mail.gmail.com","subject":"Re: [PATCH 2/2] ref-filter: support filtering of operational refs","fromName":"Taylor Blau","fromEmail":"me@ttaylorr.com","sentAt":"2024-01-02T18:47:22Z","receivedAt":"2024-01-02T18:47:24Z","isPatch":true,"sender":{"key":"me@ttaylorr.com","avatar":"https://avatars.githubusercontent.com/u/301000140?v=4"},"body":"On Tue, Jan 02, 2024 at 07:18:48AM -0800, Karthik Nayak wrote:\n> > As \"git for-each-ref\" takes pattern that is prefix match, e.g.,\n> >\n> >     $ git for-each-ref refs/remotes/\n> >\n> > shows everything like refs/remotes/origin/main that begins with\n> > refs/remotes/, I wonder if\n> >\n> >     $ git for-each-ref \"\"\n> >\n> > should mean what you are asking for.  After all, \"git for-each-ref\"\n> > does *not* take \"--branches\" and others like \"git log\" family to\n> > limit its operation to subhierarchy of \"refs/\" to begin with.\n>\n> But I don't think using an empty pattern is the best way to go forward.\n> This would break the pattern matching feature. For instance, what if the\n> user wanted to print all refs, but pattern match \"*_HEAD\"?\n>\n> Would that be\n>\n>       $ git for-each-ref \"\" \"*_HEAD\"\n>\n> I think this would be confusing, since the first pattern is now acting\n> as an option, since its not really filtering rather its changing the\n> search space.\n>\n> Maybe \"--all-refs\" or \"--all-ref-types\" instead?\n\nI tend to agree that the special empty pattern would be a good shorthand\nfor listing all references underneath refs/, including any top-level\npsuedo-refs.\n\nBut I don't think that I quite follow what Karthik is saying here.\nfor-each-ref returns the union of references that match the given\npattern(s), not their intersection. So if you wanted to list just the\npsudo-refs ending in '_HEAD', you'd do:\n\n  $ git for-each-ref \"*_HEAD\"\n\nI think if you wanted to list all pseudo-refs, calling the option\n`--pseudo-refs` seems reasonable. But if you want to list some subset of\npsueod-refs matching a given pattern, you should specify that pattern\ndirectly.\n\nThanks,\nTaylor\n"},{"id":"486205","messageId":"ZZRayoauM6s5XUFR@nand.local","threadId":"60645","inReplyTo":"ZY1PLtPue4PgbhwU@tanuki","subject":"Re: [PATCH 2/2] ref-filter: support filtering of operational refs","fromName":"Taylor Blau","fromEmail":"me@ttaylorr.com","sentAt":"2024-01-02T18:49:46Z","receivedAt":"2024-01-02T18:49:48Z","isPatch":true,"sender":{"key":"me@ttaylorr.com","avatar":"https://avatars.githubusercontent.com/u/301000140?v=4"},"body":"On Thu, Dec 28, 2023 at 11:34:22AM +0100, Patrick Steinhardt wrote:\n> One interesting question is how we should treat files that look like a\n> pseudoref, but which really aren't. I'm not aware of any such files\n> written by Git itself, but it could certainly be that a user wrote such\n> a file into the repository manually. But given that we're adding new\n> behaviour that will be opt-in (e.g. via a new switch) I'd rather err on\n> the side of caution and mark any such file as broken instead of silently\n> ignoring them.\n\nI probably wouldn't spend a ton of time worrying about this personally.\nWithout additional information, I think it's impossible for us to\ndetermine a-priori whether or not a file underneath $GIT_DIR should be\ninterpreted as a pseudo-ref or not.\n\nI agree with your reasoning that since this is opt-in via a new\ncommand-line flag, that we're probably OK here enumerating the files in\n$GIT_DIR, and printing out the ones that look like pseudo-refs.\n\nThanks,\nTaylor\n"},{"id":"486248","messageId":"ZZUgUUlB8A-rhep5@tanuki","threadId":"60645","inReplyTo":"ZZRaOhK869S1Sg1h@nand.local","subject":"Re: [PATCH 2/2] ref-filter: support filtering of operational refs","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2024-01-03T08:52:33Z","receivedAt":"2024-01-03T08:52:39Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Tue, Jan 02, 2024 at 01:47:22PM -0500, Taylor Blau wrote:\n> On Tue, Jan 02, 2024 at 07:18:48AM -0800, Karthik Nayak wrote:\n> > > As \"git for-each-ref\" takes pattern that is prefix match, e.g.,\n> > >\n> > >     $ git for-each-ref refs/remotes/\n> > >\n> > > shows everything like refs/remotes/origin/main that begins with\n> > > refs/remotes/, I wonder if\n> > >\n> > >     $ git for-each-ref \"\"\n> > >\n> > > should mean what you are asking for.  After all, \"git for-each-ref\"\n> > > does *not* take \"--branches\" and others like \"git log\" family to\n> > > limit its operation to subhierarchy of \"refs/\" to begin with.\n> >\n> > But I don't think using an empty pattern is the best way to go forward.\n> > This would break the pattern matching feature. For instance, what if the\n> > user wanted to print all refs, but pattern match \"*_HEAD\"?\n> >\n> > Would that be\n> >\n> >       $ git for-each-ref \"\" \"*_HEAD\"\n> >\n> > I think this would be confusing, since the first pattern is now acting\n> > as an option, since its not really filtering rather its changing the\n> > search space.\n> >\n> > Maybe \"--all-refs\" or \"--all-ref-types\" instead?\n> \n> I tend to agree that the special empty pattern would be a good shorthand\n> for listing all references underneath refs/, including any top-level\n> psuedo-refs.\n> \n> But I don't think that I quite follow what Karthik is saying here.\n> for-each-ref returns the union of references that match the given\n> pattern(s), not their intersection. So if you wanted to list just the\n> psudo-refs ending in '_HEAD', you'd do:\n> \n>   $ git for-each-ref \"*_HEAD\"\n> \n> I think if you wanted to list all pseudo-refs, calling the option\n> `--pseudo-refs` seems reasonable. But if you want to list some subset of\n> psueod-refs matching a given pattern, you should specify that pattern\n> directly.\n\nWhere I think this proposal falls short is if you have refs outside of\nthe \"refs/\" hierarchy. Granted, this is nothing that should usually\nhappen nowadays. But I think we should safeguard us for the future:\n\n  - There may be bugs in the reftable backend that allow for such refs\n    to be created.\n\n  - We may even eventually end up saying that it's valid for refs to not\n    start with \"refs/\". I consider this to be mostly an artifact of how\n    the files backend works, so it is not entirely unreasonable for us\n    to eventually lift the restriction for the reftable backend.\n\nI do not want to push for the second bullet point anytime soon, nor do I\nhave any plans to do so in the future. But regardless of that I would\nreally love to have a way to ask the ref backend for _any_ reference\nthat it knows of, regardless of its prefix. Otherwise it becomes next to\nimpossible for a user to learn about what the reftable binary-format\nactually contains. So I think that the current focus on pseudo-refs is\ntoo short-sighted, and would want to aim for a more complete solution to\nthis problem.\n\nThis could be in the form of a `--all-refs` flag that gets translated\ninto a new `DO_FOR_EACH_REF_ALL_REFS` bit, which would indicate to the\nref backend to also enumerate refs outside of the \"refs/\" hierarchy.\nThis is orthogonal to the already existing `--all` pseudo-opt, because\n`--all` would only ever enumerate refs inside of the \"refs/\" hierarchy.\n\nPatrick\n"},{"id":"486250","messageId":"CAOLa=ZS4OOAmyRvf4HH-c_3GvnVkh6zS2kD3hEhRZ7NZT-rvyA@mail.gmail.com","threadId":"60645","inReplyTo":"ZZUgUUlB8A-rhep5@tanuki","subject":"Re: [PATCH 2/2] ref-filter: support filtering of operational refs","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2024-01-03T10:22:47Z","receivedAt":"2024-01-03T10:22:49Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"Patrick Steinhardt <ps@pks.im> writes:\n\n> On Tue, Jan 02, 2024 at 01:47:22PM -0500, Taylor Blau wrote:\n>> On Tue, Jan 02, 2024 at 07:18:48AM -0800, Karthik Nayak wrote:\n>> > > As \"git for-each-ref\" takes pattern that is prefix match, e.g.,\n>> > >\n>> > >     $ git for-each-ref refs/remotes/\n>> > >\n>> > > shows everything like refs/remotes/origin/main that begins with\n>> > > refs/remotes/, I wonder if\n>> > >\n>> > >     $ git for-each-ref \"\"\n>> > >\n>> > > should mean what you are asking for.  After all, \"git for-each-ref\"\n>> > > does *not* take \"--branches\" and others like \"git log\" family to\n>> > > limit its operation to subhierarchy of \"refs/\" to begin with.\n>> >\n>> > But I don't think using an empty pattern is the best way to go forward.\n>> > This would break the pattern matching feature. For instance, what if the\n>> > user wanted to print all refs, but pattern match \"*_HEAD\"?\n>> >\n>> > Would that be\n>> >\n>> >       $ git for-each-ref \"\" \"*_HEAD\"\n>> >\n>> > I think this would be confusing, since the first pattern is now acting\n>> > as an option, since its not really filtering rather its changing the\n>> > search space.\n>> >\n>> > Maybe \"--all-refs\" or \"--all-ref-types\" instead?\n>>\n>> I tend to agree that the special empty pattern would be a good shorthand\n>> for listing all references underneath refs/, including any top-level\n>> psuedo-refs.\n>>\n>> But I don't think that I quite follow what Karthik is saying here.\n>> for-each-ref returns the union of references that match the given\n>> pattern(s), not their intersection. So if you wanted to list just the\n>> psudo-refs ending in '_HEAD', you'd do:\n>>\n>>   $ git for-each-ref \"*_HEAD\"\n>>\n>> I think if you wanted to list all pseudo-refs, calling the option\n>> `--pseudo-refs` seems reasonable. But if you want to list some subset of\n>> psueod-refs matching a given pattern, you should specify that pattern\n>> directly.\n>\n> Where I think this proposal falls short is if you have refs outside of\n> the \"refs/\" hierarchy. Granted, this is nothing that should usually\n> happen nowadays. But I think we should safeguard us for the future:\n>\n>   - There may be bugs in the reftable backend that allow for such refs\n>     to be created.\n>\n>   - We may even eventually end up saying that it's valid for refs to not\n>     start with \"refs/\". I consider this to be mostly an artifact of how\n>     the files backend works, so it is not entirely unreasonable for us\n>     to eventually lift the restriction for the reftable backend.\n>\n> I do not want to push for the second bullet point anytime soon, nor do I\n> have any plans to do so in the future. But regardless of that I would\n> really love to have a way to ask the ref backend for _any_ reference\n> that it knows of, regardless of its prefix. Otherwise it becomes next to\n> impossible for a user to learn about what the reftable binary-format\n> actually contains. So I think that the current focus on pseudo-refs is\n> too short-sighted, and would want to aim for a more complete solution to\n> this problem.\n>\n> This could be in the form of a `--all-refs` flag that gets translated\n> into a new `DO_FOR_EACH_REF_ALL_REFS` bit, which would indicate to the\n> ref backend to also enumerate refs outside of the \"refs/\" hierarchy.\n> This is orthogonal to the already existing `--all` pseudo-opt, because\n> `--all` would only ever enumerate refs inside of the \"refs/\" hierarchy.\n>\n> Patrick\n\nThanks Patrick. I think the confusion was because I was referring to add\na new command to print all refs, meaning all refs including the ones\noutside the \"refs/\" folder.\n\nThe confusion was that I thought Junio was referring to using\n\n    $ git for-each-ref \"\"\n\nto print all refs under $GIT_DIR, while he was actually talking about\n\"$GIT_DIR/refs/\" directory.\n\nSo to loop back, I'm suggesting to add `--all-refs` to print all the\nrefs under $GIT_DIR. This would include refs traditionally found under\n\"refs/\" and other refs like pseudo refs, HEAD and perhaps user created\nrefs under $GIT_DIR.\n"},{"id":"486253","messageId":"xmqqwmsqbhyt.fsf@gitster.g","threadId":"60645","inReplyTo":"CAOLa=ZS4OOAmyRvf4HH-c_3GvnVkh6zS2kD3hEhRZ7NZT-rvyA@mail.gmail.com","subject":"Re: [PATCH 2/2] ref-filter: support filtering of operational refs","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2024-01-03T14:38:02Z","receivedAt":"2024-01-03T14:38:08Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Karthik Nayak <karthik.188@gmail.com> writes:\n\n> The confusion was that I thought Junio was referring to using\n>\n>     $ git for-each-ref \"\"\n>\n> to print all refs under $GIT_DIR, while he was actually talking about\n> \"$GIT_DIR/refs/\" directory.\n\nI do not think you misunderstood me here, though.  \n\nWhen you have your master branch (refs/heads/master), your v1.0 tag\n(refs/tags/v1.0), and the usual pseudorefs, giving \"refs\" to \"git\nfor-each-ref\" would yield refs/heads/master and refs/tags/v1.0 but\nnot HEAD and others, simply because the pattern \"refs\" in\n\n    $ git for-each-ref \"refs\"\n\nworks as a hierarchy prefix match.  You give \"refs/heads\" and you\nget only your master branch but not tags or HEAD in such a\nrepository.  As a natural extension to that behaviour, an empty\nstring as a hierarchy prefix that matches everything would work\nwell: you'd get HEAD, refs/heads/master, and refs/tags/v1.0 as an\nempty prefix would cover all of the hiearchies these three refs (and\npseudorefs if you had ORIG_HEAD and MERGE_HEAD there) live in.\n\nIn any case, it is not a very much interesting to define the syntax\nto tell for-each-ref not to limit itself under \"refs/\".  My point\nwas that you do not need a special option for that, as shown above.\n\nWhat is more interesting is what to do with refs that are specific\nto other worktrees, e.g.\n\n    $ git rev-parse \"worktrees/$name/refs/bisect/bad\"\n\nwould currently let you peek into (and worse yet, muck with, if you\nreally wanted to, with something like \"git update-ref\") refs that\nshould be only visible in another worktree.  Should for-each-ref and\nfriends learn a way to iterate over them?  I have no answer to that\nquestion.\n\n"},{"id":"486254","messageId":"ZZWBLafB3pIlZqpw@nand.local","threadId":"60645","inReplyTo":"ZZUgUUlB8A-rhep5@tanuki","subject":"Re: [PATCH 2/2] ref-filter: support filtering of operational refs","fromName":"Taylor Blau","fromEmail":"me@ttaylorr.com","sentAt":"2024-01-03T15:45:49Z","receivedAt":"2024-01-03T15:45:52Z","isPatch":true,"sender":{"key":"me@ttaylorr.com","avatar":"https://avatars.githubusercontent.com/u/301000140?v=4"},"body":"On Wed, Jan 03, 2024 at 09:52:33AM +0100, Patrick Steinhardt wrote:\n> > I tend to agree that the special empty pattern would be a good shorthand\n> > for listing all references underneath refs/, including any top-level\n> > psuedo-refs.\n> >\n> > But I don't think that I quite follow what Karthik is saying here.\n> > for-each-ref returns the union of references that match the given\n> > pattern(s), not their intersection. So if you wanted to list just the\n> > psudo-refs ending in '_HEAD', you'd do:\n> >\n> >   $ git for-each-ref \"*_HEAD\"\n> >\n> > I think if you wanted to list all pseudo-refs, calling the option\n> > `--pseudo-refs` seems reasonable. But if you want to list some subset of\n> > psueod-refs matching a given pattern, you should specify that pattern\n> > directly.\n>\n> Where I think this proposal falls short is if you have refs outside of\n> the \"refs/\" hierarchy. Granted, this is nothing that should usually\n> happen nowadays. But I think we should safeguard us for the future:\n\nHmm. Maybe I misspoke, but I was thinking that `--pseudo-refs` would\nimply that we list all references (regardless of whether they appear in\nthe top-level refs/ hierarchy). But perhaps I'm misunderstanding what\nyou're trying to accomplish here.\n\nThanks,\nTaylor\n"},{"id":"486255","messageId":"ZZWCXFghtql4i4YE@tanuki","threadId":"60645","inReplyTo":"xmqqwmsqbhyt.fsf@gitster.g","subject":"Re: [PATCH 2/2] ref-filter: support filtering of operational refs","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2024-01-03T15:50:52Z","receivedAt":"2024-01-03T15:50:59Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Wed, Jan 03, 2024 at 06:38:02AM -0800, Junio C Hamano wrote:\n> Karthik Nayak <karthik.188@gmail.com> writes:\n> \n> > The confusion was that I thought Junio was referring to using\n> >\n> >     $ git for-each-ref \"\"\n> >\n> > to print all refs under $GIT_DIR, while he was actually talking about\n> > \"$GIT_DIR/refs/\" directory.\n> \n> I do not think you misunderstood me here, though.  \n> \n> When you have your master branch (refs/heads/master), your v1.0 tag\n> (refs/tags/v1.0), and the usual pseudorefs, giving \"refs\" to \"git\n> for-each-ref\" would yield refs/heads/master and refs/tags/v1.0 but\n> not HEAD and others, simply because the pattern \"refs\" in\n> \n>     $ git for-each-ref \"refs\"\n> \n> works as a hierarchy prefix match.  You give \"refs/heads\" and you\n> get only your master branch but not tags or HEAD in such a\n> repository.  As a natural extension to that behaviour, an empty\n> string as a hierarchy prefix that matches everything would work\n> well: you'd get HEAD, refs/heads/master, and refs/tags/v1.0 as an\n> empty prefix would cover all of the hiearchies these three refs (and\n> pseudorefs if you had ORIG_HEAD and MERGE_HEAD there) live in.\n> \n> In any case, it is not a very much interesting to define the syntax\n> to tell for-each-ref not to limit itself under \"refs/\".  My point\n> was that you do not need a special option for that, as shown above.\n\nI think you're just stating that \"it's possible, but not necessarily a\ngood idea\" (let me know if I'm misinterpreting, I'm not quite sure\nwhether I read this correctly). Anyway, let me add my 2c here, even\nthough it may ultimately be completely moot.\n\nThe downside of an empty prefix is that you wouldn't be able to filter\nrefs outside of the \"refs/\" hierarchy in case we'd use the empty prefix.\nA better alternative would be to use \"/\" as an indicator that you want\nto list refs outside of \"refs/\". That'd allow for more flexible queries:\n\n  - \"/\" prints all refs and pseudo refs, even those outside of the\n    \"refs/\" hierarchy.\n\n  - \"/refs\" prints your normal refs.\n\n  - \"/something/else\" prints refs in \"$GIT_DIR/something/else\".\n\nI'm not sure whether it's a better idea than using a flag and I'd assume\nthat the implementation would be more complex in that case because the\nrespective backends would need to special-case leading slashes.\n\nSo in the end I'm still in the camp that a flag is likely a better idea.\n\n> What is more interesting is what to do with refs that are specific\n> to other worktrees, e.g.\n> \n>     $ git rev-parse \"worktrees/$name/refs/bisect/bad\"\n> \n> would currently let you peek into (and worse yet, muck with, if you\n> really wanted to, with something like \"git update-ref\") refs that\n> should be only visible in another worktree.  Should for-each-ref and\n> friends learn a way to iterate over them?  I have no answer to that\n> question.\n\nThat's a good question indeed. I could certainly see an argument that\nthere should be the possibility to list them to get an allcompassing\nview of the repository's refs. It's sure going to get more complex like\nthat though (which is not a good argument not to do this).\n\nCurrently, per-worktree refs are implemented as quasi-separate ref\nstores (see `get_worktree_ref_store()`), and the reffiles backend will\nindeed use completely separate stacks for each worktree. So ultimately\nit makes me think that this is higher-level logic that the ref store\nbackend wouldn't need to be aware of, but that git-for-each-ref(1) or\nrelated commands would need to handle.\n\nSo I'm not quite sure whether we should solve all these related problems\nat once. If we were to implement these features via a flag then I could\nsee us using a value-flag with which you can control what exactly should\nbe included in the listing. So something like:\n\n  - `--with-refs=repository` includes all refs of the current\n    repository.\n\n  - `--with-refs=worktrees` includes refs of all worktrees.\n\nI dunno. I feel like I start to overthink this.\n\nPatrick\n"},{"id":"486256","messageId":"ZZWCxIHf9ySEOWEJ@tanuki","threadId":"60645","inReplyTo":"ZZWBLafB3pIlZqpw@nand.local","subject":"Re: [PATCH 2/2] ref-filter: support filtering of operational refs","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2024-01-03T15:52:36Z","receivedAt":"2024-01-03T15:52:41Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Wed, Jan 03, 2024 at 10:45:49AM -0500, Taylor Blau wrote:\n> On Wed, Jan 03, 2024 at 09:52:33AM +0100, Patrick Steinhardt wrote:\n> > > I tend to agree that the special empty pattern would be a good shorthand\n> > > for listing all references underneath refs/, including any top-level\n> > > psuedo-refs.\n> > >\n> > > But I don't think that I quite follow what Karthik is saying here.\n> > > for-each-ref returns the union of references that match the given\n> > > pattern(s), not their intersection. So if you wanted to list just the\n> > > psudo-refs ending in '_HEAD', you'd do:\n> > >\n> > >   $ git for-each-ref \"*_HEAD\"\n> > >\n> > > I think if you wanted to list all pseudo-refs, calling the option\n> > > `--pseudo-refs` seems reasonable. But if you want to list some subset of\n> > > psueod-refs matching a given pattern, you should specify that pattern\n> > > directly.\n> >\n> > Where I think this proposal falls short is if you have refs outside of\n> > the \"refs/\" hierarchy. Granted, this is nothing that should usually\n> > happen nowadays. But I think we should safeguard us for the future:\n> \n> Hmm. Maybe I misspoke, but I was thinking that `--pseudo-refs` would\n> imply that we list all references (regardless of whether they appear in\n> the top-level refs/ hierarchy). But perhaps I'm misunderstanding what\n> you're trying to accomplish here.\n\nAh, okay. I think in that case it's simply a misunderstanding. To me a\npseudo-ref only includes refs that match `is_pseudoref_syntax()`, so\nthings like \"HEAD\", \"ORIG_HEAD\" or \"MERGE_HEAD\". So with that\nunderstanding, a ref \"something/outside/refs\" would not be included,\nbut I'd very much like to see it listed.\n\nPatrick\n"},{"id":"486257","messageId":"xmqqsf3ebe1l.fsf@gitster.g","threadId":"60645","inReplyTo":"ZZWCXFghtql4i4YE@tanuki","subject":"Re: [PATCH 2/2] ref-filter: support filtering of operational refs","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2024-01-03T16:02:46Z","receivedAt":"2024-01-03T16:02:55Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Patrick Steinhardt <ps@pks.im> writes:\n\n> The downside of an empty prefix is that you wouldn't be able to filter\n> refs outside of the \"refs/\" hierarchy in case we'd use the empty prefix.\n> A better alternative would be to use \"/\" as an indicator that you want\n> to list refs outside of \"refs/\". That'd allow for more flexible queries:\n>\n>   - \"/\" prints all refs and pseudo refs, even those outside of the\n>     \"refs/\" hierarchy.\n>\n>   - \"/refs\" prints your normal refs.\n>\n>   - \"/something/else\" prints refs in \"$GIT_DIR/something/else\".\n\nI do not get this at all, sorry.  What makes your \"/\" cover \"refs/\"\nbut not \"something/\"?  Unless you have some rule that special cases \n\"/\" to apply the \"hierarchy prefix\" matching rule unevenly, that is\nnot possible.  So you can easily lose the \"/\" all of your above\npatterns share, go back to what I showed, and apply the morally\nequivalent special case to an empty prefix and you'd be OK.\n\nIn any case, I do not think supporting anything other than\npseudorefs and HEAD outside \"refs/\" is a good idea to begin with\n(the \"worktrees/$name/\" example), and requiring that all normal\nreferences live inside \"refs/\" hierarchy is a good idea, so all of\nthe above is moot, I would say.\n\nThanks.\n"},{"id":"486258","messageId":"ZZWIlx-9D2r9AfDW@tanuki","threadId":"60645","inReplyTo":"xmqqsf3ebe1l.fsf@gitster.g","subject":"Re: [PATCH 2/2] ref-filter: support filtering of operational refs","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2024-01-03T16:17:27Z","receivedAt":"2024-01-03T16:17:33Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Wed, Jan 03, 2024 at 08:02:46AM -0800, Junio C Hamano wrote:\n> Patrick Steinhardt <ps@pks.im> writes:\n> \n> > The downside of an empty prefix is that you wouldn't be able to filter\n> > refs outside of the \"refs/\" hierarchy in case we'd use the empty prefix.\n> > A better alternative would be to use \"/\" as an indicator that you want\n> > to list refs outside of \"refs/\". That'd allow for more flexible queries:\n> >\n> >   - \"/\" prints all refs and pseudo refs, even those outside of the\n> >     \"refs/\" hierarchy.\n> >\n> >   - \"/refs\" prints your normal refs.\n> >\n> >   - \"/something/else\" prints refs in \"$GIT_DIR/something/else\".\n> \n> I do not get this at all, sorry.  What makes your \"/\" cover \"refs/\"\n> but not \"something/\"? \n\nIt does cover \"something/\". But...\n\n> Unless you have some rule that special cases \"/\" to apply the\n> \"hierarchy prefix\" matching rule unevenly, that is not possible.  So\n> you can easily lose the \"/\" all of your above patterns share, go back\n> to what I showed, and apply the morally equivalent special case to an\n> empty prefix and you'd be OK.\n\n... I think you're right -- I was arguing under the misassumption that\nthe typical rev-parse rules kicked in for git-for-each-ref(1) (e.g.\nmatching \"heads/foo\" to \"refs/heads/foo\"). But they don't, so my point\nindeed becomes moot and I see what you're getting at now and agree with\nyou.\n\n> In any case, I do not think supporting anything other than\n> pseudorefs and HEAD outside \"refs/\" is a good idea to begin with\n> (the \"worktrees/$name/\" example), and requiring that all normal\n> references live inside \"refs/\" hierarchy is a good idea, so all of\n> the above is moot, I would say.\n\nYeah, I'm on the same page: anything outside of \"refs/\" should not be\nsupported. But the problem is that tools like git-update-ref(1) don't\nenforce this, so something like `git update-ref foo/bar HEAD` happily\ncreates \"$GIT_DIR/foo/bar\". And I bet there are other ways to write refs\nat arbitrary paths.\n\nWith the files backend it's easy to see that this was created and can be\nrectified. But with the reftable library you wouldn't be able to learn\nabout the existence of this ref at all if we ignored anything but\npseudo-refs and refs prefixed with \"refs/\".\n\nSo while I agree that we shouldn't endorse such refs, we need to at\nleast give an escape hatch in case such refs end up in the refdb anyway.\n\nPatrick\n"},{"id":"486263","messageId":"ZZWSxyv4QxSPQOSd@nand.local","threadId":"60645","inReplyTo":"ZZWCxIHf9ySEOWEJ@tanuki","subject":"Re: [PATCH 2/2] ref-filter: support filtering of operational refs","fromName":"Taylor Blau","fromEmail":"me@ttaylorr.com","sentAt":"2024-01-03T17:00:55Z","receivedAt":"2024-01-03T17:00:57Z","isPatch":true,"sender":{"key":"me@ttaylorr.com","avatar":"https://avatars.githubusercontent.com/u/301000140?v=4"},"body":"On Wed, Jan 03, 2024 at 04:52:36PM +0100, Patrick Steinhardt wrote:\n> On Wed, Jan 03, 2024 at 10:45:49AM -0500, Taylor Blau wrote:\n> > On Wed, Jan 03, 2024 at 09:52:33AM +0100, Patrick Steinhardt wrote:\n> > > > I tend to agree that the special empty pattern would be a good shorthand\n> > > > for listing all references underneath refs/, including any top-level\n> > > > psuedo-refs.\n> > > >\n> > > > But I don't think that I quite follow what Karthik is saying here.\n> > > > for-each-ref returns the union of references that match the given\n> > > > pattern(s), not their intersection. So if you wanted to list just the\n> > > > psudo-refs ending in '_HEAD', you'd do:\n> > > >\n> > > >   $ git for-each-ref \"*_HEAD\"\n> > > >\n> > > > I think if you wanted to list all pseudo-refs, calling the option\n> > > > `--pseudo-refs` seems reasonable. But if you want to list some subset of\n> > > > psueod-refs matching a given pattern, you should specify that pattern\n> > > > directly.\n> > >\n> > > Where I think this proposal falls short is if you have refs outside of\n> > > the \"refs/\" hierarchy. Granted, this is nothing that should usually\n> > > happen nowadays. But I think we should safeguard us for the future:\n> >\n> > Hmm. Maybe I misspoke, but I was thinking that `--pseudo-refs` would\n> > imply that we list all references (regardless of whether they appear in\n> > the top-level refs/ hierarchy). But perhaps I'm misunderstanding what\n> > you're trying to accomplish here.\n>\n> Ah, okay. I think in that case it's simply a misunderstanding. To me a\n> pseudo-ref only includes refs that match `is_pseudoref_syntax()`, so\n> things like \"HEAD\", \"ORIG_HEAD\" or \"MERGE_HEAD\". So with that\n> understanding, a ref \"something/outside/refs\" would not be included,\n> but I'd very much like to see it listed.\n\nOK, I see: you're trying to add an option that lists all references\n(including those outside of the top-level \"refs/\" hierarchy). But my\nproposal to use `--pseudo-refs` was to list *just* those references\noutside of the top-level hierarchy.\n\nI wonder if we might want to do something else entirely, which is an\noption which controls the top-level \"namespace\" of references that we\nwant to see. The behavior would then be to list all references under\n\"namespace\" (which presumably would be \"refs/\" by default).\n\nIf you want to list references like something/outside/refs, your\nnamespace would then be --namespace=\"\".\n\nI think that this would be a bit more flexible than the current\nsuggestions, but I am also not as familiar as you are at this particular\nproblem :-).\n\nThanks,\nTaylor\n"},{"id":"486268","messageId":"xmqqil4a9vue.fsf@gitster.g","threadId":"60645","inReplyTo":"ZZWIlx-9D2r9AfDW@tanuki","subject":"Re: [PATCH 2/2] ref-filter: support filtering of operational refs","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2024-01-03T17:21:13Z","receivedAt":"2024-01-03T17:21:16Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Patrick Steinhardt <ps@pks.im> writes:\n\n> ... But the problem is that tools like git-update-ref(1) don't\n> enforce this, so something like `git update-ref foo/bar HEAD` happily\n> creates \"$GIT_DIR/foo/bar\". And I bet there are other ways to write refs\n> at arbitrary paths.\n\nI think we should tighten things up over time.  First by teaching\nthe ref backend that anything that is not a pseudoref, HEAD or a\nproper ref (one item of whose definition is \"lives under refs/\nhierarchy) should not resolve_ref() successfully.  That should\ncorrectly fail things like\n\n    $ git rev-parse worktrees/$name/bisect/bad\n    $ git update-ref foo/bar HEAD\n\nI'd hope.\n\nThanks.\n\n"},{"id":"486269","messageId":"ZZWbMekL2URby0qV@tanuki","threadId":"60645","inReplyTo":"xmqqil4a9vue.fsf@gitster.g","subject":"Re: [PATCH 2/2] ref-filter: support filtering of operational refs","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2024-01-03T17:36:49Z","receivedAt":"2024-01-03T17:36:56Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Wed, Jan 03, 2024 at 09:21:13AM -0800, Junio C Hamano wrote:\n> Patrick Steinhardt <ps@pks.im> writes:\n> \n> > ... But the problem is that tools like git-update-ref(1) don't\n> > enforce this, so something like `git update-ref foo/bar HEAD` happily\n> > creates \"$GIT_DIR/foo/bar\". And I bet there are other ways to write refs\n> > at arbitrary paths.\n> \n> I think we should tighten things up over time.  First by teaching\n> the ref backend that anything that is not a pseudoref, HEAD or a\n> proper ref (one item of whose definition is \"lives under refs/\n> hierarchy) should not resolve_ref() successfully.  That should\n> correctly fail things like\n> \n>     $ git rev-parse worktrees/$name/bisect/bad\n>     $ git update-ref foo/bar HEAD\n> \n> I'd hope.\n> \n> Thanks.\n\nYeah, agreed, that's something we should do. I do wonder whether this\nwill break existing usecases, but in any case I'd rather consider it an\naccident that it is possible to write (and read) such refs in the first\nplace.\n\nPatrick\n"},{"id":"486270","messageId":"xmqqedey9u32.fsf@gitster.g","threadId":"60645","inReplyTo":"ZZWbMekL2URby0qV@tanuki","subject":"Re: [PATCH 2/2] ref-filter: support filtering of operational refs","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2024-01-03T17:59:13Z","receivedAt":"2024-01-03T17:59:24Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Patrick Steinhardt <ps@pks.im> writes:\n\n>> I think we should tighten things up over time.  First by teaching\n>> the ref backend that anything that is not a pseudoref, HEAD or a\n>> proper ref (one item of whose definition is \"lives under refs/\n>> hierarchy) should not resolve_ref() successfully.  That should\n>> correctly fail things like\n>> \n>>     $ git rev-parse worktrees/$name/bisect/bad\n>>     $ git update-ref foo/bar HEAD\n> ...\n> Yeah, agreed, that's something we should do. I do wonder whether this\n> will break existing usecases, but in any case I'd rather consider it an\n> accident that it is possible to write (and read) such refs in the first\n> place.\n\nUnfortunately, the worktrees/$name/refs/bisect/bad and its friends\nare documented in \"git worktree\" and the refs.c layer is aware of\nthe \"main-worktree/\" and \"worktrees/\" hierarchy, so while I still\nthink it is a good long-term direction to make it impossible to\ncreate random refs like \"foo/bar\" and \"resf/heads/master\" via the\ncommands like \"git update-ref\", we cannot limit ourselves only to\n\"refs/\" hierarchy.\n"},{"id":"486271","messageId":"ZZWg5JvjQymy2wcn@tanuki","threadId":"60645","inReplyTo":"xmqqedey9u32.fsf@gitster.g","subject":"Re: [PATCH 2/2] ref-filter: support filtering of operational refs","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2024-01-03T18:01:08Z","receivedAt":"2024-01-03T18:01:14Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Wed, Jan 03, 2024 at 09:59:13AM -0800, Junio C Hamano wrote:\n> Patrick Steinhardt <ps@pks.im> writes:\n> \n> >> I think we should tighten things up over time.  First by teaching\n> >> the ref backend that anything that is not a pseudoref, HEAD or a\n> >> proper ref (one item of whose definition is \"lives under refs/\n> >> hierarchy) should not resolve_ref() successfully.  That should\n> >> correctly fail things like\n> >> \n> >>     $ git rev-parse worktrees/$name/bisect/bad\n> >>     $ git update-ref foo/bar HEAD\n> > ...\n> > Yeah, agreed, that's something we should do. I do wonder whether this\n> > will break existing usecases, but in any case I'd rather consider it an\n> > accident that it is possible to write (and read) such refs in the first\n> > place.\n> \n> Unfortunately, the worktrees/$name/refs/bisect/bad and its friends\n> are documented in \"git worktree\" and the refs.c layer is aware of\n> the \"main-worktree/\" and \"worktrees/\" hierarchy, so while I still\n> think it is a good long-term direction to make it impossible to\n> create random refs like \"foo/bar\" and \"resf/heads/master\" via the\n> commands like \"git update-ref\", we cannot limit ourselves only to\n> \"refs/\" hierarchy.\n\nAh, I first wanted to point this out, but then noticed that you didn't\ninclude the \"refs/\" prefix in \"worktrees/$name/bisect/bad\" and thought\nthis was intentional. But yes, per-worktree refs need to stay supported,\nweird as they may be.\n\nPatrick\n"},{"id":"486288","messageId":"CAOLa=ZStP6F1njTeoQZwN58k+_0r9LT7z-wg2819FWZPq90wQg@mail.gmail.com","threadId":"60645","inReplyTo":"ZZWg5JvjQymy2wcn@tanuki","subject":"Re: [PATCH 2/2] ref-filter: support filtering of operational refs","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2024-01-04T11:31:10Z","receivedAt":"2024-01-04T11:31:12Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"Patrick Steinhardt <ps@pks.im> writes:\n\n> On Wed, Jan 03, 2024 at 09:59:13AM -0800, Junio C Hamano wrote:\n>> Patrick Steinhardt <ps@pks.im> writes:\n>>\n>> >> I think we should tighten things up over time.  First by teaching\n>> >> the ref backend that anything that is not a pseudoref, HEAD or a\n>> >> proper ref (one item of whose definition is \"lives under refs/\n>> >> hierarchy) should not resolve_ref() successfully.  That should\n>> >> correctly fail things like\n>> >>\n>> >>     $ git rev-parse worktrees/$name/bisect/bad\n>> >>     $ git update-ref foo/bar HEAD\n>> > ...\n>> > Yeah, agreed, that's something we should do. I do wonder whether this\n>> > will break existing usecases, but in any case I'd rather consider it an\n>> > accident that it is possible to write (and read) such refs in the first\n>> > place.\n>>\n>> Unfortunately, the worktrees/$name/refs/bisect/bad and its friends\n>> are documented in \"git worktree\" and the refs.c layer is aware of\n>> the \"main-worktree/\" and \"worktrees/\" hierarchy, so while I still\n>> think it is a good long-term direction to make it impossible to\n>> create random refs like \"foo/bar\" and \"resf/heads/master\" via the\n>> commands like \"git update-ref\", we cannot limit ourselves only to\n>> \"refs/\" hierarchy.\n>\n> Ah, I first wanted to point this out, but then noticed that you didn't\n> include the \"refs/\" prefix in \"worktrees/$name/bisect/bad\" and thought\n> this was intentional. But yes, per-worktree refs need to stay supported,\n> weird as they may be.\n>\n> Patrick\n\nThanks all for the discussion, I'll try to summarize the path forward\nas per my understanding.\n\n1. We want to introduce a way to output all refs. This includes refs\nunder \"refs/\", pseudo refs, HEAD, and any other ref like objects under\n$GIT_DIR. The reasoning being that users are allowed currently to create\nrefs without any directory restrictions. So with the upcoming reftable\nbackend, it becomes important to provide a utility to print all the refs\nheld in the reftable. Ideally we want to restrict such ref's from being\ncreated but for the time being, since thats allowed, we should also\nprovide the utility to print such refs.\n\n2. In the files backend, this would involve iterating through the\n$GIT_DIR and finding all ref-like objects and printing them.\n\n3. To expose this to the user, we could do something like\n\n   $ git for-each-ref \"\"\n\nWhich is a natural extension of the current syntax, where the empty\nstring would imply that we do not filter to the \"refs/\" directory.\nIt is still not clear whether we should support \"worktrees\".\n\nAny corrections here?\n"},{"id":"486326","messageId":"xmqq1qawr6p4.fsf@gitster.g","threadId":"60645","inReplyTo":"CAOLa=ZStP6F1njTeoQZwN58k+_0r9LT7z-wg2819FWZPq90wQg@mail.gmail.com","subject":"Re: [PATCH 2/2] ref-filter: support filtering of operational refs","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2024-01-04T23:59:19Z","receivedAt":"2024-01-04T23:59:25Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Karthik Nayak <karthik.188@gmail.com> writes:\n\n> Thanks all for the discussion, I'll try to summarize the path forward\n> as per my understanding.\n\nIt has already been clear for the past 5 years or so since 3a3b9d8c\n(refs: new ref types to make per-worktree refs visible to all\nworktrees, 2018-10-21) that we need to treat \"worktrees/foo/HEAD\",\n\"worktrees/bar/refs/bisect/bad\", etc. as something end-users can\naccess via the normal ref mechansim (by a resolve_ref() call that is\neventually made from get_sha1() when these are passed to say \"git\nlog\"); I just did not remember that one but that does not mean we\ncan suddenly change the rules.\n\nSo you'd probably need to tweak the end of your bullet point #3, but\nother than that it is a great summary.\n\nThanks.\n\n> 1. We want to introduce a way to output all refs. This includes refs\n> under \"refs/\", pseudo refs, HEAD, and any other ref like objects under\n> $GIT_DIR. The reasoning being that users are allowed currently to create\n> refs without any directory restrictions. So with the upcoming reftable\n> backend, it becomes important to provide a utility to print all the refs\n> held in the reftable. Ideally we want to restrict such ref's from being\n> created but for the time being, since thats allowed, we should also\n> provide the utility to print such refs.\n>\n> 2. In the files backend, this would involve iterating through the\n> $GIT_DIR and finding all ref-like objects and printing them.\n>\n> 3. To expose this to the user, we could do something like\n>\n>    $ git for-each-ref \"\"\n>\n> Which is a natural extension of the current syntax, where the empty\n> string would imply that we do not filter to the \"refs/\" directory.\n> It is still not clear whether we should support \"worktrees\".\n>\n> Any corrections here?\n"}]}