From 2e3a987f3b968573e499bb353734430df39a64a5 Mon Sep 17 00:00:00 2001 From: Jonatan Holmgren Date: Thu, 26 Feb 2026 21:53:26 +0100 Subject: [PATCH 1/3] doc: fix list continuation in alias subsection example The example showing the equivalence between alias.last and alias.last.command was missing the list continuation marks (+ between the shell session block and the following prose, leaving the paragraph detached from the list item in the rendered output. Signed-off-by: Jonatan Holmgren Signed-off-by: Junio C Hamano --- Documentation/config/alias.adoc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Documentation/config/alias.adoc b/Documentation/config/alias.adoc index 115fdbb1e3..26949a0ccb 100644 --- a/Documentation/config/alias.adoc +++ b/Documentation/config/alias.adoc @@ -30,13 +30,14 @@ Examples: ---- + With a Git alias defined, e.g., - ++ $ git config --global alias.last "cat-file commit HEAD" # Which is equivalent to $ git config --global alias.last.command "cat-file commit HEAD" ++ +`git last` is equivalent to `git cat-file commit HEAD`. -`git last` is equivalent to `git cat-file commit HEAD`. To avoid -confusion and troubles with script usage, aliases that +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. From 65892943750b0c66017389f0233ba5a6a7205165 Mon Sep 17 00:00:00 2001 From: Jonatan Holmgren Date: Thu, 26 Feb 2026 21:53:27 +0100 Subject: [PATCH 2/3] alias: treat empty subsection [alias ""] as plain [alias] When git-config stores a key of the form alias..name, it records it under an empty subsection ([alias ""]). The new subsection-aware alias lookup would see a non-NULL but zero-length subsection and fall into the subsection code path, where it required a "command" key and thus silently ignored the entry. Normalize an empty subsection to NULL before any further processing so that entries stored this way continue to work as plain case-insensitive aliases, matching the pre-subsection behaviour. Users who relied on alias..name to create an alias literally named ".name" may want to migrate to subsection syntax, which looks less confusing: [alias ".name"] command = Add tests covering both the empty-subsection compatibility case and the leading-dot alias via the new syntax. Signed-off-by: Jonatan Holmgren Signed-off-by: Junio C Hamano --- alias.c | 4 ++++ t/t0014-alias.sh | 14 ++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/alias.c b/alias.c index 0d636278bc..ec9833dd30 100644 --- a/alias.c +++ b/alias.c @@ -30,6 +30,10 @@ static int config_alias_cb(const char *var, const char *value, * - [alias "name"] * command = value (with subsection, case-sensitive) */ + /* Treat [alias ""] (empty subsection) the same as plain [alias]. */ + if (subsection && !subsection_len) + subsection = NULL; + if (subsection && strcmp(key, "command")) return 0; diff --git a/t/t0014-alias.sh b/t/t0014-alias.sh index 34bbdb51c5..68b4903cbf 100755 --- a/t/t0014-alias.sh +++ b/t/t0014-alias.sh @@ -183,4 +183,18 @@ test_expect_success 'subsection aliases listed in help -a' ' test_grep "förgrena" output ' +test_expect_success 'empty subsection treated as no subsection' ' + test_config "alias..something" "!echo foobar" && + git something >actual && + echo foobar >expect && + test_cmp expect actual +' + +test_expect_success 'alias with leading dot via subsection syntax' ' + test_config alias.".something".command "!echo foobar" && + git .something >actual && + echo foobar >expect && + test_cmp expect actual +' + test_done From cdef6255095251500cc7d08d304072e1e2fa0bbd Mon Sep 17 00:00:00 2001 From: Jonatan Holmgren Date: Thu, 26 Feb 2026 21:53:28 +0100 Subject: [PATCH 3/3] git, help: fix memory leaks in alias listing The list_aliases() function sets the util pointer of each list item to a heap-allocated copy of the alias command value. Two callers failed to free these util pointers: - list_cmds() in git.c collects a string list with STRING_LIST_INIT_DUP and clears it with string_list_clear(&list, 0), which frees the duplicated strings (strdup_strings=1) but not the util pointers. Pass free_util=1 to free them. - list_cmds_by_config() in help.c calls string_list_sort_u(list, 0) to deduplicate the list before processing completion.commands overrides. When duplicate entries are removed, the util pointer of each discarded item is leaked because free_util=0. Pass free_util=1 to free them. Reported-by: Jacob Keller Signed-off-by: Jonatan Holmgren Signed-off-by: Junio C Hamano --- git.c | 2 +- help.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/git.c b/git.c index c5fad56813..b5eb740e83 100644 --- a/git.c +++ b/git.c @@ -119,7 +119,7 @@ static int list_cmds(const char *spec) } for (size_t i = 0; i < list.nr; i++) puts(list.items[i].string); - string_list_clear(&list, 0); + string_list_clear(&list, 1); return 0; } diff --git a/help.c b/help.c index 82fb2eaa3f..725e92a195 100644 --- a/help.c +++ b/help.c @@ -423,7 +423,7 @@ void list_cmds_by_config(struct string_list *list) return; string_list_sort(list); - string_list_remove_duplicates(list, 0); + string_list_remove_duplicates(list, 1); while (*cmd_list) { struct strbuf sb = STRBUF_INIT;