{"thread":{"id":"65544","subject":"Bug: Hierarchical Aliases no longer work in 2.54.0","startedAt":"2026-04-23T18:19:46Z","lastAt":"2026-05-19T00:44:59Z","messageCount":18,"participants":["Grossfeld, Michael","Jeff King","René Scharfe","Michael Grossfeld","Jonatan Holmgren","Kristoffer Haugsbakk","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"542225","messageId":"PH7PR12MB73313034573C59C73F821BBFE52A2@PH7PR12MB7331.namprd12.prod.outlook.com","threadId":"65544","inReplyTo":null,"subject":"Bug: Hierarchical Aliases no longer work in 2.54.0","fromName":"Grossfeld, Michael","fromEmail":"michael.grossfeld@amd.com","sentAt":"2026-04-23T18:19:42Z","receivedAt":"2026-04-23T18:19:46Z","isPatch":false,"body":"Hello all! Seeing this issue on 2.54.0 and it didn't look like anyone had reported it yet.\n\n> What did you do before the bug happened? (Steps to reproduce your issue)\n\nAttempting to use the hierarchical alias \"pull.sub\", which was working in 2.53.0, is no longer working in 2.54.0.\nIt returns the following error: \"git: 'pull.sub' is not a git command. See 'git --help'.\"\n\n> What did you expect to happen? (Expected behavior)\n\nThe git alias should have firsted pulled, then updated submodules recursively.\n\n> What happened instead? (Actual behavior)\n\nIt reports the following error: \"git: 'pull.sub' is not a git command. See 'git --help'.\"\n\n> What's different between what you expected and what actually happened?\n\ngit 2.53.0 to git 2.54.0.\n\n> Anything else you want to add:\n\nThe alias was defined in my gitconfig as in 2.53.0, and remains this way:\n\n[alias \"pull\"]\n        sub = \"!f() { git pull origin --recurse-submodules=no --ff-only; echo Updating Submodules...; git submodule update --recursive --jobs=16 --progress; }; f\"\n\nIt was written via this command:\n        git config --global alias.pull.sub '!f() { git pull origin --recurse-submodules=no --ff-only -p; echo Updating Submodules...; git submodule update --recursive --jobs=16; }; f'\n\nTrying to do the following (with .command):\n        git config --global alias.pull.sub.command '!f() { git pull origin --recurse-submodules=no --ff-only -p; echo Updating Submodules...; git submodule update --recursive --jobs=16; }; f'\n\nResults in a section of the gitconfig that looks like this:\n\n[alias \"pull.sub\"]\n        command = \"!f() { git pull origin --recurse-submodules=no --ff-only -p; echo Updating Submodules...; git submodule update --recursive --jobs=16; }; f\"\n\n[System Info]\ngit version:\ngit version 2.54.0.windows.1\ncpu: x86_64\nbuilt from commit: 2b8a3ab140826ac423c2845ef81d4c6ac4f7bf3c\nsizeof-long: 4\nsizeof-size_t: 8\nshell-path: D:/git-sdk-64-build-installers/usr/bin/sh\nrust: disabled\nfeature: fsmonitor--daemon\ngettext: enabled\nlibcurl: 8.19.0\nOpenSSL: OpenSSL 3.5.6 7 Apr 2026\nzlib: 1.3.2\nSHA-1: SHA1_DC\nSHA-256: SHA256_BLK\ndefault-ref-format: files\ndefault-hash: sha1\nuname: Windows 10.0 26200\ncompiler info: gnuc: 15.2\nlibc info: no libc information available\n$SHELL (typically, interactive shell): D:\\develop\\tools\\Git\\usr\\bin\\bash.exe\n\nThanks for the help!\n\nMichael Grossfeld\nAMD"},{"id":"542226","messageId":"20260423211237.GA1906241@coredump.intra.peff.net","threadId":"65544","inReplyTo":"PH7PR12MB73313034573C59C73F821BBFE52A2@PH7PR12MB7331.namprd12.prod.outlook.com","subject":"Re: Bug: Hierarchical Aliases no longer work in 2.54.0","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2026-04-23T21:12:37Z","receivedAt":"2026-04-23T21:12:39Z","isPatch":false,"body":"On Thu, Apr 23, 2026 at 06:19:42PM +0000, Grossfeld, Michael wrote:\n\n> Hello all! Seeing this issue on 2.54.0 and it didn't look like anyone had reported it yet.\n\nThanks for the report. I think you're the first.\n\n> > What did you do before the bug happened? (Steps to reproduce your issue)\n> \n> Attempting to use the hierarchical alias \"pull.sub\", which was working\n> in 2.53.0, is no longer working in 2.54.0.\n> It returns the following error: \"git: 'pull.sub' is not a git command.\n> See 'git --help'.\"\n\nHere's a shorter reproduction recipe:\n\n  git -c alias.foo.bar='!echo ok' foo.bar\n\nWith v2.53 it produces \"ok\", and in v2.54 you get:\n\n  git: 'foo.bar' is not a git command. See 'git --help'.\n\nThis is due to the introduction of the three-level alias syntax in\nac1f12a9de (alias: support non-alphanumeric names via subsection syntax,\n2026-02-18). We now allow \"git foo\" to expand based on both alias.foo\nand alias.foo.command, the latter of which allows more flexible syntax.\n\nBut now we think you are trying to set the \"sub\" key of the \"pull\"\nalias, which is obviously nonsense. I don't think three-level config\nlike this was ever a planned feature in the original alias expansion,\nbut it did indeed work. So I think this is a regression worth fixing.\n\nIn the short-term, you can work around it by using the new syntax:\n\n  [alias \"pull.sub\"]\n  command = ...whatever...\n\nAnd I think we'd want a fix something like this:\n\ndiff --git a/alias.c b/alias.c\nindex ec9833dd30..58f21ac6ba 100644\n--- a/alias.c\n+++ b/alias.c\n@@ -34,8 +34,20 @@ static int config_alias_cb(const char *var, const char *value,\n \tif (subsection && !subsection_len)\n \t\tsubsection = NULL;\n \n-\tif (subsection && strcmp(key, \"command\"))\n-\t\treturn 0;\n+\tif (subsection && strcmp(key, \"command\")) {\n+\t\t/*\n+\t\t * We have historically support the \"alias.name\" form when\n+\t\t * \"name\" happens to contain dots (e.g., alias.foo.bar to allow\n+\t\t * \"git foo.bar\". But our parsing above would split that into\n+\t\t * subsection \"foo\".\n+\t\t *\n+\t\t * If we do not understand the final key in a subsection-style\n+\t\t * variable, fall back to treating it as a two-level alias.\n+\t\t */\n+\t\tkey = subsection;\n+\t\tsubsection = NULL;\n+\t\tsubsection_len = 0;\n+\t}\n \n \tif (data->alias) {\n \t\tint match;\n\nThat does still break a historical alias if you happened to call it\n\"foo.command\". I'm not sure if we want to try to be even more thorough\nand fall back on that case, or if we're getting now into unlikely\nhypotheticals.\n\n-Peff\n"},{"id":"542230","messageId":"ea07acab-313d-435d-8328-e601fee980c3@web.de","threadId":"65544","inReplyTo":"PH7PR12MB73313034573C59C73F821BBFE52A2@PH7PR12MB7331.namprd12.prod.outlook.com","subject":"Re: Bug: Hierarchical Aliases no longer work in 2.54.0","fromName":"René Scharfe","fromEmail":"l.s.r@web.de","sentAt":"2026-04-23T21:36:39Z","receivedAt":"2026-04-23T22:02:22Z","isPatch":false,"body":"On 4/23/26 8:19 PM, Grossfeld, Michael wrote:\n> Hello all! Seeing this issue on 2.54.0 and it didn't look like anyone had reported it yet.\n> \n>> What did you do before the bug happened? (Steps to reproduce your issue)\n> \n> Attempting to use the hierarchical alias \"pull.sub\", which was working in 2.53.0, is no longer working in 2.54.0.\n> It returns the following error: \"git: 'pull.sub' is not a git command. See 'git --help'.\"\n> >> What did you expect to happen? (Expected behavior)\n> \n> The git alias should have firsted pulled, then updated submodules recursively.\n> \n>> What happened instead? (Actual behavior)\n> \n> It reports the following error: \"git: 'pull.sub' is not a git command. See 'git --help'.\"\n> \n>> What's different between what you expected and what actually happened?\n> \n> git 2.53.0 to git 2.54.0.\n> \n>> Anything else you want to add:\n> \n> The alias was defined in my gitconfig as in 2.53.0, and remains this way:\n> \n> [alias \"pull\"]\n>         sub = \"!f() { git pull origin --recurse-submodules=no --ff-only; echo Updating Submodules...; git submodule update --recursive --jobs=16 --progress; }; f\"\n\nBroken by ac1f12a9de4 (alias: support non-alphanumeric names via\nsubsection syntax, 2026-02-18).\n\nAlias sections were not documented before.  How did you discover them?\n\nI think the previous behavior can be brought back while keeping the\nnew feature, except for aliases that end in \".command\".\n\n> It was written via this command:\n>         git config --global alias.pull.sub '!f() { git pull origin --recurse-submodules=no --ff-only -p; echo Updating Submodules...; git submodule update --recursive --jobs=16; }; f'\n> \n> Trying to do the following (with .command):\n>         git config --global alias.pull.sub.command '!f() { git pull origin --recurse-submodules=no --ff-only -p; echo Updating Submodules...; git submodule update --recursive --jobs=16; }; f'\n> \n> Results in a section of the gitconfig that looks like this:\n> \n> [alias \"pull.sub\"]\n>         command = \"!f() { git pull origin --recurse-submodules=no --ff-only -p; echo Updating Submodules...; git submodule update --recursive --jobs=16; }; f\"\n\nWhich works, right?\n\n> [System Info]\n> git version:\n> git version 2.54.0.windows.1\n> cpu: x86_64\n> built from commit: 2b8a3ab140826ac423c2845ef81d4c6ac4f7bf3c\n> sizeof-long: 4\n> sizeof-size_t: 8\n> shell-path: D:/git-sdk-64-build-installers/usr/bin/sh\n> rust: disabled\n> feature: fsmonitor--daemon\n> gettext: enabled\n> libcurl: 8.19.0\n> OpenSSL: OpenSSL 3.5.6 7 Apr 2026\n> zlib: 1.3.2\n> SHA-1: SHA1_DC\n> SHA-256: SHA256_BLK\n> default-ref-format: files\n> default-hash: sha1\n> uname: Windows 10.0 26200\n> compiler info: gnuc: 15.2\n> libc info: no libc information available\n> $SHELL (typically, interactive shell): D:\\develop\\tools\\Git\\usr\\bin\\bash.exe\n> \n> Thanks for the help!\n> \n> Michael Grossfeld\n> AMD\n\n"},{"id":"542231","messageId":"20260423224653.893-1-Michael.Grossfeld@amd.com","threadId":"65544","inReplyTo":"ea07acab-313d-435d-8328-e601fee980c3@web.de","subject":"Re: Bug: Hierarchical Aliases no longer work in 2.54.0","fromName":"Michael Grossfeld","fromEmail":"michael.grossfeld@amd.com","sentAt":"2026-04-23T22:46:53Z","receivedAt":"2026-04-23T22:47:17Z","isPatch":false,"body":"> Broken by ac1f12a9de4 (alias: support non-alphanumeric names via\n> subsection syntax, 2026-02-18).\n\n> Alias sections were not documented before.  How did you discover them?\n\nSheer dumb luck. I gravitated to it rather than a dash/hyphen based approach when I was creating aliases for my team.\n\n> I think the previous behavior can be brought back while keeping the\n> new feature, except for aliases that end in \".command\".\n\nThat would work for me.\n\n> Which works, right?\n\nYes, doing 'alias.pull.sub.command' works, but for the users on my team that have the old aliases, they are crashing.\n"},{"id":"542235","messageId":"20260423225511.924-1-Michael.Grossfeld@amd.com","threadId":"65544","inReplyTo":"20260423211237.GA1906241@coredump.intra.peff.net","subject":"Re: Bug: Hierarchical Aliases no longer work in 2.54.0","fromName":"Michael Grossfeld","fromEmail":"michael.grossfeld@amd.com","sentAt":"2026-04-23T22:55:11Z","receivedAt":"2026-04-23T22:55:23Z","isPatch":false,"body":"> In the short-term, you can work around it by using the new syntax:\n>\n>  [alias \"pull.sub\"]\n>  command = ...whatever...\n\nSounds good. I'll likely write a script for my team to convert their\nexisting aliases depending on their git version.\n\n> That does still break a historical alias if you happened to call it\n> \"foo.command\". I'm not sure if we want to try to be even more thorough\n> and fall back on that case, or if we're getting now into unlikely\n> hypotheticals.\n\nFor my purposes, this would be fine and work for me. As the hierarchical\naliases are already unlikely, I imagine \"foo.command\" existing is even more\nunlikely.\n"},{"id":"542238","messageId":"c81fb8a8-f9dc-4922-82bd-3c7769a44fbd@jontes.page","threadId":"65544","inReplyTo":"PH7PR12MB73313034573C59C73F821BBFE52A2@PH7PR12MB7331.namprd12.prod.outlook.com","subject":"Re: Bug: Hierarchical Aliases no longer work in 2.54.0","fromName":"Jonatan Holmgren","fromEmail":"jonatan@jontes.page","sentAt":"2026-04-24T07:29:30Z","receivedAt":"2026-04-24T07:35:57Z","isPatch":false,"body":"That's a curious bug, sorry to hear I broke you/your team's workflow.  \nYes, three-level aliases were previously accidentally supported, now \nexplicitly but with a new syntax (this was to support non-ascii \ncharacters). I'll send a patch fixing this but a release cycle will \nindeed take time.\n\nThanks!\n"},{"id":"542259","messageId":"20260424151053.917066-1-jonatan@jontes.page","threadId":"65544","inReplyTo":"PH7PR12MB73313034573C59C73F821BBFE52A2@PH7PR12MB7331.namprd12.prod.outlook.com","subject":"[PATCH] alias: restore support for simple dotted aliases","fromName":"Jonatan Holmgren","fromEmail":"jonatan@jontes.page","sentAt":"2026-04-24T15:10:48Z","receivedAt":"2026-04-24T15:20:25Z","isPatch":true,"body":"Historically, config entries like alias.foo.bar expanded the alias\n\"foo.bar\". The subsection-based alias syntax introduced in\nac1f12a9de (alias: support non-alphanumeric names via subsection\nsyntax, 2026-02-18) broke that behavior by treating such entries as\nif they were subsection syntax.\n\nRestore support for the old dotted form by falling back to the full\nname when the final key is not \"command\". Add tests covering execution\nand help output for simple dotted aliases.\n\nReported-by: Michael Grossfeld <michael.grossfeld@amd.com>\nHelped-by: Jeff King <peff@peff.net>\n---\n alias.c          | 16 ++++++++++++++--\n help.c           |  9 ++++++++-\n t/t0014-alias.sh | 12 ++++++++++++\n 3 files changed, 34 insertions(+), 3 deletions(-)\n\ndiff --git a/alias.c b/alias.c\nindex ec9833dd30..e737c49edd 100644\n--- a/alias.c\n+++ b/alias.c\n@@ -34,8 +34,20 @@ static int config_alias_cb(const char *var, const char *value,\n \tif (subsection && !subsection_len)\n \t\tsubsection = NULL;\n \n-\tif (subsection && strcmp(key, \"command\"))\n-\t\treturn 0;\n+\tif (subsection && strcmp(key, \"command\")) {\n+\t\t/*\n+\t\t * We have historically supported the \"alias.name\" form when\n+\t\t * \"name\" happens to contain dots (e.g., alias.foo.bar to allow\n+\t\t * \"git foo.bar\". But our parsing above would split that into\n+\t\t * subsection \"foo\".\n+\t\t *\n+\t\t * If we do not understand the final key in a subsection-style\n+\t\t * variable, fall back to treating it as a two-level alias.\n+\t\t */\n+\t\tkey = var + strlen(\"alias.\");\n+\t\tsubsection = NULL;\n+\t\tsubsection_len = 0;\n+\t}\n \n \tif (data->alias) {\n \t\tint match;\ndiff --git a/help.c b/help.c\nindex 3e59d07c37..46241492ce 100644\n--- a/help.c\n+++ b/help.c\n@@ -592,14 +592,21 @@ static int git_unknown_cmd_config(const char *var, const char *value,\n \t/* Also use aliases for command lookup */\n \tif (!parse_config_key(var, \"alias\", &subsection, &subsection_len,\n \t\t\t      &key)) {\n+\t\tsize_t key_len = strlen(key);\n+\n \t\tif (subsection) {\n \t\t\t/* [alias \"name\"] command = value */\n \t\t\tif (!strcmp(key, \"command\"))\n \t\t\t\tadd_cmdname(&cfg->aliases, subsection,\n \t\t\t\t\t    subsection_len);\n+\t\t\telse {\n+\t\t\t\tkey = var + strlen(\"alias.\");\n+\t\t\t\tkey_len = strlen(key);\n+\t\t\t\tadd_cmdname(&cfg->aliases, key, key_len);\n+\t\t\t}\n \t\t} else {\n \t\t\t/* alias.name = value */\n-\t\t\tadd_cmdname(&cfg->aliases, key, strlen(key));\n+\t\t\tadd_cmdname(&cfg->aliases, key, key_len);\n \t\t}\n \t}\n \ndiff --git a/t/t0014-alias.sh b/t/t0014-alias.sh\nindex 68b4903cbf..5144b0effd 100755\n--- a/t/t0014-alias.sh\n+++ b/t/t0014-alias.sh\n@@ -128,6 +128,12 @@ test_expect_success 'subsection syntax works' '\n \ttest_grep \"ran-subsection\" output\n '\n \n+test_expect_success 'simple dotted alias syntax still works' '\n+\ttest_config alias.simple.dotted \"!echo ran-simple-dotted\" &&\n+\tgit simple.dotted >output &&\n+\ttest_grep \"ran-simple-dotted\" output\n+'\n+\n test_expect_success 'subsection syntax only accepts command key' '\n \ttest_config alias.invalid.notcommand value &&\n \ttest_must_fail git invalid 2>error &&\n@@ -183,6 +189,12 @@ test_expect_success 'subsection aliases listed in help -a' '\n \ttest_grep \"förgrena\" output\n '\n \n+test_expect_success 'simple dotted aliases listed in help -a' '\n+\ttest_config alias.simple.listed \"!echo test\" &&\n+\tgit help -a >output &&\n+\ttest_grep \"simple.listed\" output\n+'\n+\n test_expect_success 'empty subsection treated as no subsection' '\n \ttest_config \"alias..something\" \"!echo foobar\" &&\n \tgit something >actual &&\n-- \n2.54.0\n\n"},{"id":"542262","messageId":"38188193-e6ab-40bf-950a-c516aec71d5d@app.fastmail.com","threadId":"65544","inReplyTo":"20260424151053.917066-1-jonatan@jontes.page","subject":"Re: [PATCH] alias: restore support for simple dotted aliases","fromName":"Kristoffer Haugsbakk","fromEmail":"kristofferhaugsbakk@fastmail.com","sentAt":"2026-04-24T16:09:45Z","receivedAt":"2026-04-24T16:10:07Z","isPatch":true,"body":"On Fri, Apr 24, 2026, at 17:10, Jonatan Holmgren wrote:\n> Historically, config entries like alias.foo.bar expanded the alias\n> \"foo.bar\". The subsection-based alias syntax introduced in\n> ac1f12a9de (alias: support non-alphanumeric names via subsection\n> syntax, 2026-02-18) broke that behavior by treating such entries as\n> if they were subsection syntax.\n>\n> Restore support for the old dotted form by falling back to the full\n> name when the final key is not \"command\". Add tests covering execution\n> and help output for simple dotted aliases.\n>\n> Reported-by: Michael Grossfeld <michael.grossfeld@amd.com>\n> Helped-by: Jeff King <peff@peff.net>\n\nMissing signoff.\n\n> ---\n>[snip]\n"},{"id":"542263","messageId":"20260424161707.1514255-1-jonatan@jontes.page","threadId":"65544","inReplyTo":"PH7PR12MB73313034573C59C73F821BBFE52A2@PH7PR12MB7331.namprd12.prod.outlook.com","subject":"[PATCH] alias: restore support for simple dotted aliases","fromName":"Jonatan Holmgren","fromEmail":"jonatan@jontes.page","sentAt":"2026-04-24T16:17:00Z","receivedAt":"2026-04-24T16:27:18Z","isPatch":true,"body":"Historically, config entries like alias.foo.bar expanded the alias\n\"foo.bar\". The subsection-based alias syntax introduced in\nac1f12a9de (alias: support non-alphanumeric names via subsection\nsyntax, 2026-02-18) broke that behavior by treating such entries as\nif they were subsection syntax.\n\nRestore support for the old dotted form by falling back to the full\nname when the final key is not \"command\". Add tests covering execution\nand help output for simple dotted aliases.\n\nReported-by: Michael Grossfeld <michael.grossfeld@amd.com>\nHelped-by: Jeff King <peff@peff.net>\nSigned-off-by: Jonatan Holmgren <jonatan@jontes.page>\n---\n alias.c          | 16 ++++++++++++++--\n help.c           |  9 ++++++++-\n t/t0014-alias.sh | 12 ++++++++++++\n 3 files changed, 34 insertions(+), 3 deletions(-)\n\ndiff --git a/alias.c b/alias.c\nindex ec9833dd30..e737c49edd 100644\n--- a/alias.c\n+++ b/alias.c\n@@ -34,8 +34,20 @@ static int config_alias_cb(const char *var, const char *value,\n \tif (subsection && !subsection_len)\n \t\tsubsection = NULL;\n \n-\tif (subsection && strcmp(key, \"command\"))\n-\t\treturn 0;\n+\tif (subsection && strcmp(key, \"command\")) {\n+\t\t/*\n+\t\t * We have historically supported the \"alias.name\" form when\n+\t\t * \"name\" happens to contain dots (e.g., alias.foo.bar to allow\n+\t\t * \"git foo.bar\". But our parsing above would split that into\n+\t\t * subsection \"foo\".\n+\t\t *\n+\t\t * If we do not understand the final key in a subsection-style\n+\t\t * variable, fall back to treating it as a two-level alias.\n+\t\t */\n+\t\tkey = var + strlen(\"alias.\");\n+\t\tsubsection = NULL;\n+\t\tsubsection_len = 0;\n+\t}\n \n \tif (data->alias) {\n \t\tint match;\ndiff --git a/help.c b/help.c\nindex 3e59d07c37..46241492ce 100644\n--- a/help.c\n+++ b/help.c\n@@ -592,14 +592,21 @@ static int git_unknown_cmd_config(const char *var, const char *value,\n \t/* Also use aliases for command lookup */\n \tif (!parse_config_key(var, \"alias\", &subsection, &subsection_len,\n \t\t\t      &key)) {\n+\t\tsize_t key_len = strlen(key);\n+\n \t\tif (subsection) {\n \t\t\t/* [alias \"name\"] command = value */\n \t\t\tif (!strcmp(key, \"command\"))\n \t\t\t\tadd_cmdname(&cfg->aliases, subsection,\n \t\t\t\t\t    subsection_len);\n+\t\t\telse {\n+\t\t\t\tkey = var + strlen(\"alias.\");\n+\t\t\t\tkey_len = strlen(key);\n+\t\t\t\tadd_cmdname(&cfg->aliases, key, key_len);\n+\t\t\t}\n \t\t} else {\n \t\t\t/* alias.name = value */\n-\t\t\tadd_cmdname(&cfg->aliases, key, strlen(key));\n+\t\t\tadd_cmdname(&cfg->aliases, key, key_len);\n \t\t}\n \t}\n \ndiff --git a/t/t0014-alias.sh b/t/t0014-alias.sh\nindex 68b4903cbf..5144b0effd 100755\n--- a/t/t0014-alias.sh\n+++ b/t/t0014-alias.sh\n@@ -128,6 +128,12 @@ test_expect_success 'subsection syntax works' '\n \ttest_grep \"ran-subsection\" output\n '\n \n+test_expect_success 'simple dotted alias syntax still works' '\n+\ttest_config alias.simple.dotted \"!echo ran-simple-dotted\" &&\n+\tgit simple.dotted >output &&\n+\ttest_grep \"ran-simple-dotted\" output\n+'\n+\n test_expect_success 'subsection syntax only accepts command key' '\n \ttest_config alias.invalid.notcommand value &&\n \ttest_must_fail git invalid 2>error &&\n@@ -183,6 +189,12 @@ test_expect_success 'subsection aliases listed in help -a' '\n \ttest_grep \"förgrena\" output\n '\n \n+test_expect_success 'simple dotted aliases listed in help -a' '\n+\ttest_config alias.simple.listed \"!echo test\" &&\n+\tgit help -a >output &&\n+\ttest_grep \"simple.listed\" output\n+'\n+\n test_expect_success 'empty subsection treated as no subsection' '\n \ttest_config \"alias..something\" \"!echo foobar\" &&\n \tgit something >actual &&\n-- \n2.54.0\n\n"},{"id":"542283","messageId":"xmqqpl3ovuvq.fsf@gitster.g","threadId":"65544","inReplyTo":"20260424151053.917066-1-jonatan@jontes.page","subject":"Re: [PATCH] alias: restore support for simple dotted aliases","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-04-24T22:47:05Z","receivedAt":"2026-04-24T22:47:08Z","isPatch":true,"body":"Jonatan Holmgren <jonatan@jontes.page> writes:\n\n> Historically, config entries like alias.foo.bar expanded the alias\n> \"foo.bar\". The subsection-based alias syntax introduced in\n> ac1f12a9de (alias: support non-alphanumeric names via subsection\n> syntax, 2026-02-18) broke that behavior by treating such entries as\n> if they were subsection syntax.\n>\n> Restore support for the old dotted form by falling back to the full\n> name when the final key is not \"command\". Add tests covering execution\n> and help output for simple dotted aliases.\n>\n> Reported-by: Michael Grossfeld <michael.grossfeld@amd.com>\n> Helped-by: Jeff King <peff@peff.net>\n> ---\n>  alias.c          | 16 ++++++++++++++--\n>  help.c           |  9 ++++++++-\n>  t/t0014-alias.sh | 12 ++++++++++++\n>  3 files changed, 34 insertions(+), 3 deletions(-)\n\nDo we lose the extensibility introduced by the new syntax by going\nthis route, though?  I would imagine that\n\n    [alias \"frotz\"]\n\tcommand = !\"nitfol\"\n\thelp = \"run nitfol command\"\n\nwould have been a natural first addition to the current system to\ngive help text to the alias, but this change makes such an\nextensibility impossible, doesn't it?\n\nIf this change robs the extensibility, it makes mse wonder if the\nthree-level \"alias\" was a mistake, and we should have instead\nintroduced a new \"nalias\" that is three level from the get go.\n"},{"id":"542286","messageId":"40408c99-7e2a-4cf6-b9b2-6d0e0da3b2c5@jontes.page","threadId":"65544","inReplyTo":"xmqqpl3ovuvq.fsf@gitster.g","subject":"Re: [PATCH] alias: restore support for simple dotted aliases","fromName":"Jonatan Holmgren","fromEmail":"jonatan@jontes.page","sentAt":"2026-04-25T09:57:24Z","receivedAt":"2026-04-25T09:57:30Z","isPatch":true,"body":"That is a challenge we are going to have to consider. I think reserving\n`command` is a worthwhile compromise, but obviously we cannot do that for\narbitrary future keys such as `help`, `hidden`, etc.\n\nOne possible compromise would be to reserve `command` and `alias-*`, as\nneither seems very likely to exist in users' historical alias names.\n\nA new namespace makes the most sense from a namespace-pollution point of\nview, but I struggle to see that as good UX. Even a separate namespace\nonly for alias metadata would make more sense to me than moving aliases\nentirely, since subsection aliases with just `command` will likely be \nfar more common than any future metadata keys, but this is not something \nI see as a good solution either.\n"},{"id":"542310","messageId":"20260425232916.GA29816@coredump.intra.peff.net","threadId":"65544","inReplyTo":"40408c99-7e2a-4cf6-b9b2-6d0e0da3b2c5@jontes.page","subject":"Re: [PATCH] alias: restore support for simple dotted aliases","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2026-04-25T23:29:16Z","receivedAt":"2026-04-25T23:29:18Z","isPatch":true,"body":"On Sat, Apr 25, 2026 at 11:57:24AM +0200, Jonatan Holmgren wrote:\n\n> That is a challenge we are going to have to consider. I think reserving\n> `command` is a worthwhile compromise, but obviously we cannot do that for\n> arbitrary future keys such as `help`, `hidden`, etc.\n\nWe don't necessarily have to reserve them. When we see alias.foo.bar, we\ncould consider it as both alias \"foo.bar\" and the \"bar\" key of alias\n\"foo\", without regard to what is in \"bar\" (i.e., whether it is \"command\"\nor \"help\", etc). I.e., don't \"fall back\" but allow two overlapping\nnamespace.s\n\nThat is the most backwards-compatible thing we could do, but does create\nsome interesting situations.\n\nIf you define alias.foo.command with the intent to allow \"git foo\", that\nis also creating the identical alias \"git foo.command\". Probably nobody\ncares too much, as if you did not mean to make \"foo.command\" you would\nnever invoke it. We'd probably want to omit it when listing aliases,\nthough.\n\nIf we later introduce alias.foo.help, the same thing applies but with a\ntwist. Running \"git foo.help\" will invoke that key as an alias command,\nbut it is probably not a sensible command in the first place. But again,\nI'm not sure why anybody would try to do so.\n\n\nThat said, I don't think reserving \"command\" or even some future names\nis that painful in the long run. The three-level syntax is a superset of\nthe old functionality, and in general the best solution will be for\nusers to convert their old aliases to it. The benefits of providing the\nfallback compatibility are:\n\n  1. Users can avoid having to do anything at all. And that will still\n     be true for the majority, unless they happen to have a three-level\n     alias that ends with \".command\" (for now) or eventually \".help\",\n     etc. We don't have any hard data, but I have to imagine that the\n     numbers here are vanishingly small.\n\n  2. Cross-version compatibility. You can't use alias.pull.sub.command\n     in Git v2.53 and older, so it's otherwise impossible to have config\n     that works both there and with v2.54.\n\n     But as time goes on, wanting to cross that version boundary becomes\n     less and less likely. If we we eventually introduce \".help\" and it\n     breaks somebody foo.help alias, suggesting alias.foo.help.command\n     will work all the way back to Git v2.54, which may be sufficient.\n\n> One possible compromise would be to reserve `command` and `alias-*`, as\n> neither seems very likely to exist in users' historical alias names.\n> \n> A new namespace makes the most sense from a namespace-pollution point of\n> view, but I struggle to see that as good UX. Even a separate namespace\n> only for alias metadata would make more sense to me than moving aliases\n> entirely, since subsection aliases with just `command` will likely be far\n> more common than any future metadata keys, but this is not something I see\n> as a good solution either.\n\nYeah. Obviously a totally separate namespace makes all of this go away,\nbut it feels like we are sacrificing the experience going forward in\norder to accommodate some fairly unlikely historical clashes.\n\n-Peff\n"},{"id":"542311","messageId":"20260425234700.GB29816@coredump.intra.peff.net","threadId":"65544","inReplyTo":"20260425232916.GA29816@coredump.intra.peff.net","subject":"Re: [PATCH] alias: restore support for simple dotted aliases","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2026-04-25T23:47:00Z","receivedAt":"2026-04-25T23:47:02Z","isPatch":true,"body":"On Sat, Apr 25, 2026 at 07:29:16PM -0400, Jeff King wrote:\n\n> On Sat, Apr 25, 2026 at 11:57:24AM +0200, Jonatan Holmgren wrote:\n> \n> > That is a challenge we are going to have to consider. I think reserving\n> > `command` is a worthwhile compromise, but obviously we cannot do that for\n> > arbitrary future keys such as `help`, `hidden`, etc.\n> \n> We don't necessarily have to reserve them. When we see alias.foo.bar, we\n> could consider it as both alias \"foo.bar\" and the \"bar\" key of alias\n> \"foo\", without regard to what is in \"bar\" (i.e., whether it is \"command\"\n> or \"help\", etc). I.e., don't \"fall back\" but allow two overlapping\n> namespace.s\n> \n> That is the most backwards-compatible thing we could do, but does create\n> some interesting situations.\n\nFor reference, I mean something like this:\n\ndiff --git a/alias.c b/alias.c\nindex ec9833dd30..07c6bd3645 100644\n--- a/alias.c\n+++ b/alias.c\n@@ -34,16 +34,20 @@ static int config_alias_cb(const char *var, const char *value,\n \tif (subsection && !subsection_len)\n \t\tsubsection = NULL;\n \n-\tif (subsection && strcmp(key, \"command\"))\n-\t\treturn 0;\n-\n \tif (data->alias) {\n \t\tint match;\n \n \t\tif (subsection)\n-\t\t\tmatch = (strlen(data->alias) == subsection_len &&\n-\t\t\t\t !strncmp(data->alias, subsection,\n-\t\t\t\t\t  subsection_len));\n+\t\t\t/*\n+\t\t\t * alias.foo.command always matches \"foo\", but for\n+\t\t\t * historical compatibility also match alias.foo.bar as\n+\t\t\t * \"foo.bar\", even when \"bar\" is \"command\" or any other\n+\t\t\t * key we happen to know about.\n+\t\t\t */\n+\t\t\tmatch = (!strcmp(key, \"command\") &&\n+\t\t\t\t strlen(data->alias) == subsection_len &&\n+\t\t\t\t !strncmp(data->alias, subsection, subsection_len))\n+\t\t\t\t|| !strcmp(data->alias, subsection);\n \t\telse\n \t\t\tmatch = !strcasecmp(data->alias, key);\n \n@@ -59,8 +63,23 @@ static int config_alias_cb(const char *var, const char *value,\n \t\t\treturn config_error_nonbool(var);\n \n \t\tif (subsection)\n+\t\t\t/*\n+\t\t\t * If it's not alias.foo.command, then either it's a\n+\t\t\t * historical alias (git \"foo.bar\"), or it's some\n+\t\t\t * metadata not support yet by this version\n+\t\t\t * (\"alias.foo.help\" or similar).\n+\t\t\t *\n+\t\t\t * We'll guess it's the former and include the whole\n+\t\t\t * \"foo.bar\" in the list.\n+\t\t\t *\n+\t\t\t * We might want to suppress duplicates when we see both\n+\t\t\t * alias.foo.command and alias.foo.help, since that's\n+\t\t\t * what a hypothetical future version might understand.\n+\t\t\t */\n \t\t\titem = string_list_append_nodup(data->list,\n-\t\t\t\txmemdupz(subsection, subsection_len));\n+\t\t\t\t\t\t\t!strcmp(key, \"command\")\n+\t\t\t\t\t\t\t? xmemdupz(subsection, subsection_len)\n+\t\t\t\t\t\t\t: xstrdup(subsection));\n \t\telse\n \t\t\titem = string_list_append(data->list, key);\n \t\titem->util = xstrdup(value);\n\n-Peff\n"},{"id":"542335","messageId":"4a130a23-fa32-460b-a338-409d85d18166@jontes.page","threadId":"65544","inReplyTo":"20260425232916.GA29816@coredump.intra.peff.net","subject":"Re: [PATCH] alias: restore support for simple dotted aliases","fromName":"Jonatan Holmgren","fromEmail":"jonatan@jontes.page","sentAt":"2026-04-26T19:21:52Z","receivedAt":"2026-04-26T19:27:45Z","isPatch":true,"body":"I see the appeal of the overlapping-namespace approach for maximum compat.\n\nMy hesitation is that it introduces a config model where a single key\n(`alias.foo.bar`) no longer has a clear interpretation, but instead is\nimplicitly treated as both a historical alias and structured data. That\nfeels harder to reason about and document.\n\nFor the regression, I would lean toward a narrower compatibility rule:\nrestore dotted aliases except where they collide with explicitly\nrecognized structured keys (currently `command`). That keeps behavior\npredictable while still fixing the breakage.\n\nIf we want to grow metadata in the future, it might be better to make\nthat expansion explicit at that point rather than baking in ambiguity\nnow.\n\nI think the worst outcome from this thread would be moving the\nnew alias syntax into a different namespace entirely (e.g., `nalias`).\nIf namespace cleanliness is the priority, reserving `command` and\n`alias-*` still seems like the best path forward to me.\n\nOne question: do we consider the historical dotted aliases something we\nwant to preserve indefinitely, or just something to transition away from?\nMy assumption has been that they were an accidental side-effect of the\nconfig parsing rather than a designed feature, but I agree they are now\npart of existing workflows and need to be handled carefully.\n"},{"id":"542336","messageId":"20260426230125.GA218434@coredump.intra.peff.net","threadId":"65544","inReplyTo":"4a130a23-fa32-460b-a338-409d85d18166@jontes.page","subject":"Re: [PATCH] alias: restore support for simple dotted aliases","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2026-04-26T23:01:25Z","receivedAt":"2026-04-26T23:01:34Z","isPatch":true,"body":"On Sun, Apr 26, 2026 at 09:21:52PM +0200, Jonatan Holmgren wrote:\n\n> I see the appeal of the overlapping-namespace approach for maximum compat.\n> \n> My hesitation is that it introduces a config model where a single key\n> (`alias.foo.bar`) no longer has a clear interpretation, but instead is\n> implicitly treated as both a historical alias and structured data. That\n> feels harder to reason about and document.\n> \n> For the regression, I would lean toward a narrower compatibility rule:\n> restore dotted aliases except where they collide with explicitly\n> recognized structured keys (currently `command`). That keeps behavior\n> predictable while still fixing the breakage.\n\nYeah, I agree with you here (and the rest of this email). My earlier\nmessage was mostly about laying out the possible alternatives.\n\n> One question: do we consider the historical dotted aliases something we\n> want to preserve indefinitely, or just something to transition away from?\n> My assumption has been that they were an accidental side-effect of the\n> config parsing rather than a designed feature, but I agree they are now\n> part of existing workflows and need to be handled carefully.\n\nI think it would be OK to consider them a historical curiosity that may\neventually be removed, but without an active deprecation timeline. If\nyou do not need to work with older versions of Git it is already a good\nidea to move to the new syntax because it prevents your alias being\ncaught up if further keys are added. It might be reasonable for the\ndocumentation to note that (and of course also mention the downside,\nwhich is that older versions of Git will not respect your alias).\n\nWe could eventually drop support, but I think it would have to be\neither:\n\n  1. In some distant version such that \"pre-2.54\" is considered ancient.\n\n  2. At some version boundary where we declare a number of breaking\n     changes. Git 3.0 is probably going to such a version, but I don't\n     know if we have a concrete timeline (or how long we'd want a\n     change to be in the \"breaking changes\" list in the build-up to that\n     version).\n\nThere's a related question, too, about whether \"alias.foo\" (without\nextra dots) could/should be dropped eventually. I don't see a particular\nreason to do so, as the cost to carrying support is quite minimal.\n\n-Peff\n"},{"id":"542349","messageId":"d1170f92-3690-4fa4-8070-75ac9f119174@jontes.page","threadId":"65544","inReplyTo":"20260426230125.GA218434@coredump.intra.peff.net","subject":"Re: [PATCH] alias: restore support for simple dotted aliases","fromName":"Jonatan Holmgren","fromEmail":"jonatan@jontes.page","sentAt":"2026-04-27T08:36:55Z","receivedAt":"2026-04-27T08:37:02Z","isPatch":true,"body":"Sorry, that wasn't a \"hey we should deprecate this\" code-wise, I was \nasking from a documentation point of view, i.e. was curious how you felt \nabout what is \"advisable\". Shouldn't've included that in my email\n"},{"id":"543131","messageId":"xmqqbjelp7ab.fsf@gitster.g","threadId":"65544","inReplyTo":"d1170f92-3690-4fa4-8070-75ac9f119174@jontes.page","subject":"Re: [PATCH] alias: restore support for simple dotted aliases","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-05-12T04:43:08Z","receivedAt":"2026-05-12T04:43:10Z","isPatch":true,"body":"Jonatan Holmgren <jonatan@jontes.page> writes:\n\n> Sorry, that wasn't a \"hey we should deprecate this\" code-wise, I was \n> asking from a documentation point of view, i.e. was curious how you felt \n> about what is \"advisable\". Shouldn't've included that in my email\n\nAfter this, the discussion went dark, but I think everything that\nneeds saying has been said and we are in agreement that the current\npatch is a good way forward without closing doors for the future too\ntightly ;-)  Let me mark the topic for 'next'.\n\nThanks, all.\n"},{"id":"543570","messageId":"20260519004458.GC1612961@coredump.intra.peff.net","threadId":"65544","inReplyTo":"xmqqbjelp7ab.fsf@gitster.g","subject":"Re: [PATCH] alias: restore support for simple dotted aliases","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2026-05-19T00:44:58Z","receivedAt":"2026-05-19T00:44:59Z","isPatch":true,"body":"On Tue, May 12, 2026 at 01:43:08PM +0900, Junio C Hamano wrote:\n\n> Jonatan Holmgren <jonatan@jontes.page> writes:\n> \n> > Sorry, that wasn't a \"hey we should deprecate this\" code-wise, I was \n> > asking from a documentation point of view, i.e. was curious how you felt \n> > about what is \"advisable\". Shouldn't've included that in my email\n> \n> After this, the discussion went dark, but I think everything that\n> needs saying has been said and we are in agreement that the current\n> patch is a good way forward without closing doors for the future too\n> tightly ;-)  Let me mark the topic for 'next'.\n\nYeah, sorry I didn't respond to Jonatan. I think the patch as-is is\nfine, and if we want to push people towards the new form in the\ndocumentation, that can be done separately.\n\n-Peff\n"}]}