git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v1] alias: support UTF-8 characters via subsection syntax

From
Jonatan Holmgren <jonatan@jontes.page>
Date
Feb 9, 2026, 22:01 UTC
Message-ID
<20260209220115.461109-1-jonatan@jontes.page>
In-Reply-To
<3124b359-2929-4f3f-9ac6-793277fe422b@jontes.page>

Git aliases are currently restricted to ASCII characters due to config key syntax limitations. This prevents non-English speakers from creating aliases in their native languages.

Add support for UTF-8 alias names using config subsections:
    [alias "förgrena"]
        command = branch

The subsection name is matched verbatim (case-sensitive), while the existing flat syntax (alias.name) remains case-insensitive for backward compatibility. This approach uses existing config infrastructure and avoids complex Unicode normalization.

Suggested-by: Jeff King <peff@peff.net>
Signed-off-by: Jonatan Holmgren <jonatan@jontes.page>
---
 Documentation/RelNotes/2.54.0.adoc |  8 +++++
 Documentation/config/alias.adoc    | 53 +++++++++++++++++++++++++-----
 alias.c                            | 38 +++++++++++++++++----
 t/t0014-alias-utf8.sh              | 44 +++++++++++++++++++++++++
 t/t0014-alias.sh                   | 32 ++++++++++++++++++
 5 files changed, 161 insertions(+), 14 deletions(-)
 create mode 100755 t/t0014-alias-utf8.sh
diff --git a/Documentation/RelNotes/2.54.0.adoc b/Documentation/RelNotes/2.54.0.adoc
index 20c660d82a..8cb00a21bb 100644
--- a/Documentation/RelNotes/2.54.0.adoc
+++ b/Documentation/RelNotes/2.54.0.adoc
@@ -7,6 +7,14 @@ UI, Workflows & Features
  * "git add -p" and friends note what the current status of the hunk
    being shown is.
 
+ * Git aliases now support UTF-8 characters in alias names through
+   subsection syntax: `[alias "name"] command = value`. This enables
+   aliases in non-English languages. The flat syntax continues
+   to work for backward compatibility.
+
+ * The new subsection syntax uses case-sensitive matching and
+   the flat syntax remains case-insensitive for backward compatibility.
+
 
 Performance, Internal Implementation, Development Support etc.
 --------------------------------------------------------------
diff --git a/Documentation/config/alias.adoc b/Documentation/config/alias.adoc
index 80ce17d2de..feba1e2022 100644
--- a/Documentation/config/alias.adoc
+++ b/Documentation/config/alias.adoc
@@ -1,12 +1,49 @@
 alias.*::
-	Command aliases for the linkgit:git[1] command wrapper - e.g.
-	after defining `alias.last = cat-file commit HEAD`, the invocation
-	`git last` is equivalent to `git cat-file commit HEAD`. To avoid
-	confusion and troubles with script usage, aliases that
-	hide existing Git commands are ignored except for deprecated
-	commands.  Arguments are split by
-	spaces, the usual shell quoting and escaping are supported.
-	A quote pair or a backslash can be used to quote them.
+alias.*.command::
+	Command aliases for the linkgit:git[1] command wrapper. Aliases
+	can be defined using two syntaxes:
++
+--
+1. **Simple syntax** (case-insensitive): `alias.name = value`
+2. **Subsection syntax** (recommended for UTF-8/special characters):
+   `[alias "name"]` with `command = value`
+
+The subsection syntax allows alias names containing UTF-8 characters,
+spaces, or special characters, as the subsection preserves the exact
+bytes including case.
+--
++
+Examples:
++
+----
+# Simple syntax (ASCII names)
+[alias]
+    co = checkout
+    st = status
+
+# Subsection syntax (UTF-8 and special characters)
+[alias "hämta"]
+    command = fetch
+[alias "gömma"]
+    command = stash
+[alias "my alias with whitespace"]
+    command = "status --short"
+----
++
+After defining these, you can run `git co`, `git hämta`, `git gömma`,
+and `git "my alias with whitespace"` (note the quotes for aliases with spaces).
++
+**Note:** The flat syntax `alias.name` remains case-insensitive for
+backward compatibility. The new subsection syntax is case-sensitive:
+`[alias "Foo"]` and `[alias "foo"]` are different aliases.
++
+E.g. after defining `alias.last = cat-file commit HEAD`, the invocation
+`git last` is equivalent to `git cat-file commit HEAD`. To avoid
+confusion and troubles with script usage, aliases that
+hide existing Git commands are ignored except for deprecated
+commands.  Arguments are split by
+spaces, the usual shell quoting and escaping are supported.
+A quote pair or a backslash can be used to quote them.
 +
 Note that the first word of an alias does not necessarily have to be a
 command. It can be a command-line option that will be passed into the
