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

[PATCH v9 1/4] var: represent multi-valued variables with a string_list

From
APAndrew Pleeter <andrewpleeter@gmail.com>
Date
Sep 26, 2026, 16:20 UTC
Message-ID
<20260926162048.30853-2-andrewpleeter@gmail.com>
In-Reply-To
<xmqq33va1lcg.fsf@gitster.g>

A variable whose value is a list, of which GIT_CONFIG_GLOBAL is currently the only one, is read into a single string whose elements are joined with newlines, and "git var -l" splits that string apart again before showing each element. Round-tripping through a delimiter that can legitimately appear in a value is fragile, and it forces every future caller to know which variables need splitting.

Give "struct git_var" a separate "multiread" function that appends the elements to a string_list, and let the single "read" function stay for the variables that have exactly one value. A variable uses one or the other, never both, so which one is set also says whether the variable is multi-valued.

The output is unchanged. While at it, say in the documentation that GIT_CONFIG_GLOBAL can have multiple values, so that callers know when to expect a list.

Signed-off-by: Andrew Pleeter <andrewpleeter@gmail.com>
---
 Documentation/git-var.adoc |  1 +
 builtin/var.c              | 79 +++++++++++++++++++++-----------------
 2 files changed, 44 insertions(+), 36 deletions(-)
diff --git a/Documentation/git-var.adoc b/Documentation/git-var.adoc
index 697c10aded..de3007732d 100644
--- a/Documentation/git-var.adoc
+++ b/Documentation/git-var.adoc
@@ -83,6 +83,7 @@ endif::git-default-pager[]
 
 `GIT_CONFIG_GLOBAL`::
     The path to the global (per-user) configuration files, if any.
+    This variable can have multiple values.
 
 Most path values contain only one value. However, some can contain multiple
 values, which are separated by newlines, and are listed in order from highest to
diff --git a/builtin/var.c b/builtin/var.c
index cc3a43cde2..9f7c8a6113 100644
--- a/builtin/var.c
+++ b/builtin/var.c
@@ -14,10 +14,11 @@
 #include "environment.h"
 #include "ident.h"
 #include "pager.h"
-#include "refs.h"
 #include "path.h"
-#include "strbuf.h"
+#include "refs.h"
 #include "run-command.h"
+#include "strbuf.h"
+#include "string-list.h"
 
 static const char var_usage[] = "git var (-l | <variable>)";
 
@@ -90,35 +91,27 @@ static char *git_config_val_system(int ident_flag UNUSED)
 	return NULL;
 }
 
