@@ -80,6 +80,20 @@ GIT_ATTR_SYSTEM::
GIT_ATTR_GLOBAL::
The path to the global (per-user) linkgit:gitattributes[5] file.
+GIT_CONFIG_SYSTEM::
+ The path to the system configuration file, if one is enabled.
+
+GIT_CONFIG_GLOBAL::
+ The path to the global (per-user) configuration files, if any.
+
+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
+lowest priority. Callers should be prepared for any such path value to contain
+multiple items.
+
+Note that paths are printed even if they do not exist, but not if they are
+disabled by other environment variables.
+
SEE ALSO
--------
linkgit:git-commit-tree[1]
@@ -62,21 +62,59 @@ static const char *git_attr_val_global(int flag)
return NULL;
}
+static const char *git_config_val_system(int flag)
+{
+ if (git_config_system()) {
+ char *file = git_system_config();
+ normalize_path_copy(file, file);
+ return file;
+ }
+ return NULL;
+}
+
+static const char *git_config_val_global(int flag)
+{
+ struct strbuf buf = STRBUF_INIT;
+ char *user, *xdg;
+ size_t unused;
+
+ git_global_config(&user, &xdg);
+ if (xdg && *xdg) {
+ normalize_path_copy(xdg, xdg);
+ strbuf_addf(&buf, "%s\n", xdg);
+ }
+ if (user && *user) {
+ normalize_path_copy(user, user);
+ strbuf_addf(&buf, "%s\n", 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;
const char *(*read)(int);
+ int multivalued;
int free;
};
static struct git_var git_vars[] = {
- { "GIT_COMMITTER_IDENT", git_committer_info, 0 },
- { "GIT_AUTHOR_IDENT", git_author_info, 0 },
- { "GIT_EDITOR", editor, 0 },
- { "GIT_SEQUENCE_EDITOR", sequence_editor, 0 },
- { "GIT_PAGER", pager, 0 },
- { "GIT_DEFAULT_BRANCH", default_branch, 0 },
- { "GIT_SHELL_PATH", shell_path, 0 },
- { "GIT_ATTR_SYSTEM", git_attr_val_system, 1 },
- { "GIT_ATTR_GLOBAL", git_attr_val_global, 1 },
+ { "GIT_COMMITTER_IDENT", git_committer_info, 0, 0 },
+ { "GIT_AUTHOR_IDENT", git_author_info, 0, 0 },
+ { "GIT_EDITOR", editor, 0, 0 },
+ { "GIT_SEQUENCE_EDITOR", sequence_editor, 0, 0 },
+ { "GIT_PAGER", pager, 0, 0 },
+ { "GIT_DEFAULT_BRANCH", default_branch, 0, 9 },
+ { "GIT_SHELL_PATH", shell_path, 0, 0 },
+ { "GIT_ATTR_SYSTEM", git_attr_val_system, 0, 1 },
+ { "GIT_ATTR_GLOBAL", git_attr_val_global, 0, 1 },
+ { "GIT_CONFIG_SYSTEM", git_config_val_system, 0, 1 },
+ { "GIT_CONFIG_GLOBAL", git_config_val_global, 1, 1 },
{ "", NULL },
};
@@ -87,7 +125,17 @@ static void list_vars(void)
for (ptr = git_vars; ptr->read; ptr++)
if ((val = ptr->read(0))) {
- printf("%s=%s\n", ptr->name, val);
+ if (ptr->multivalued && *val) {
+ struct string_list list = STRING_LIST_INIT_DUP;
+ int i;
+
+ string_list_split(&list, val, '\n', -1);
+ for (i = 0; i < list.nr; i++)
+ printf("%s=%s\n", ptr->name, list.items[i].string);
+ string_list_clear(&list, 0);
+ } else {
+ printf("%s=%s\n", ptr->name, val);
+ }
if (ptr->free)
free((void *)val);
}
@@ -179,6 +179,49 @@ test_expect_success 'GIT_ATTR_GLOBAL points to the correct location' '
)
'
+test_expect_success 'GIT_CONFIG_SYSTEM points to the correct location' '
+ TRASHDIR="$(test-tool path-utils normalize_path_copy "$(pwd)")" &&
+ test_must_fail env GIT_CONFIG_NOSYSTEM=1 git var GIT_CONFIG_SYSTEM &&
+ (
+ sane_unset GIT_CONFIG_NOSYSTEM &&
+ git var GIT_CONFIG_SYSTEM >path &&
+ test "$(cat path)" != "" &&
+ GIT_CONFIG_SYSTEM=/dev/null git var GIT_CONFIG_SYSTEM >path &&
+ if test_have_prereq MINGW
+ then
+ test "$(cat path)" = "nul"
+ else
+ test "$(cat path)" = "/dev/null"
+ fi &&
+ GIT_CONFIG_SYSTEM="$TRASHDIR/gitconfig" git var GIT_CONFIG_SYSTEM >path &&
+ test "$(cat path)" = "$TRASHDIR/gitconfig"
+ )
+'
+
+test_expect_success 'GIT_CONFIG_GLOBAL points to the correct location' '
+ TRASHDIR="$(test-tool path-utils normalize_path_copy "$(pwd)")" &&
+ HOME="$TRASHDIR" XDG_CONFIG_HOME="$TRASHDIR/foo" git var GIT_CONFIG_GLOBAL >actual &&
+ echo "$TRASHDIR/foo/git/config" >expected &&
+ echo "$TRASHDIR/.gitconfig" >>expected &&
+ test_cmp expected actual &&
+ (
+ sane_unset XDG_CONFIG_HOME &&
+ HOME="$TRASHDIR" git var GIT_CONFIG_GLOBAL >actual &&
+ echo "$TRASHDIR/.config/git/config" >expected &&
+ echo "$TRASHDIR/.gitconfig" >>expected &&
+ test_cmp expected actual &&
+ GIT_CONFIG_GLOBAL=/dev/null git var GIT_CONFIG_GLOBAL >path &&
+ if test_have_prereq MINGW
+ then
+ test "$(cat path)" = "nul"
+ else
+ test "$(cat path)" = "/dev/null"
+ fi &&
+ GIT_CONFIG_GLOBAL="$TRASHDIR/gitconfig" git var GIT_CONFIG_GLOBAL >path &&
+ test "$(cat path)" = "$TRASHDIR/gitconfig"
+ )
+'
+
# For git var -l, we check only a representative variable;
# testing the whole output would make our test too brittle with
# respect to unrelated changes in the test suite's environment.
@@ -196,6 +239,29 @@ test_expect_success 'git var -l lists config' '
test_cmp expect actual.bare
'
+test_expect_success 'git var -l lists multiple global configs' '
+ TRASHDIR="$(test-tool path-utils normalize_path_copy "$(pwd)")" &&
+ HOME="$TRASHDIR" XDG_CONFIG_HOME="$TRASHDIR/foo" git var -l >actual &&
+ grep "^GIT_CONFIG_GLOBAL=" actual >filtered &&
+ echo "GIT_CONFIG_GLOBAL=$TRASHDIR/foo/git/config" >expected &&
+ echo "GIT_CONFIG_GLOBAL=$TRASHDIR/.gitconfig" >>expected &&
+ test_cmp expected filtered
+'
+
+test_expect_success 'git var -l does not split multiline editors' '
+ (
+ GIT_EDITOR="!f() {
+ echo Hello!
+ }; f" &&
+ export GIT_EDITOR &&
+ echo "GIT_EDITOR=$GIT_EDITOR" >expected &&
+ git var -l >var &&
+ cat var &&
+ sed -n -e "/^GIT_EDITOR/,\$p" var | head -n 3 >actual &&
+ test_cmp expected actual
+ )
+'
+
test_expect_success 'listing and asking for variables are exclusive' '
test_must_fail git var -l GIT_COMMITTER_IDENT
'