diff --git a/alias.c b/alias.c
index 1a1a141a0a..f0c5f12fdd 100644
--- a/alias.c
+++ b/alias.c
@@ -17,19 +17,45 @@ static int config_alias_cb(const char *key, const char *value,
 			   const struct config_context *ctx UNUSED, void *d)
 {
 	struct config_alias_data *data = d;
-	const char *p;
+	const char *cmd, *subkey;
+	size_t cmd_len;
+	int is_subsection;
 
-	if (!skip_prefix(key, "alias.", &p))
+	/* Use parse_config_key() to handle both 2-level and 3-level keys */
+	if (parse_config_key(key, "alias", &cmd, &cmd_len, &subkey) < 0)
 		return 0;
 
+	/*
+	 * Support two syntaxes:
+	 * 1. alias.name = value (simple, 2-level key)
+	 * 2. [alias "name"] command = value (new, 3-level key)
+	 */
+	if (cmd) {
+		if (strcmp(subkey, "command"))
+			return 0;
+		is_subsection = 1;
+	} else {
+		cmd = subkey;
+		cmd_len = strlen(cmd);
+		is_subsection = 0;
+	}
+
 	if (data->alias) {
-		if (!strcasecmp(p, data->alias)) {
+		int match;
+		if (is_subsection) {
+			match = (strlen(data->alias) == cmd_len &&
+				 !strncmp(data->alias, cmd, cmd_len));
+		} else {
+			match = (strlen(data->alias) == cmd_len &&
+				 !strncasecmp(data->alias, cmd, cmd_len));
+		}
+
+		if (match) {
 			FREE_AND_NULL(data->v);
-			return git_config_string(&data->v,
-						 key, value);
+			return git_config_string(&data->v, key, value);
 		}
 	} else if (data->list) {
-		string_list_append(data->list, p);
+		string_list_append_nodup(data->list, xmemdupz(cmd, cmd_len));
 	}
 
 	return 0;
diff --git a/t/t0014-alias-utf8.sh b/t/t0014-alias-utf8.sh
new file mode 100755
index 0000000000..d55b5a7213
--- /dev/null
+++ b/t/t0014-alias-utf8.sh
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+test_description='UTF-8 support in git aliases via subsection syntax'
+
+. ./test-lib.sh
+
+# Skip if filesystem/locale doesn't support UTF-8
+test_lazy_prereq UTF8_LOCALE '
+	test_have_prereq !MINGW &&
+	test_set_prereq UTF8_LOCALE
+'
+
+test_expect_success 'setup test repository' '
+	git init &&
+	test_commit initial
+'
+
+test_expect_success UTF8_LOCALE 'setup UTF-8 aliases' '
+	git config alias."förgrena".command branch &&
+	git config alias."分支".command "branch --list" &&
+	git config alias."test name".command status
+'
+
+test_expect_success UTF8_LOCALE 'UTF-8 alias with Swedish characters' '
+	git förgrena >output &&
+	test_grep -E "^(\* )?(main|master)" output
+'
+
+test_expect_success UTF8_LOCALE 'UTF-8 alias with CJK characters' '
+	git 分支 >output &&
+	test_grep -E "^(\* )?(main|master)" output
+'
+
+test_expect_success UTF8_LOCALE 'alias with spaces in name' '
+	git "test name" >output &&
+	test_grep "On branch" output
+'
+
+test_expect_success 'list UTF-8 aliases' '
+	git config --get-regexp "^alias\\..*\\.command" >output &&
+	test_line_count -ge 3 output
+'
+
+test_done
diff --git a/t/t0014-alias.sh b/t/t0014-alias.sh
index 07a53e7366..b19a8a5061 100755
--- a/t/t0014-alias.sh
+++ b/t/t0014-alias.sh
@@ -111,5 +111,37 @@ test_expect_success 'cannot alias-shadow a sample of regular builtins' '
 		cannot_alias_regular_builtin "$cmd" || return 1
 	done
 '
+test_expect_success 'flat syntax still works' '
+	git config alias.testlegacy status &&
+	git testlegacy >output &&
+	test_grep "On branch" output
+'
+
+test_expect_success 'new subsection syntax works' '
+	git config alias.testnew.command status &&
+	git testnew >output &&
+	test_grep "On branch" output
+'
+
+test_expect_success 'subsection syntax only accepts command key' '
+	git config alias.invalid.notcommand "value" &&
+	test_must_fail git invalid 2>error &&
+	test_grep -i "not a git command" error
+'
+
+test_expect_success 'simple syntax is case-insensitive' '
+	git config alias.LegacyCase status &&
+	git legacycase >output 2>&1 &&
+	test_grep "On branch" output
+'
+
+test_expect_success 'subsection syntax is case-sensitive' '
+	test_commit case-test &&
+	git config alias.SubCase.command "log --oneline" &&
+	git config alias.subcase.command status &&
+	git SubCase >upper.out 2>&1 &&
+	git subcase >lower.out 2>&1 &&
+	! test_cmp upper.out lower.out
+'
 
 test_done
-- 
2.53.0
Previous: Theodore TsoNext: Jeff King
Message 14 of 88 in “[RFC] Support UTF-8 characters in Git alias names”
  1. Jonatan HolmgrenFeb 8, 2026
  2. D. Ben KnobleFeb 8, 2026
  3. brian m. carlsonFeb 8, 2026
  4. Junio C HamanoFeb 9, 2026
  5. Jonatan HolmgrenFeb 9, 2026
  6. Junio C HamanoFeb 9, 2026
  7. brian m. carlsonFeb 9, 2026
  8. Junio C HamanoFeb 9, 2026
  9. Ben KnobleFeb 10, 2026
  10. Junio C HamanoFeb 10, 2026
  11. Jeff KingFeb 10, 2026
  12. Jeff KingFeb 9, 2026
  13. Theodore TsoFeb 9, 2026
  14. alias: support UTF-8 characters via subsection syntaxJonatan Holmgren, Feb 9, 2026
  15. Jeff KingFeb 10, 2026
  16. Torsten BögershausenFeb 10, 2026
  17. Junio C HamanoFeb 10, 2026
  18. 0/2 support UTF-8 in alias namesJonatan Holmgren, Feb 10, 2026
  19. 1/2 help: use list_aliases() for alias listing and lookupJonatan Holmgren, Feb 10, 2026
  20. Junio C HamanoFeb 10, 2026
  21. 2/2 alias: support non-alphanumeric names via subsection syntaxJonatan Holmgren, Feb 10, 2026
  22. Junio C HamanoFeb 10, 2026
  23. Jonatan HolmgrenFeb 10, 2026
  24. Kristoffer HaugsbakkFeb 23, 2026
  25. Kristoffer HaugsbakkFeb 23, 2026
  26. Junio C HamanoFeb 23, 2026
  27. Kristoffer HaugsbakkFeb 23, 2026
  28. Patrick SteinhardtFeb 24, 2026
  29. 0/3 support UTF-8 in alias namesJonatan Holmgren, Feb 10, 2026
  30. 1/3 help: use list_aliases() for alias listingJonatan Holmgren, Feb 10, 2026
  31. Junio C HamanoFeb 10, 2026
  32. 2/3 alias: prepare for subsection aliasesJonatan Holmgren, Feb 10, 2026
  33. 3/3 alias: support non-alphanumeric names via subsection syntaxJonatan Holmgren, Feb 10, 2026
  34. 0/3 support UTF-8 in alias namesJonatan Holmgren, Feb 11, 2026
  35. 2/3 alias: prepare for subsection aliasesJonatan Holmgren, Feb 11, 2026
  36. Junio C HamanoFeb 11, 2026
  37. 1/3 help: use list_aliases() for alias listingJonatan Holmgren, Feb 11, 2026
  38. Junio C HamanoFeb 11, 2026
  39. 3/3 alias: support non-alphanumeric names via subsection syntaxJonatan Holmgren, Feb 11, 2026
  40. Junio C HamanoFeb 11, 2026
  41. Richard KerryFeb 12, 2026
  42. Jonatan HolmgrenFeb 12, 2026
  43. Jonatan HolmgrenFeb 12, 2026
  44. Torsten BögershausenFeb 12, 2026
  45. Jonatan HolmgrenFeb 12, 2026
  46. 0/4 support uTF-8 in alias namesJonatan Holmgren, Feb 16, 2026
  47. 4/4 completion: fix zsh alias listing for subsection aliasesJonatan Holmgren, Feb 16, 2026
  48. D. Ben KnobleFeb 16, 2026
  49. Junio C HamanoFeb 17, 2026
  50. 2/4 alias: prepare for subsection aliasesJonatan Holmgren, Feb 16, 2026
  51. 1/4 help: use list_aliases() for alias listingJonatan Holmgren, Feb 16, 2026
  52. 3/4 alias: support non-alphanumeric names via subsection syntaxJonatan Holmgren, Feb 16, 2026
  53. 0/4 support UTF-8 in alias namesJonatan Holmgren, Feb 18, 2026
  54. 2/4 alias: prepare for subsection aliasesJonatan Holmgren, Feb 18, 2026
  55. Kristoffer HaugsbakkFeb 18, 2026
  56. 1/4 help: use list_aliases() for alias listingJonatan Holmgren, Feb 18, 2026
  57. 4/4 completion: fix zsh alias listing for subsection aliasesJonatan Holmgren, Feb 18, 2026
  58. 3/4 alias: support non-alphanumeric names via subsection syntaxJonatan Holmgren, Feb 18, 2026
  59. 0/4 support UTF-8 in alias namesJonatan Holmgren, Feb 18, 2026
  60. 1/4 help: use list_aliases() for alias listingJonatan Holmgren, Feb 18, 2026
  61. Jacob KellerFeb 24, 2026
  62. Junio C HamanoFeb 24, 2026
  63. Junio C HamanoFeb 25, 2026
  64. Jacob KellerFeb 26, 2026
  65. Jacob KellerFeb 24, 2026
  66. 2/4 alias: prepare for subsection aliasesJonatan Holmgren, Feb 18, 2026
  67. 3/4 alias: support non-alphanumeric names via subsection syntaxJonatan Holmgren, Feb 18, 2026
  68. Kristoffer HaugsbakkFeb 24, 2026
  69. Jonatan HolmgrenFeb 24, 2026
  70. Kristoffer HaugsbakkFeb 24, 2026
  71. 4/4 completion: fix zsh alias listing for subsection aliasesJonatan Holmgren, Feb 18, 2026
  72. Junio C HamanoFeb 19, 2026
  73. Jonatan HolmgrenFeb 19, 2026
  74. 0/2 Fix small issues in alias subsection handlingJonatan Holmgren, Feb 24, 2026
  75. 1/2 doc: fix list continuation in alias subsection exampleJonatan Holmgren, Feb 24, 2026
  76. Junio C HamanoFeb 24, 2026
  77. Kristoffer HaugsbakkFeb 24, 2026
  78. Junio C HamanoFeb 24, 2026
  79. 2/2 alias: treat empty subsection [alias ""] as plain [alias]Jonatan Holmgren, Feb 24, 2026
  80. Junio C HamanoFeb 26, 2026
  81. 0/3 Fix small issues in alias subsection handlingJonatan Holmgren, Feb 26, 2026
  82. 2/3 alias: treat empty subsection [alias ""] as plain [alias]Jonatan Holmgren, Feb 26, 2026
  83. 1/3 doc: fix list continuation in alias subsection exampleJonatan Holmgren, Feb 26, 2026
  84. Kristoffer HaugsbakkMar 3, 2026
  85. Jonatan HolmgrenMar 3, 2026
  86. 3/3 git, help: fix memory leaks in alias listingJonatan Holmgren, Feb 26, 2026
  87. Junio C HamanoFeb 26, 2026
  88. doc: fix list continuation in alias.adocJonatan Holmgren, Mar 3, 2026

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.