-static char *git_config_val_global(int ident_flag UNUSED)
+static void git_config_val_global(struct string_list *list)
 {
-	struct strbuf buf = STRBUF_INIT;
 	char *user, *xdg;
-	size_t unused;
 
 	git_global_config_paths(&user, &xdg);
 	if (xdg && *xdg) {
 		normalize_path_copy(xdg, xdg);
-		strbuf_addf(&buf, "%s\n", xdg);
+		string_list_append(list, xdg);
 	}
 	if (user && *user) {
 		normalize_path_copy(user, user);
-		strbuf_addf(&buf, "%s\n", user);
+		string_list_append(list, user);
 	}
 	free(xdg);
 	free(user);
-	strbuf_trim_trailing_newline(&buf);
-	if (buf.len == 0) {
-		strbuf_release(&buf);
-		return NULL;
-	}
-	return strbuf_detach(&buf, &unused);
 }
 
 struct git_var {
 	const char *name;
 	char *(*read)(int);
-	int multivalued;
+	void (*multiread)(struct string_list *);
 };
 static struct git_var git_vars[] = {
 	{
@@ -163,8 +156,7 @@ static struct git_var git_vars[] = {
 	},
 	{
 		.name = "GIT_CONFIG_GLOBAL",
-		.read = git_config_val_global,
-		.multivalued = 1,
+		.multiread = git_config_val_global,
 	},
 	{
 		.name = "",
@@ -175,28 +167,30 @@ static struct git_var git_vars[] = {
 static void list_vars(void)
 {
 	struct git_var *ptr;
-	char *val;
-
-	for (ptr = git_vars; ptr->read; ptr++)
-		if ((val = ptr->read(0))) {
-			if (ptr->multivalued && *val) {
-				struct string_list list = STRING_LIST_INIT_DUP;
-
-				string_list_split(&list, val, "\n", -1);
-				for (size_t i = 0; i < list.nr; i++)
-					printf("%s=%s\n", ptr->name, list.items[i].string);
-				string_list_clear(&list, 0);
-			} else {
+
+	for (ptr = git_vars; ptr->read || ptr->multiread; ptr++) {
+		if (ptr->read) {
+			char *val = ptr->read(0);
+
+			if (val) {
 				printf("%s=%s\n", ptr->name, val);
+				free(val);
 			}
-			free(val);
+		} else {
+			struct string_list list = STRING_LIST_INIT_DUP;
+
+			ptr->multiread(&list);
+			for (size_t i = 0; i < list.nr; i++)
+				printf("%s=%s\n", ptr->name, list.items[i].string);
+			string_list_clear(&list, 0);
 		}
+	}
 }
 
 static const struct git_var *get_git_var(const char *var)
 {
 	struct git_var *ptr;
-	for (ptr = git_vars; ptr->read; ptr++) {
+	for (ptr = git_vars; ptr->read || ptr->multiread; ptr++) {
 		if (strcmp(var, ptr->name) == 0) {
 			return ptr;
 		}
@@ -220,7 +214,6 @@ int cmd_var(int argc,
 	    struct repository *repo UNUSED)
 {
 	const struct git_var *git_var;
-	char *val;
 
 	show_usage_if_asked(argc, argv, var_usage);
 	if (argc != 2)
@@ -237,12 +230,26 @@ int cmd_var(int argc,
 	if (!git_var)
 		usage(var_usage);
 
-	val = git_var->read(IDENT_STRICT);
-	if (!val)
-		return 1;
+	if (git_var->read) {
+		char *val = git_var->read(IDENT_STRICT);
+
+		if (!val)
+			return 1;
 
-	printf("%s\n", val);
-	free(val);
+		printf("%s\n", val);
+		free(val);
+	} else {
+		struct string_list list = STRING_LIST_INIT_DUP;
+
+		git_var->multiread(&list);
+		if (!list.nr) {
+			string_list_clear(&list, 0);
+			return 1;
+		}
+		for (size_t i = 0; i < list.nr; i++)
+			printf("%s\n", list.items[i].string);
+		string_list_clear(&list, 0);
+	}
 
 	return 0;
 }
-- 
2.54.0 (Apple Git-157)
Previous: Andrew PleeterNext: Andrew Pleeter
Message 30 of 35 in “builtin/whoami: add new 'whoami' command”
  1. builtin/whoami: add new 'whoami' commandAndrew Pleeter via GitGitGadget, Aug 25, 2026
  2. brian m. carlsonAug 25, 2026
  3. Junio C HamanoAug 25, 2026
  4. builtin/ident: add new 'ident' commandAndrew Pleeter via GitGitGadget, Aug 31, 2026
  5. Jeff KingSep 1, 2026
  6. Junio C HamanoSep 1, 2026
  7. var: support broken-down idents, default key, multiple args, and -zAndrew Pleeter via GitGitGadget, Sep 3, 2026
  8. Junio C HamanoSep 3, 2026
  9. Ben KnobleSep 3, 2026
  10. Phillip WoodSep 4, 2026
  11. Junio C HamanoSep 4, 2026
  12. Phillip WoodSep 8, 2026
  13. var: support broken-down idents, signing key, multiple args, and -zAndrew Pleeter via GitGitGadget, Sep 8, 2026
  14. Phillip WoodSep 8, 2026
  15. var: support broken-down idents, signing key, multiple args, and -zAndrew Pleeter via GitGitGadget, Sep 8, 2026
  16. Junio C HamanoSep 8, 2026
  17. var: support broken-down idents, signing key, multiple args, and -zAndrew Pleeter via GitGitGadget, Sep 9, 2026
  18. Phillip WoodSep 9, 2026
  19. Junio C HamanoSep 9, 2026
  20. var: support broken-down idents, signing key, multiple args, and -zAndrew Pleeter via GitGitGadget, Sep 10, 2026
  21. Junio C HamanoSep 14, 2026
  22. var: support broken-down idents, signing key, multiple args, and -zAndrew Pleeter via GitGitGadget, Sep 14, 2026
  23. Junio C HamanoSep 15, 2026
  24. Andrew PleeterSep 15, 2026
  25. Phillip WoodSep 22, 2026
  26. Andrew PleeterSep 26, 2026
  27. 0/4 var: -z output, multiple variables, and broken-out identsAndrew Pleeter, Sep 26, 2026
  28. Phillip WoodOct 2, 2026
  29. Andrew PleeterOct 2, 2026
  30. 1/4 var: represent multi-valued variables with a string_listAndrew Pleeter, Sep 26, 2026
  31. 2/4 var: add "-z" output modeAndrew Pleeter, Sep 26, 2026
  32. 3/4 var: accept more than one variableAndrew Pleeter, Sep 26, 2026
  33. Phillip WoodOct 2, 2026
  34. 4/4 var: add broken-out identity variablesAndrew Pleeter, Sep 26, 2026
  35. Phillip WoodOct 2, 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.