{"thread":{"id":"58584","subject":"[PATCH] symbolic-ref: teach \"--[no-]recurse\" option","startedAt":"2022-10-07T22:00:45Z","lastAt":"2022-10-11T14:49:09Z","messageCount":13,"participants":["Junio C Hamano","Eric Sunshine","Bagas Sanjaya","Philip Oakley"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"464404","messageId":"xmqqleprcn08.fsf@gitster.g","threadId":"58584","inReplyTo":null,"subject":"[PATCH] symbolic-ref: teach \"--[no-]recurse\" option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-10-07T22:00:39Z","receivedAt":"2022-10-07T22:00:45Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Suppose you are managing many maintenance tracks in your project,\nand some of the more recent ones are maint-2.36 and maint-2.37.\nFurther imagine that your project recently tagged the official 2.38\nrelease, which means you would need to start maint-2.38 track soon,\nby doing:\n\n  $ git checkout -b maint-2.38 v2.38.0^0\n  $ git branch --list 'maint-2.3[6-9]'\n  * maint-2.38\n    maint-2.36\n    maint-2.37\n\nSo far, so good.  But it also is reasonable to want not to have to\nworry about which maintenance track is the latest, by pointing a\nmore generic-sounding 'maint' branch at it, by doing:\n\n  $ git symbolic-ref refs/heads/maint refs/heads/maint-2.38\n\nwhich would allow you to say \"whichever it is, check out the latest\nmaintenance track\", by doing:\n\n  $ git checkout maint\n  $ git branch --show-current\n  maint-2.38\n\nIt is arguably better to say that we are on 'maint-2.38' rather than\non 'maint', and \"git merge/pull\" would record \"into maint-2.38\" and\nnot \"into maint\", so I think what we have is a good behaviour.\n\nOne thing that is slightly irritating, however, is that I do not\nthink there is a good way (other than \"cat .git/HEAD\") to learn that\nyou checked out 'maint' to get into that state.  Just like the output\nof \"git branch --show-current\" shows above, \"git symbolic-ref HEAD\"\nwould report 'refs/heads/maint-2.38', bypassing the intermediate\nsymbolic ref at 'refs/heads/maint' that is pointed at by HEAD.\n\nThe internal resolve_ref() API already has the necessary support for\nstopping after resolving a single level of a symbolic-ref, and we\ncan expose it by adding a \"--[no-]recurse\" option to the command.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/symbolic-ref.c  | 16 ++++++++++------\n t/t1401-symbolic-ref.sh | 14 ++++++++++++++\n 2 files changed, 24 insertions(+), 6 deletions(-)\n\ndiff --git c/builtin/symbolic-ref.c w/builtin/symbolic-ref.c\nindex 1b0f10225f..5c9de63267 100644\n--- c/builtin/symbolic-ref.c\n+++ w/builtin/symbolic-ref.c\n@@ -10,10 +10,13 @@ static const char * const git_symbolic_ref_usage[] = {\n \tNULL\n };\n \n-static int check_symref(const char *HEAD, int quiet, int shorten, int print)\n+static int check_symref(const char *HEAD, int quiet, int shorten, int recurse, int print)\n {\n-\tint flag;\n-\tconst char *refname = resolve_ref_unsafe(HEAD, 0, NULL, &flag);\n+\tint resolve_flags, flag;\n+\tconst char *refname;\n+\n+\tresolve_flags = (recurse ? 0 : RESOLVE_REF_NO_RECURSE);\n+\trefname = resolve_ref_unsafe(HEAD, resolve_flags, NULL, &flag);\n \n \tif (!refname)\n \t\tdie(\"No such ref: %s\", HEAD);\n@@ -35,13 +38,14 @@ static int check_symref(const char *HEAD, int quiet, int shorten, int print)\n \n int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)\n {\n-\tint quiet = 0, delete = 0, shorten = 0, ret = 0;\n+\tint quiet = 0, delete = 0, shorten = 0, recurse = 1, ret = 0;\n \tconst char *msg = NULL;\n \tstruct option options[] = {\n \t\tOPT__QUIET(&quiet,\n \t\t\tN_(\"suppress error message for non-symbolic (detached) refs\")),\n \t\tOPT_BOOL('d', \"delete\", &delete, N_(\"delete symbolic ref\")),\n \t\tOPT_BOOL(0, \"short\", &shorten, N_(\"shorten ref output\")),\n+\t\tOPT_BOOL(0, \"recurse\", &recurse, N_(\"recursively dereference (default)\")),\n \t\tOPT_STRING('m', NULL, &msg, N_(\"reason\"), N_(\"reason of the update\")),\n \t\tOPT_END(),\n \t};\n@@ -55,7 +59,7 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)\n \tif (delete) {\n \t\tif (argc != 1)\n \t\t\tusage_with_options(git_symbolic_ref_usage, options);\n-\t\tret = check_symref(argv[0], 1, 0, 0);\n+\t\tret = check_symref(argv[0], 1, 0, 0, 0);\n \t\tif (ret)\n \t\t\tdie(\"Cannot delete %s, not a symbolic ref\", argv[0]);\n \t\tif (!strcmp(argv[0], \"HEAD\"))\n@@ -65,7 +69,7 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)\n \n \tswitch (argc) {\n \tcase 1:\n-\t\tret = check_symref(argv[0], quiet, shorten, 1);\n+\t\tret = check_symref(argv[0], quiet, shorten, recurse, 1);\n \t\tbreak;\n \tcase 2:\n \t\tif (!strcmp(argv[0], \"HEAD\") &&\ndiff --git c/t/t1401-symbolic-ref.sh w/t/t1401-symbolic-ref.sh\nindex 0c204089b8..d708acdb81 100755\n--- c/t/t1401-symbolic-ref.sh\n+++ w/t/t1401-symbolic-ref.sh\n@@ -175,4 +175,18 @@ test_expect_success 'symbolic-ref allows top-level target for non-HEAD' '\n \ttest_cmp_rev top-level HEAD\n '\n \n+test_expect_success 'symbolic-ref pointing at another' '\n+\tgit update-ref refs/heads/maint-2.37 HEAD &&\n+\tgit symbolic-ref refs/heads/maint refs/heads/maint-2.37 &&\n+\tgit checkout maint &&\n+\n+\tgit symbolic-ref HEAD >actual &&\n+\techo refs/heads/maint-2.37 >expect &&\n+\ttest_cmp expect actual &&\n+\n+\tgit symbolic-ref --no-recurse HEAD >actual &&\n+\techo refs/heads/maint >expect &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\n"},{"id":"464411","messageId":"CAPig+cQZ_SehTLoFEtBf2Xv=8iw3-DkjQfP3R9J8kUm3DjkLBw@mail.gmail.com","threadId":"58584","inReplyTo":"xmqqleprcn08.fsf@gitster.g","subject":"Re: [PATCH] symbolic-ref: teach \"--[no-]recurse\" option","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2022-10-08T03:35:39Z","receivedAt":"2022-10-08T03:35:54Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Fri, Oct 7, 2022 at 6:19 PM Junio C Hamano <gitster@pobox.com> wrote:\n> [...]\n> One thing that is slightly irritating, however, is that I do not\n> think there is a good way (other than \"cat .git/HEAD\") to learn that\n> you checked out 'maint' to get into that state.  Just like the output\n> of \"git branch --show-current\" shows above, \"git symbolic-ref HEAD\"\n> would report 'refs/heads/maint-2.38', bypassing the intermediate\n> symbolic ref at 'refs/heads/maint' that is pointed at by HEAD.\n>\n> The internal resolve_ref() API already has the necessary support for\n> stopping after resolving a single level of a symbolic-ref, and we\n> can expose it by adding a \"--[no-]recurse\" option to the command.\n>\n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n> ---\n>  builtin/symbolic-ref.c  | 16 ++++++++++------\n>  t/t1401-symbolic-ref.sh | 14 ++++++++++++++\n>  2 files changed, 24 insertions(+), 6 deletions(-)\n\nShould this be accompanied by a documentation update or is the patch\nintended as an RFC?\n"},{"id":"464414","messageId":"xmqq4jwfc5er.fsf@gitster.g","threadId":"58584","inReplyTo":"CAPig+cQZ_SehTLoFEtBf2Xv=8iw3-DkjQfP3R9J8kUm3DjkLBw@mail.gmail.com","subject":"Re: [PATCH] symbolic-ref: teach \"--[no-]recurse\" option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-10-08T04:20:44Z","receivedAt":"2022-10-08T04:20:56Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Eric Sunshine <sunshine@sunshineco.com> writes:\n\n> On Fri, Oct 7, 2022 at 6:19 PM Junio C Hamano <gitster@pobox.com> wrote:\n>> [...]\n>> One thing that is slightly irritating, however, is that I do not\n>> think there is a good way (other than \"cat .git/HEAD\") to learn that\n>> you checked out 'maint' to get into that state.  Just like the output\n>> of \"git branch --show-current\" shows above, \"git symbolic-ref HEAD\"\n>> would report 'refs/heads/maint-2.38', bypassing the intermediate\n>> symbolic ref at 'refs/heads/maint' that is pointed at by HEAD.\n>>\n>> The internal resolve_ref() API already has the necessary support for\n>> stopping after resolving a single level of a symbolic-ref, and we\n>> can expose it by adding a \"--[no-]recurse\" option to the command.\n>>\n>> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n>> ---\n>>  builtin/symbolic-ref.c  | 16 ++++++++++------\n>>  t/t1401-symbolic-ref.sh | 14 ++++++++++++++\n>>  2 files changed, 24 insertions(+), 6 deletions(-)\n>\n> Should this be accompanied by a documentation update or is the patch\n> intended as an RFC?\n\nIt started its life as an RFC but I had an actual need during\ntoday's integration run ;-).  Will try to come up with a\ndocumentation patch when I have time.\n\nThanks.\n"},{"id":"464416","messageId":"xmqqsfjzaq78.fsf@gitster.g","threadId":"58584","inReplyTo":"xmqqleprcn08.fsf@gitster.g","subject":"[PATCH v2] symbolic-ref: teach \"--[no-]recurse\" option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-10-08T04:34:35Z","receivedAt":"2022-10-08T04:34:45Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Suppose you are managing many maintenance tracks in your project,\nand some of the more recent ones are maint-2.36 and maint-2.37.\nFurther imagine that your project recently tagged the official 2.38\nrelease, which means you would need to start maint-2.38 track soon,\nby doing:\n\n  $ git checkout -b maint-2.38 v2.38.0^0\n  $ git branch --list 'maint-2.3[6-9]'\n  * maint-2.38\n    maint-2.36\n    maint-2.37\n\nSo far, so good.  But it also is reasonable to want not to have to\nworry about which maintenance track is the latest, by pointing a\nmore generic-sounding 'maint' branch at it, by doing:\n\n  $ git symbolic-ref refs/heads/maint refs/heads/maint-2.38\n\nwhich would allow you to say \"whichever it is, check out the latest\nmaintenance track\", by doing:\n\n  $ git checkout maint\n  $ git branch --show-current\n  maint-2.38\n\nIt is arguably better to say that we are on 'maint-2.38' rather than\non 'maint', and \"git merge/pull\" would record \"into maint-2.38\" and\nnot \"into maint\", so I think what we have is a good behaviour.\n\nOne thing that is slightly irritating, however, is that I do not\nthink there is a good way (other than \"cat .git/HEAD\") to learn that\nyou checked out 'maint' to get into that state.  Just like the output\nof \"git branch --show-current\" shows above, \"git symbolic-ref HEAD\"\nwould report 'refs/heads/maint-2.38', bypassing the intermediate\nsymbolic ref at 'refs/heads/maint' that is pointed at by HEAD.\n\nThe internal resolve_ref() API already has the necessary support for\nstopping after resolving a single level of a symbolic-ref, and we\ncan expose it by adding a \"--[no-]recurse\" option to the command.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n\n * Updates documentation, which was entirely lacking in v1, with no\n   other changes.\n\n Documentation/git-symbolic-ref.txt |  9 +++++++++\n builtin/symbolic-ref.c             | 16 ++++++++++------\n t/t1401-symbolic-ref.sh            | 14 ++++++++++++++\n 3 files changed, 33 insertions(+), 6 deletions(-)\n\ndiff --git a/Documentation/git-symbolic-ref.txt b/Documentation/git-symbolic-ref.txt\nindex ef68ad2b71..3b5a97ea2b 100644\n--- a/Documentation/git-symbolic-ref.txt\n+++ b/Documentation/git-symbolic-ref.txt\n@@ -46,6 +46,15 @@ OPTIONS\n \tWhen showing the value of <name> as a symbolic ref, try to shorten the\n \tvalue, e.g. from `refs/heads/master` to `master`.\n \n+--recurse::\n+--no-recurse::\n+\tWhen showing the value of <name> as a symbolic ref, if\n+\t<name> refers to another symbolic ref, follow such a chain\n+\tof symbolic refs until the result no longer points at a\n+\tsymbolic ref (`--recurse`, which is the default).\n+\t`--no-recurse` stops after dereferencing only a single level\n+\tof symbolic ref.\n+\n -m::\n \tUpdate the reflog for <name> with <reason>.  This is valid only\n \twhen creating or updating a symbolic ref.\ndiff --git a/builtin/symbolic-ref.c b/builtin/symbolic-ref.c\nindex e547a08d6c..1af27b3a68 100644\n--- a/builtin/symbolic-ref.c\n+++ b/builtin/symbolic-ref.c\n@@ -10,10 +10,13 @@ static const char * const git_symbolic_ref_usage[] = {\n \tNULL\n };\n \n-static int check_symref(const char *HEAD, int quiet, int shorten, int print)\n+static int check_symref(const char *HEAD, int quiet, int shorten, int recurse, int print)\n {\n-\tint flag;\n-\tconst char *refname = resolve_ref_unsafe(HEAD, 0, NULL, &flag);\n+\tint resolve_flags, flag;\n+\tconst char *refname;\n+\n+\tresolve_flags = (recurse ? 0 : RESOLVE_REF_NO_RECURSE);\n+\trefname = resolve_ref_unsafe(HEAD, resolve_flags, NULL, &flag);\n \n \tif (!refname)\n \t\tdie(\"No such ref: %s\", HEAD);\n@@ -35,13 +38,14 @@ static int check_symref(const char *HEAD, int quiet, int shorten, int print)\n \n int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)\n {\n-\tint quiet = 0, delete = 0, shorten = 0, ret = 0;\n+\tint quiet = 0, delete = 0, shorten = 0, recurse = 1, ret = 0;\n \tconst char *msg = NULL;\n \tstruct option options[] = {\n \t\tOPT__QUIET(&quiet,\n \t\t\tN_(\"suppress error message for non-symbolic (detached) refs\")),\n \t\tOPT_BOOL('d', \"delete\", &delete, N_(\"delete symbolic ref\")),\n \t\tOPT_BOOL(0, \"short\", &shorten, N_(\"shorten ref output\")),\n+\t\tOPT_BOOL(0, \"recurse\", &recurse, N_(\"recursively dereference (default)\")),\n \t\tOPT_STRING('m', NULL, &msg, N_(\"reason\"), N_(\"reason of the update\")),\n \t\tOPT_END(),\n \t};\n@@ -55,7 +59,7 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)\n \tif (delete) {\n \t\tif (argc != 1)\n \t\t\tusage_with_options(git_symbolic_ref_usage, options);\n-\t\tret = check_symref(argv[0], 1, 0, 0);\n+\t\tret = check_symref(argv[0], 1, 0, 0, 0);\n \t\tif (ret)\n \t\t\tdie(\"Cannot delete %s, not a symbolic ref\", argv[0]);\n \t\tif (!strcmp(argv[0], \"HEAD\"))\n@@ -65,7 +69,7 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)\n \n \tswitch (argc) {\n \tcase 1:\n-\t\tret = check_symref(argv[0], quiet, shorten, 1);\n+\t\tret = check_symref(argv[0], quiet, shorten, recurse, 1);\n \t\tbreak;\n \tcase 2:\n \t\tif (!strcmp(argv[0], \"HEAD\") &&\ndiff --git a/t/t1401-symbolic-ref.sh b/t/t1401-symbolic-ref.sh\nindex 132a1b885a..773a6e8e01 100755\n--- a/t/t1401-symbolic-ref.sh\n+++ b/t/t1401-symbolic-ref.sh\n@@ -163,4 +163,18 @@ test_expect_success 'symbolic-ref can resolve d/f name (ENOTDIR)' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'symbolic-ref pointing at another' '\n+\tgit update-ref refs/heads/maint-2.37 HEAD &&\n+\tgit symbolic-ref refs/heads/maint refs/heads/maint-2.37 &&\n+\tgit checkout maint &&\n+\n+\tgit symbolic-ref HEAD >actual &&\n+\techo refs/heads/maint-2.37 >expect &&\n+\ttest_cmp expect actual &&\n+\n+\tgit symbolic-ref --no-recurse HEAD >actual &&\n+\techo refs/heads/maint >expect &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\n-- \n2.38.0-165-ga5df27c8e1\n\n"},{"id":"464417","messageId":"CAPig+cQHw_VjbA2_HaZJj3Q0v8C6uUukr40vXFuizx4M_04XFA@mail.gmail.com","threadId":"58584","inReplyTo":"xmqqsfjzaq78.fsf@gitster.g","subject":"Re: [PATCH v2] symbolic-ref: teach \"--[no-]recurse\" option","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2022-10-08T04:54:36Z","receivedAt":"2022-10-08T04:54:54Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Sat, Oct 8, 2022 at 12:34 AM Junio C Hamano <gitster@pobox.com> wrote:\n> [...]\n> One thing that is slightly irritating, however, is that I do not\n> think there is a good way (other than \"cat .git/HEAD\") to learn that\n> you checked out 'maint' to get into that state.  Just like the output\n> of \"git branch --show-current\" shows above, \"git symbolic-ref HEAD\"\n> would report 'refs/heads/maint-2.38', bypassing the intermediate\n> symbolic ref at 'refs/heads/maint' that is pointed at by HEAD.\n> [...]\n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n> ---\n> diff --git a/Documentation/git-symbolic-ref.txt b/Documentation/git-symbolic-ref.txt\n> @@ -46,6 +46,15 @@ OPTIONS\n> +--recurse::\n> +--no-recurse::\n> +       When showing the value of <name> as a symbolic ref, if\n> +       <name> refers to another symbolic ref, follow such a chain\n> +       of symbolic refs until the result no longer points at a\n> +       symbolic ref (`--recurse`, which is the default).\n> +       `--no-recurse` stops after dereferencing only a single level\n> +       of symbolic ref.\n\nWith his recent documentation-normalization work, I suspect Ævar would\nappreciate an update to the synopsis, as well:\n\n    SYNOPSIS\n    --------\n    [verse]\n    'git symbolic-ref' [-m <reason>] <name> <ref>\n   -'git symbolic-ref' [-q] [--short] <name>\n   +'git symbolic-ref' [-q] [--short] [--no-recurse] <name>\n    'git symbolic-ref' --delete [-q] <name>\n\nor something similar (i.e. plain [--recurse] or composite\n[--[no-]-recurse] or [--recurse | --no-recurse]).\n"},{"id":"464424","messageId":"0b44cdca-3115-e09e-70c8-6f56101c3d9c@gmail.com","threadId":"58584","inReplyTo":"xmqqsfjzaq78.fsf@gitster.g","subject":"Re: [PATCH v2] symbolic-ref: teach \"--[no-]recurse\" option","fromName":"Bagas Sanjaya","fromEmail":"bagasdotme@gmail.com","sentAt":"2022-10-08T09:37:00Z","receivedAt":"2022-10-08T09:37:07Z","isPatch":true,"sender":{"key":"bagasdotme@gmail.com","avatar":"https://avatars.githubusercontent.com/u/40219486?v=4"},"body":"On 10/8/22 11:34, Junio C Hamano wrote:\n> Suppose you are managing many maintenance tracks in your project,\n> and some of the more recent ones are maint-2.36 and maint-2.37.\n> Further imagine that your project recently tagged the official 2.38\n> release, which means you would need to start maint-2.38 track soon,\n> by doing:\n> \n>   $ git checkout -b maint-2.38 v2.38.0^0\n>   $ git branch --list 'maint-2.3[6-9]'\n>   * maint-2.38\n>     maint-2.36\n>     maint-2.37\n> \n> So far, so good.  But it also is reasonable to want not to have to\n> worry about which maintenance track is the latest, by pointing a\n> more generic-sounding 'maint' branch at it, by doing:\n> \n>   $ git symbolic-ref refs/heads/maint refs/heads/maint-2.38\n> \n> which would allow you to say \"whichever it is, check out the latest\n> maintenance track\", by doing:\n> \n>   $ git checkout maint\n>   $ git branch --show-current\n>   maint-2.38\n> \n> It is arguably better to say that we are on 'maint-2.38' rather than\n> on 'maint', and \"git merge/pull\" would record \"into maint-2.38\" and\n> not \"into maint\", so I think what we have is a good behaviour.\n> \n> One thing that is slightly irritating, however, is that I do not\n> think there is a good way (other than \"cat .git/HEAD\") to learn that\n> you checked out 'maint' to get into that state.  Just like the output\n> of \"git branch --show-current\" shows above, \"git symbolic-ref HEAD\"\n> would report 'refs/heads/maint-2.38', bypassing the intermediate\n> symbolic ref at 'refs/heads/maint' that is pointed at by HEAD.\n> \n> The internal resolve_ref() API already has the necessary support for\n> stopping after resolving a single level of a symbolic-ref, and we\n> can expose it by adding a \"--[no-]recurse\" option to the command.\n> \n\nThe example case above is from recent Git releases, right?\n\nI think the wording should instead use generalized version numbers.\nFor example the still maintained release tracks are X.Y-1 and X.Y,\nbut now X+1 have been tagged, which creates X+1.Y track.\n\nThanks.\n\n-- \nAn old man doll... just what I always wanted! - Clara\n"},{"id":"464426","messageId":"86355292-cb54-32c8-abf5-542fb4cf9ade@iee.email","threadId":"58584","inReplyTo":"xmqqsfjzaq78.fsf@gitster.g","subject":"Re: [PATCH v2] symbolic-ref: teach \"--[no-]recurse\" option","fromName":"Philip Oakley","fromEmail":"philipoakley@iee.email","sentAt":"2022-10-08T12:28:21Z","receivedAt":"2022-10-08T12:28:29Z","isPatch":true,"sender":{"key":"philipoakley@iee.email","avatar":"https://avatars.githubusercontent.com/u/914343?v=4"},"body":"Hi Junio\n\nOn 08/10/2022 05:34, Junio C Hamano wrote:\n> Suppose you are managing many maintenance tracks in your project,\n> and some of the more recent ones are maint-2.36 and maint-2.37.\n> Further imagine that your project recently tagged the official 2.38\n> release, which means you would need to start maint-2.38 track soon,\n> by doing:\n>\n>   $ git checkout -b maint-2.38 v2.38.0^0\n>   $ git branch --list 'maint-2.3[6-9]'\n>   * maint-2.38\n>     maint-2.36\n>     maint-2.37\n>\n> So far, so good.  But it also is reasonable to want not to have to\n> worry about which maintenance track is the latest, by pointing a\n> more generic-sounding 'maint' branch at it, by doing:\n>\n>   $ git symbolic-ref refs/heads/maint refs/heads/maint-2.38\n>\n> which would allow you to say \"whichever it is, check out the latest\n> maintenance track\", by doing:\n>\n>   $ git checkout maint\n>   $ git branch --show-current\n>   maint-2.38\n>\n> It is arguably better to say that we are on 'maint-2.38' rather than\n> on 'maint', and \"git merge/pull\" would record \"into maint-2.38\" and\n> not \"into maint\", so I think what we have is a good behaviour.\n>\n> One thing that is slightly irritating, however, is that I do not\n> think there is a good way (other than \"cat .git/HEAD\") to learn that\n> you checked out 'maint' to get into that state.  Just like the output\n> of \"git branch --show-current\" shows above, \"git symbolic-ref HEAD\"\n> would report 'refs/heads/maint-2.38', bypassing the intermediate\n> symbolic ref at 'refs/heads/maint' that is pointed at by HEAD.\n>\n> The internal resolve_ref() API already has the necessary support for\n> stopping after resolving a single level of a symbolic-ref, and we\n> can expose it by adding a \"--[no-]recurse\" option to the command.\n>\n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n> ---\n>\n>  * Updates documentation, which was entirely lacking in v1, with no\n>    other changes.\n>\n>  Documentation/git-symbolic-ref.txt |  9 +++++++++\n\nIs there also a need to update SubmittingPatches to clarify the\ndistinctions between the generic name 'maint', the specific `maint-xx`\nbranches, and the symbolic ref linkages from `maint`.\n\nThe existence of the `maint-xx` branches, and where they came from, was\nsomething that eluded me for a long time.\n\nThe descriptions give the impression there is just a single main branch,\nwith a singular name, and that was the end of it. It was only much later\nwhen some security patches were pushed down to numerous older `maint-xx`\nbranches. The use of the singular `maint` is also used in examples a\nnumber of places further cementing the singular maintenance view.\n\nA few words clarifying the `maint` vs `maint-x.yy` branches could help\nusers past the confusion.\n--\nPhilip\n\n>  builtin/symbolic-ref.c             | 16 ++++++++++------\n>  t/t1401-symbolic-ref.sh            | 14 ++++++++++++++\n>  3 files changed, 33 insertions(+), 6 deletions(-)\n>\n> diff --git a/Documentation/git-symbolic-ref.txt b/Documentation/git-symbolic-ref.txt\n> index ef68ad2b71..3b5a97ea2b 100644\n> --- a/Documentation/git-symbolic-ref.txt\n> +++ b/Documentation/git-symbolic-ref.txt\n> @@ -46,6 +46,15 @@ OPTIONS\n>  \tWhen showing the value of <name> as a symbolic ref, try to shorten the\n>  \tvalue, e.g. from `refs/heads/master` to `master`.\n>  \n> +--recurse::\n> +--no-recurse::\n> +\tWhen showing the value of <name> as a symbolic ref, if\n> +\t<name> refers to another symbolic ref, follow such a chain\n> +\tof symbolic refs until the result no longer points at a\n> +\tsymbolic ref (`--recurse`, which is the default).\n> +\t`--no-recurse` stops after dereferencing only a single level\n> +\tof symbolic ref.\n> +\n>  -m::\n>  \tUpdate the reflog for <name> with <reason>.  This is valid only\n>  \twhen creating or updating a symbolic ref.\n> diff --git a/builtin/symbolic-ref.c b/builtin/symbolic-ref.c\n> index e547a08d6c..1af27b3a68 100644\n> --- a/builtin/symbolic-ref.c\n> +++ b/builtin/symbolic-ref.c\n> @@ -10,10 +10,13 @@ static const char * const git_symbolic_ref_usage[] = {\n>  \tNULL\n>  };\n>  \n> -static int check_symref(const char *HEAD, int quiet, int shorten, int print)\n> +static int check_symref(const char *HEAD, int quiet, int shorten, int recurse, int print)\n>  {\n> -\tint flag;\n> -\tconst char *refname = resolve_ref_unsafe(HEAD, 0, NULL, &flag);\n> +\tint resolve_flags, flag;\n> +\tconst char *refname;\n> +\n> +\tresolve_flags = (recurse ? 0 : RESOLVE_REF_NO_RECURSE);\n> +\trefname = resolve_ref_unsafe(HEAD, resolve_flags, NULL, &flag);\n>  \n>  \tif (!refname)\n>  \t\tdie(\"No such ref: %s\", HEAD);\n> @@ -35,13 +38,14 @@ static int check_symref(const char *HEAD, int quiet, int shorten, int print)\n>  \n>  int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)\n>  {\n> -\tint quiet = 0, delete = 0, shorten = 0, ret = 0;\n> +\tint quiet = 0, delete = 0, shorten = 0, recurse = 1, ret = 0;\n>  \tconst char *msg = NULL;\n>  \tstruct option options[] = {\n>  \t\tOPT__QUIET(&quiet,\n>  \t\t\tN_(\"suppress error message for non-symbolic (detached) refs\")),\n>  \t\tOPT_BOOL('d', \"delete\", &delete, N_(\"delete symbolic ref\")),\n>  \t\tOPT_BOOL(0, \"short\", &shorten, N_(\"shorten ref output\")),\n> +\t\tOPT_BOOL(0, \"recurse\", &recurse, N_(\"recursively dereference (default)\")),\n>  \t\tOPT_STRING('m', NULL, &msg, N_(\"reason\"), N_(\"reason of the update\")),\n>  \t\tOPT_END(),\n>  \t};\n> @@ -55,7 +59,7 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)\n>  \tif (delete) {\n>  \t\tif (argc != 1)\n>  \t\t\tusage_with_options(git_symbolic_ref_usage, options);\n> -\t\tret = check_symref(argv[0], 1, 0, 0);\n> +\t\tret = check_symref(argv[0], 1, 0, 0, 0);\n>  \t\tif (ret)\n>  \t\t\tdie(\"Cannot delete %s, not a symbolic ref\", argv[0]);\n>  \t\tif (!strcmp(argv[0], \"HEAD\"))\n> @@ -65,7 +69,7 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)\n>  \n>  \tswitch (argc) {\n>  \tcase 1:\n> -\t\tret = check_symref(argv[0], quiet, shorten, 1);\n> +\t\tret = check_symref(argv[0], quiet, shorten, recurse, 1);\n>  \t\tbreak;\n>  \tcase 2:\n>  \t\tif (!strcmp(argv[0], \"HEAD\") &&\n> diff --git a/t/t1401-symbolic-ref.sh b/t/t1401-symbolic-ref.sh\n> index 132a1b885a..773a6e8e01 100755\n> --- a/t/t1401-symbolic-ref.sh\n> +++ b/t/t1401-symbolic-ref.sh\n> @@ -163,4 +163,18 @@ test_expect_success 'symbolic-ref can resolve d/f name (ENOTDIR)' '\n>  \ttest_cmp expect actual\n>  '\n>  \n> +test_expect_success 'symbolic-ref pointing at another' '\n> +\tgit update-ref refs/heads/maint-2.37 HEAD &&\n> +\tgit symbolic-ref refs/heads/maint refs/heads/maint-2.37 &&\n> +\tgit checkout maint &&\n> +\n> +\tgit symbolic-ref HEAD >actual &&\n> +\techo refs/heads/maint-2.37 >expect &&\n> +\ttest_cmp expect actual &&\n> +\n> +\tgit symbolic-ref --no-recurse HEAD >actual &&\n> +\techo refs/heads/maint >expect &&\n> +\ttest_cmp expect actual\n> +'\n> +\n>  test_done\n\n"},{"id":"464428","messageId":"0d7707ba-5cfb-35a6-441f-06bf80053a72@iee.email","threadId":"58584","inReplyTo":"86355292-cb54-32c8-abf5-542fb4cf9ade@iee.email","subject":"Re: [PATCH v2] symbolic-ref: teach \"--[no-]recurse\" option","fromName":"Philip Oakley","fromEmail":"philipoakley@iee.email","sentAt":"2022-10-08T15:28:27Z","receivedAt":"2022-10-08T15:28:33Z","isPatch":true,"sender":{"key":"philipoakley@iee.email","avatar":"https://avatars.githubusercontent.com/u/914343?v=4"},"body":"spelling correction\n\nOn 08/10/2022 13:28, Philip Oakley wrote:\n> The existence of the `maint-xx` branches, and where they came from, was\n> something that eluded me for a long time.\n>\n> The descriptions give the impression there is just a single main branch,\n\ns/main/`maint`/ \n> with a singular name, and that was the end of it. It was only much later\n> when some security patches were pushed down to numerous older `maint-xx`\n> branches. The use of the singular `maint` is also used in examples a\n> number of places further cementing the singular maintenance view.\n>\n> A few words clarifying the `maint` vs `maint-x.yy` branches could help\n> users past the confusion.\n\n"},{"id":"464437","messageId":"xmqqr0zha9sx.fsf@gitster.g","threadId":"58584","inReplyTo":"CAPig+cQHw_VjbA2_HaZJj3Q0v8C6uUukr40vXFuizx4M_04XFA@mail.gmail.com","subject":"Re: [PATCH v2] symbolic-ref: teach \"--[no-]recurse\" option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-10-09T04:41:02Z","receivedAt":"2022-10-09T04:41:11Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Eric Sunshine <sunshine@sunshineco.com> writes:\n\n> With his recent documentation-normalization work, I suspect Ævar would\n> appreciate an update to the synopsis, as well:\n>\n>     SYNOPSIS\n>     --------\n>     [verse]\n>     'git symbolic-ref' [-m <reason>] <name> <ref>\n>    -'git symbolic-ref' [-q] [--short] <name>\n>    +'git symbolic-ref' [-q] [--short] [--no-recurse] <name>\n>     'git symbolic-ref' --delete [-q] <name>\n>\n> or something similar (i.e. plain [--recurse] or composite\n> [--[no-]-recurse] or [--recurse | --no-recurse]).\n\nYeah, that looks good.\n\nI checked the in-code usage that used [<options>] (hence I didn't\nhave to do anything new), but apparently forgot about the doc.\n\nAs there is (and there will ever be) no configuration knob for this\nplumbing command to make the non-recursive behaviour the default, I\nthink listing [--no-recurse] alone, not [--[no-]recurse], would be\nthe right thing to do in the documentation.\n\nThanks.\n"},{"id":"464442","messageId":"xmqqfsfx8akc.fsf@gitster.g","threadId":"58584","inReplyTo":"86355292-cb54-32c8-abf5-542fb4cf9ade@iee.email","subject":"Re: [PATCH v2] symbolic-ref: teach \"--[no-]recurse\" option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-10-09T12:07:31Z","receivedAt":"2022-10-09T12:07:42Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Philip Oakley <philipoakley@iee.email> writes:\n\n> Is there also a need to update SubmittingPatches to clarify the\n> distinctions between the generic name 'maint', the specific `maint-xx`\n> branches, and the symbolic ref linkages from `maint`.\n\nNot at all.  Perhaps you are thinking about MaintNotes, but even\nthere, general public do not have to be concerned about maint-xx\nmost of the time.  I myself would not be keeping branches for\nancient maintenance tracks anywhere.  As the older maintenance\ntracks, other than the most recent ones, do not get topics graduated\nto 'master' merged down by me (even though topic branches that fix\nnotable bugs may fork from an older version to allow motivated third\nparty maintainers to merge them down to older maintenance releases),\nthere is not really a reason to keep branches like maint-2.15 for\ndaily operation.  Only when we need security updates that go back to\nolder maintenance tracks, I may do\n\n    $ git checkout -b maint-2.30 v2.30.5\n    $ git merge cve-something-fix\n    ... edit release notes etc. ...\n    $ git commit -m 'Git 2.30.6'\n    $ git tag -s -m 'Git 2.30.6' v2.30.6\n\nbut after that is done, there is no reason to keep an old branch\nlike maint-2.30 lying around, other than to make it easier to\nprepare for v2.30.7 (as maint-2.30 will remember what tag was the\nlatest on that particular maintenance track).\n\n> The descriptions give the impression there is just a single main branch,\n> with a singular name, and that was the end of it.\n\nAnd that is the correct world view for most of the  general public.\n\n    https://github.com/git/git/\n\nshows 'maint', 'master' ('main'), 'next', and 'seen' from the\nproject code, plus 'todo' which holds an unrelated history that\nkeeps track of maintenance tools and misc stuff.\n\nBy the way, I do not personally have 'main' in my working\nrepository.  The only trick I have to help folks who expect to see\n'main' instead of 'master' is the push refspec to distribute the\nintegration results to various repositories.  My 'master' is pushed\nto both 'master' and 'main' in destination repositories.\n\nThe mirror/backup repository of my private working repository does\nhave tentive branches, like the broken-out topic branches that are\nstill active, which are pruned when they no longer are needed.\nSome maint-xx branches are also there but they are there not because\nthey are necessary but because I just haven't bothered to clean them\nup ;-)\n\n"},{"id":"464443","messageId":"xmqqa66588po.fsf@gitster.g","threadId":"58584","inReplyTo":"0b44cdca-3115-e09e-70c8-6f56101c3d9c@gmail.com","subject":"Re: [PATCH v2] symbolic-ref: teach \"--[no-]recurse\" option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-10-09T12:47:31Z","receivedAt":"2022-10-09T12:47:39Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Bagas Sanjaya <bagasdotme@gmail.com> writes:\n\n> On 10/8/22 11:34, Junio C Hamano wrote:\n>> Suppose you are managing many maintenance tracks in your project,\n>> and some of the more recent ones are maint-2.36 and maint-2.37.\n>\n> The example case above is from recent Git releases, right?\n\nIt is left to reader's imagination.  Concrete numbers are easier to\nunderstand, as it would be clear that 2.36 comes before 2.37 which\ncomes before 2.38.\n\n"},{"id":"464461","messageId":"xmqqy1to63y8.fsf_-_@gitster.g","threadId":"58584","inReplyTo":"xmqqsfjzaq78.fsf@gitster.g","subject":"[PATCH v3] symbolic-ref: teach \"--[no-]recurse\" option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-10-09T22:13:19Z","receivedAt":"2022-10-09T22:44:29Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Suppose you are managing many maintenance tracks in your project,\nand some of the more recent ones are maint-2.36 and maint-2.37.\nFurther imagine that your project recently tagged the official 2.38\nrelease, which means you would need to start maint-2.38 track soon,\nby doing:\n\n  $ git checkout -b maint-2.38 v2.38.0^0\n  $ git branch --list 'maint-2.3[6-9]'\n  * maint-2.38\n    maint-2.36\n    maint-2.37\n\nSo far, so good.  But it also is reasonable to want not to have to\nworry about which maintenance track is the latest, by pointing a\nmore generic-sounding 'maint' branch at it, by doing:\n\n  $ git symbolic-ref refs/heads/maint refs/heads/maint-2.38\n\nwhich would allow you to say \"whichever it is, check out the latest\nmaintenance track\", by doing:\n\n  $ git checkout maint\n  $ git branch --show-current\n  maint-2.38\n\nIt is arguably better to say that we are on 'maint-2.38' rather than\non 'maint', and \"git merge/pull\" would record \"into maint-2.38\" and\nnot \"into maint\", so I think what we have is a good behaviour.\n\nOne thing that is slightly irritating, however, is that I do not\nthink there is a good way (other than \"cat .git/HEAD\") to learn that\nyou checked out 'maint' to get into that state.  Just like the output\nof \"git branch --show-current\" shows above, \"git symbolic-ref HEAD\"\nwould report 'refs/heads/maint-2.38', bypassing the intermediate\nsymbolic ref at 'refs/heads/maint' that is pointed at by HEAD.\n\nThe internal resolve_ref() API already has the necessary support for\nstopping after resolving a single level of a symbolic-ref, and we\ncan expose it by adding a \"--[no-]recurse\" option to the command.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n\n * The third time is the charm?  The only change since v2 is to make\n   sure that Ævar's \"doc SYNOPSIS and cmd -h help must match\" topic\n   is not upset with the new option.\n\n Documentation/git-symbolic-ref.txt | 11 ++++++++++-\n builtin/symbolic-ref.c             | 18 +++++++++++-------\n t/t1401-symbolic-ref.sh            | 14 ++++++++++++++\n 3 files changed, 35 insertions(+), 8 deletions(-)\n\ndiff --git a/Documentation/git-symbolic-ref.txt b/Documentation/git-symbolic-ref.txt\nindex ef68ad2b71..102c83eb19 100644\n--- a/Documentation/git-symbolic-ref.txt\n+++ b/Documentation/git-symbolic-ref.txt\n@@ -9,7 +9,7 @@ SYNOPSIS\n --------\n [verse]\n 'git symbolic-ref' [-m <reason>] <name> <ref>\n-'git symbolic-ref' [-q] [--short] <name>\n+'git symbolic-ref' [-q] [--short] [--no-recurse] <name>\n 'git symbolic-ref' --delete [-q] <name>\n \n DESCRIPTION\n@@ -46,6 +46,15 @@ OPTIONS\n \tWhen showing the value of <name> as a symbolic ref, try to shorten the\n \tvalue, e.g. from `refs/heads/master` to `master`.\n \n+--recurse::\n+--no-recurse::\n+\tWhen showing the value of <name> as a symbolic ref, if\n+\t<name> refers to another symbolic ref, follow such a chain\n+\tof symbolic refs until the result no longer points at a\n+\tsymbolic ref (`--recurse`, which is the default).\n+\t`--no-recurse` stops after dereferencing only a single level\n+\tof symbolic ref.\n+\n -m::\n \tUpdate the reflog for <name> with <reason>.  This is valid only\n \twhen creating or updating a symbolic ref.\ndiff --git a/builtin/symbolic-ref.c b/builtin/symbolic-ref.c\nindex e547a08d6c..d5a70e7bd8 100644\n--- a/builtin/symbolic-ref.c\n+++ b/builtin/symbolic-ref.c\n@@ -6,14 +6,17 @@\n \n static const char * const git_symbolic_ref_usage[] = {\n \tN_(\"git symbolic-ref [<options>] <name> [<ref>]\"),\n-\tN_(\"git symbolic-ref -d [-q] <name>\"),\n+\tN_(\"git symbolic-ref -d [-q] [--no-recurse] <name>\"),\n \tNULL\n };\n \n-static int check_symref(const char *HEAD, int quiet, int shorten, int print)\n+static int check_symref(const char *HEAD, int quiet, int shorten, int recurse, int print)\n {\n-\tint flag;\n-\tconst char *refname = resolve_ref_unsafe(HEAD, 0, NULL, &flag);\n+\tint resolve_flags, flag;\n+\tconst char *refname;\n+\n+\tresolve_flags = (recurse ? 0 : RESOLVE_REF_NO_RECURSE);\n+\trefname = resolve_ref_unsafe(HEAD, resolve_flags, NULL, &flag);\n \n \tif (!refname)\n \t\tdie(\"No such ref: %s\", HEAD);\n@@ -35,13 +38,14 @@ static int check_symref(const char *HEAD, int quiet, int shorten, int print)\n \n int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)\n {\n-\tint quiet = 0, delete = 0, shorten = 0, ret = 0;\n+\tint quiet = 0, delete = 0, shorten = 0, recurse = 1, ret = 0;\n \tconst char *msg = NULL;\n \tstruct option options[] = {\n \t\tOPT__QUIET(&quiet,\n \t\t\tN_(\"suppress error message for non-symbolic (detached) refs\")),\n \t\tOPT_BOOL('d', \"delete\", &delete, N_(\"delete symbolic ref\")),\n \t\tOPT_BOOL(0, \"short\", &shorten, N_(\"shorten ref output\")),\n+\t\tOPT_BOOL(0, \"recurse\", &recurse, N_(\"recursively dereference (default)\")),\n \t\tOPT_STRING('m', NULL, &msg, N_(\"reason\"), N_(\"reason of the update\")),\n \t\tOPT_END(),\n \t};\n@@ -55,7 +59,7 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)\n \tif (delete) {\n \t\tif (argc != 1)\n \t\t\tusage_with_options(git_symbolic_ref_usage, options);\n-\t\tret = check_symref(argv[0], 1, 0, 0);\n+\t\tret = check_symref(argv[0], 1, 0, 0, 0);\n \t\tif (ret)\n \t\t\tdie(\"Cannot delete %s, not a symbolic ref\", argv[0]);\n \t\tif (!strcmp(argv[0], \"HEAD\"))\n@@ -65,7 +69,7 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)\n \n \tswitch (argc) {\n \tcase 1:\n-\t\tret = check_symref(argv[0], quiet, shorten, 1);\n+\t\tret = check_symref(argv[0], quiet, shorten, recurse, 1);\n \t\tbreak;\n \tcase 2:\n \t\tif (!strcmp(argv[0], \"HEAD\") &&\ndiff --git a/t/t1401-symbolic-ref.sh b/t/t1401-symbolic-ref.sh\nindex 132a1b885a..773a6e8e01 100755\n--- a/t/t1401-symbolic-ref.sh\n+++ b/t/t1401-symbolic-ref.sh\n@@ -163,4 +163,18 @@ test_expect_success 'symbolic-ref can resolve d/f name (ENOTDIR)' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'symbolic-ref pointing at another' '\n+\tgit update-ref refs/heads/maint-2.37 HEAD &&\n+\tgit symbolic-ref refs/heads/maint refs/heads/maint-2.37 &&\n+\tgit checkout maint &&\n+\n+\tgit symbolic-ref HEAD >actual &&\n+\techo refs/heads/maint-2.37 >expect &&\n+\ttest_cmp expect actual &&\n+\n+\tgit symbolic-ref --no-recurse HEAD >actual &&\n+\techo refs/heads/maint >expect &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\n-- \n2.38.0-167-gf9a88ca9e9\n\n"},{"id":"464615","messageId":"637a5629-66cf-7429-afc2-92709825e66d@iee.email","threadId":"58584","inReplyTo":"xmqqfsfx8akc.fsf@gitster.g","subject":"Re: [PATCH v2] symbolic-ref: teach \"--[no-]recurse\" option","fromName":"Philip Oakley","fromEmail":"philipoakley@iee.email","sentAt":"2022-10-11T14:49:02Z","receivedAt":"2022-10-11T14:49:09Z","isPatch":true,"sender":{"key":"philipoakley@iee.email","avatar":"https://avatars.githubusercontent.com/u/914343?v=4"},"body":"Hi Junio,\n\nOn 09/10/2022 13:07, Junio C Hamano wrote:\n> Philip Oakley <philipoakley@iee.email> writes:\n>\n>> Is there also a need to update SubmittingPatches to clarify the\n>> distinctions between the generic name 'maint', the specific `maint-xx`\n>> branches, and the symbolic ref linkages from `maint`.\n> Not at all.  Perhaps you are thinking about MaintNotes, but even\n> there, general public do not have to be concerned about maint-xx\n> most of the time.  I myself would not be keeping branches for\n> ancient maintenance tracks anywhere.  As the older maintenance\n> tracks, other than the most recent ones, do not get topics graduated\n> to 'master' merged down by me (even though topic branches that fix\n> notable bugs may fork from an older version to allow motivated third\n> party maintainers to merge them down to older maintenance releases),\n> there is not really a reason to keep branches like maint-2.15 for\n> daily operation.  Only when we need security updates that go back to\n> older maintenance tracks, I may do\n>\n>     $ git checkout -b maint-2.30 v2.30.5\n>     $ git merge cve-something-fix\n>     ... edit release notes etc. ...\n>     $ git commit -m 'Git 2.30.6'\n>     $ git tag -s -m 'Git 2.30.6' v2.30.6\n>\n> but after that is done, there is no reason to keep an old branch\n> like maint-2.30 lying around, other than to make it easier to\n> prepare for v2.30.7 (as maint-2.30 will remember what tag was the\n> latest on that particular maintenance track).\n>\n>> The descriptions give the impression there is just a single main branch,\n>> with a singular name, and that was the end of it.\n> And that is the correct world view for most of the  general public.\n>\n>     https://github.com/git/git/\n>\n> shows 'maint', 'master' ('main'), 'next', and 'seen' from the\n> project code, plus 'todo' which holds an unrelated history that\n> keeps track of maintenance tools and misc stuff.\n>\n> By the way, I do not personally have 'main' in my working\n> repository.  The only trick I have to help folks who expect to see\n> 'main' instead of 'master' is the push refspec to distribute the\n> integration results to various repositories.  My 'master' is pushed\n> to both 'master' and 'main' in destination repositories.\n>\n> The mirror/backup repository of my private working repository does\n> have tentive branches, like the broken-out topic branches that are\n> still active, which are pruned when they no longer are needed.\n> Some maint-xx branches are also there but they are there not because\n> they are necessary but because I just haven't bothered to clean them\n> up ;-)\n>\nThanks for the clarification.\n\nMy confusion about `maint` started quite a few years back and may be a\nmixture of a number of different issues, or simply my misunderstanding.\n\nI'm guessing here, but it may have been, that back then, that the maint\nbranch was a link to the relevant maint-xx, rather than a 'symref' and\nthat at that time the Git-for-Windows didn't really handle them, so\n`maint` may not have shown for me (similar to how RelNotes is configured\nin the Git repo).\n\nIt may also have been early confusion about remotes and their branches,\nand the impression that I needed (or should expect) a local branch of\nthe same name and this wasn't happening (obvious in retrospect), so I\nnever found any `maint` in my repo.\n\nThe whole 'remote tracking branches' stuff took a long time to\nunderstand and was non-obvious from my perspective. I suspect many\nnewbies have similar issues (e.g. the current thread\nhttps://lore.kernel.org/git/DU2P194MB15841850A17436C7AE34C149E3239@DU2P194MB1584.EURP194.PROD.OUTLOOK.COM/T/#t)\n\n--\nPhilip\n"}]}