alias: restore support for simple dotted aliases
Historically, config entries like alias.foo.bar expanded the alias "foo.bar". The subsection-based alias syntax introduced in ac1f12a9de (alias: support non-alphanumeric names via subsection syntax, 2026-02-18) broke that behavior by treating such entries as if they were subsection syntax. Restore support for the old dotted form by falling back to the full name when the final key is not "command". Add tests covering execution and help output for simple dotted aliases. Reported-by: Michael Grossfeld <michael.grossfeld@amd.com> Helped-by: Jeff King <peff@peff.net> Signed-off-by: Jonatan Holmgren <jonatan@jontes.page> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Jonatan Holmgren committed
Apr 24, 2026 at 18:17 UTC
21186cf9bbe5f1d8a039286027ebb4f33c7f85d1
3 files changed
+34
-3
alias.c
+14
-2
@@ -34,8 +34,20 @@ static int config_alias_cb(const char *var, const char *value,
34
if (subsection && !subsection_len)
35
subsection = NULL;
36
37
- if (subsection && strcmp(key, "command"))
38
- return 0;
37
+ if (subsection && strcmp(key, "command")) {
38
+ /*
39
+ * We have historically supported the "alias.name" form when
40
+ * "name" happens to contain dots (e.g., alias.foo.bar to allow
41
+ * "git foo.bar". But our parsing above would split that into
42
+ * subsection "foo".
43
+ *
44
+ * If we do not understand the final key in a subsection-style
45
+ * variable, fall back to treating it as a two-level alias.
46
+ */
47
+ key = var + strlen("alias.");
48
+ subsection = NULL;
49
+ subsection_len = 0;
50
+ }
51
52
if (data->alias) {
53
int match;
help.c
+8
-1
@@ -593,14 +593,21 @@ static int git_unknown_cmd_config(const char *var, const char *value,
593
/* Also use aliases for command lookup */
594
if (!parse_config_key(var, "alias", &subsection, &subsection_len,
595
&key)) {
596
+ size_t key_len = strlen(key);
597
+
598
if (subsection) {
599
/* [alias "name"] command = value */
600
if (!strcmp(key, "command"))
601
add_cmdname(&cfg->aliases, subsection,
602
subsection_len);
603
+ else {
604
+ key = var + strlen("alias.");
605
+ key_len = strlen(key);
606
+ add_cmdname(&cfg->aliases, key, key_len);
607
+ }
608
} else {
609
/* alias.name = value */
603
- add_cmdname(&cfg->aliases, key, strlen(key));
610
+ add_cmdname(&cfg->aliases, key, key_len);
611
}
612
}
613
t/t0014-alias.sh
+12
@@ -128,6 +128,12 @@ test_expect_success 'subsection syntax works' '
128
test_grep "ran-subsection" output
129
'
130
131
+test_expect_success 'simple dotted alias syntax still works' '
132
+ test_config alias.simple.dotted "!echo ran-simple-dotted" &&
133
+ git simple.dotted >output &&
134
+ test_grep "ran-simple-dotted" output
135
+'
136
+
137
test_expect_success 'subsection syntax only accepts command key' '
138
test_config alias.invalid.notcommand value &&
139
test_must_fail git invalid 2>error &&
@@ -183,6 +189,12 @@ test_expect_success 'subsection aliases listed in help -a' '
189
test_grep "förgrena" output
190
'
191
192
+test_expect_success 'simple dotted aliases listed in help -a' '
193
+ test_config alias.simple.listed "!echo test" &&
194
+ git help -a >output &&
195
+ test_grep "simple.listed" output
196
+'
197
+
198
test_expect_success 'empty subsection treated as no subsection' '
199
test_config "alias..something" "!echo foobar" &&
200
git something >actual &&