public inbox for git@vger.kernel.org 
 help / color / mirror / Atom feed
From: Jonatan Holmgren <jonatan@jontes•page>
To: git@vger•kernel.org
Cc: peff@peff•net, gitster@pobox•com,
	"D . Ben Knoble" <benknoble@gmail•com>,
	"brian m . carlson" <sandals@crustytoothpaste•net>,
	Jonatan Holmgren <jonatan@jontes•page>
Subject: [PATCH v1] alias: support UTF-8 characters via subsection syntax
Date: Mon,  9 Feb 2026 23:01:15 +0100	[thread overview]
Message-ID: <20260209220115.461109-1-jonatan@jontes.page> (raw)
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


  parent reply	other threads:[~2026-02-09 22:02 UTC|newest]

Thread overview: 88+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-02-08 15:30 [RFC] Support UTF-8 characters in Git alias names Jonatan Holmgren
2026-02-08 16:07 ` D. Ben Knoble
2026-02-08 23:21 ` brian m. carlson
2026-02-09 14:55   ` Junio C Hamano
2026-02-09 15:19     ` Jonatan Holmgren
2026-02-09 17:59       ` Junio C Hamano
2026-02-09 22:40     ` brian m. carlson
2026-02-09 23:14       ` Junio C Hamano
2026-02-10  0:45         ` Ben Knoble
2026-02-10  1:04           ` Junio C Hamano
2026-02-10  6:59             ` Jeff King
2026-02-09  7:36 ` Jeff King
2026-02-09 13:59   ` Theodore Tso
2026-02-09 22:01 ` Jonatan Holmgren [this message]
2026-02-10  7:44   ` [PATCH v1] alias: support UTF-8 characters via subsection syntax Jeff King
2026-02-10  8:30   ` Torsten Bögershausen
2026-02-10 16:35   ` Junio C Hamano
2026-02-10 18:31 ` [PATCH v2 0/2] support UTF-8 in alias names Jonatan Holmgren
2026-02-10 18:31   ` [PATCH v2 1/2] help: use list_aliases() for alias listing and lookup Jonatan Holmgren
2026-02-10 19:27     ` Junio C Hamano
2026-02-10 18:31   ` [PATCH v2 2/2] alias: support non-alphanumeric names via subsection syntax Jonatan Holmgren
2026-02-10 19:47     ` Junio C Hamano
2026-02-10 22:29       ` Jonatan Holmgren
2026-02-23  9:29     ` Kristoffer Haugsbakk
2026-02-23 16:07       ` Kristoffer Haugsbakk
2026-02-23 20:22         ` Junio C Hamano
2026-02-23 20:25           ` Kristoffer Haugsbakk
2026-02-24 10:27     ` Patrick Steinhardt
2026-02-10 22:27 ` [PATCH 0/3] support UTF-8 in alias names Jonatan Holmgren
2026-02-10 22:27   ` [PATCH 1/3] help: use list_aliases() for alias listing Jonatan Holmgren
2026-02-10 23:17     ` Junio C Hamano
2026-02-10 22:27   ` [PATCH 2/3] alias: prepare for subsection aliases Jonatan Holmgren
2026-02-10 22:27   ` [PATCH 3/3] alias: support non-alphanumeric names via subsection syntax Jonatan Holmgren
2026-02-11 21:18 ` [PATCH v4 0/3] support UTF-8 in alias names Jonatan Holmgren
2026-02-11 21:18   ` [PATCH v4 1/3] help: use list_aliases() for alias listing Jonatan Holmgren
2026-02-11 22:29     ` Junio C Hamano
2026-02-11 21:18   ` [PATCH v4 2/3] alias: prepare for subsection aliases Jonatan Holmgren
2026-02-11 21:53     ` Junio C Hamano
2026-02-11 21:18   ` [PATCH v4 3/3] alias: support non-alphanumeric names via subsection syntax Jonatan Holmgren
2026-02-11 22:28     ` Junio C Hamano
2026-02-12 11:16     ` Richard Kerry
2026-02-12 15:34       ` Jonatan Holmgren
2026-02-12 18:52     ` Jonatan Holmgren
2026-02-12 10:27   ` [PATCH v4 0/3] support UTF-8 in alias names Torsten Bögershausen
2026-02-12 15:35     ` Jonatan Holmgren
2026-02-16 16:15 ` [PATCH v5 0/4] support uTF-8 " Jonatan Holmgren
2026-02-16 16:15   ` [PATCH v5 1/4] help: use list_aliases() for alias listing Jonatan Holmgren
2026-02-16 16:15   ` [PATCH v5 2/4] alias: prepare for subsection aliases Jonatan Holmgren
2026-02-16 16:15   ` [PATCH v5 3/4] alias: support non-alphanumeric names via subsection syntax Jonatan Holmgren
2026-02-16 16:15   ` [PATCH v5 4/4] completion: fix zsh alias listing for subsection aliases Jonatan Holmgren
2026-02-16 18:32     ` D. Ben Knoble
2026-02-17 20:01     ` Junio C Hamano
2026-02-18 14:52 ` [PATCH v6 0/4] support UTF-8 in alias names Jonatan Holmgren
2026-02-18 14:52   ` [PATCH v6 1/4] help: use list_aliases() for alias listing Jonatan Holmgren
2026-02-18 14:52   ` [PATCH v6 2/4] alias: prepare for subsection aliases Jonatan Holmgren
2026-02-18 16:21     ` Kristoffer Haugsbakk
2026-02-18 14:52   ` [PATCH v6 3/4] alias: support non-alphanumeric names via subsection syntax Jonatan Holmgren
2026-02-18 14:52   ` [PATCH v6 4/4] completion: fix zsh alias listing for subsection aliases Jonatan Holmgren
2026-02-18 21:57 ` [PATCH v7 0/4] support UTF-8 in alias names Jonatan Holmgren
2026-02-18 21:57   ` [PATCH v7 1/4] help: use list_aliases() for alias listing Jonatan Holmgren
2026-02-24 22:19     ` Jacob Keller
2026-02-24 22:41       ` Junio C Hamano
2026-02-25 20:45         ` Junio C Hamano
2026-02-26 23:33           ` Jacob Keller
2026-02-24 22:21     ` Jacob Keller
2026-02-18 21:57   ` [PATCH v7 2/4] alias: prepare for subsection aliases Jonatan Holmgren
2026-02-18 21:57   ` [PATCH v7 3/4] alias: support non-alphanumeric names via subsection syntax Jonatan Holmgren
2026-02-24 10:55     ` Kristoffer Haugsbakk
2026-02-24 14:48       ` Jonatan Holmgren
2026-02-24 23:23         ` Kristoffer Haugsbakk
2026-02-18 21:57   ` [PATCH v7 4/4] completion: fix zsh alias listing for subsection aliases Jonatan Holmgren
2026-02-19 18:17   ` [PATCH v7 0/4] support UTF-8 in alias names Junio C Hamano
2026-02-19 18:54     ` Jonatan Holmgren
2026-02-24 17:12 ` [PATCH 0/2] Fix small issues in alias subsection handling Jonatan Holmgren
2026-02-24 17:12   ` [PATCH 1/2] doc: fix list continuation in alias subsection example Jonatan Holmgren
2026-02-24 19:11     ` Junio C Hamano
2026-02-24 19:14       ` Kristoffer Haugsbakk
2026-02-24 20:23         ` Junio C Hamano
2026-02-24 17:12   ` [PATCH 2/2] alias: treat empty subsection [alias ""] as plain [alias] Jonatan Holmgren
2026-02-26 17:00   ` [PATCH 0/2] Fix small issues in alias subsection handling Junio C Hamano
2026-02-26 20:53 ` [PATCH v2 0/3] " Jonatan Holmgren
2026-02-26 20:53   ` [PATCH v2 1/3] doc: fix list continuation in alias subsection example Jonatan Holmgren
2026-03-03  9:41     ` Kristoffer Haugsbakk
2026-03-03 15:13       ` [PATCH v2 1/3] doc: fix list continuation in alias subsection example! Jonatan Holmgren
2026-02-26 20:53   ` [PATCH v2 2/3] alias: treat empty subsection [alias ""] as plain [alias] Jonatan Holmgren
2026-02-26 20:53   ` [PATCH v2 3/3] git, help: fix memory leaks in alias listing Jonatan Holmgren
2026-02-26 21:08   ` [PATCH v2 0/3] Fix small issues in alias subsection handling Junio C Hamano
2026-03-03 15:12 ` [PATCH] doc: fix list continuation in alias.adoc Jonatan Holmgren

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260209220115.461109-1-jonatan@jontes.page \
    --to=jonatan@jontes$(echo .)page \
    --cc=benknoble@gmail$(echo .)com \
    --cc=git@vger$(echo .)kernel.org \
    --cc=gitster@pobox$(echo .)com \
    --cc=peff@peff$(echo .)net \
    --cc=sandals@crustytoothpaste$(echo .)net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox