mirror of
https://github.com/git/git.git
synced 2024-11-23 18:05:29 +08:00
config: read (but not write) from $XDG_CONFIG_HOME/git/config file
Teach git to read the "gitconfig" information from a new location, $XDG_CONFIG_HOME/git/config; this allows the user to avoid cluttering $HOME with many per-application configuration files. In the order of reading, this file comes between the global configuration file (typically $HOME/.gitconfig) and the system wide configuration file (typically /etc/gitconfig). We do not write to this new location (yet). If $XDG_CONFIG_HOME is either not set or empty, $HOME/.config/git/config will be used. This is in line with XDG specification. If the new file does not exist, the behavior is unchanged. Signed-off-by: Huynh Khoi Nguyen Nguyen <Huynh-Khoi-Nguyen.Nguyen@ensimag.imag.fr> Signed-off-by: Valentin Duperray <Valentin.Duperray@ensimag.imag.fr> Signed-off-by: Franck Jonas <Franck.Jonas@ensimag.imag.fr> Signed-off-by: Lucien Kong <Lucien.Kong@ensimag.imag.fr> Signed-off-by: Thomas Nguy <Thomas.Nguy@ensimag.imag.fr> Signed-off-by: Matthieu Moy <Matthieu.Moy@imag.fr> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
0e18bef7e6
commit
21cf322791
@ -99,8 +99,8 @@ OPTIONS
|
||||
For writing options: write to global ~/.gitconfig file rather than
|
||||
the repository .git/config.
|
||||
+
|
||||
For reading options: read only from global ~/.gitconfig rather than
|
||||
from all available files.
|
||||
For reading options: read only from global ~/.gitconfig and from
|
||||
$XDG_CONFIG_HOME/git/config rather than from all available files.
|
||||
+
|
||||
See also <<FILES>>.
|
||||
|
||||
@ -194,7 +194,7 @@ See also <<FILES>>.
|
||||
FILES
|
||||
-----
|
||||
|
||||
If not set explicitly with '--file', there are three files where
|
||||
If not set explicitly with '--file', there are four files where
|
||||
'git config' will search for configuration options:
|
||||
|
||||
$GIT_DIR/config::
|
||||
@ -204,6 +204,14 @@ $GIT_DIR/config::
|
||||
User-specific configuration file. Also called "global"
|
||||
configuration file.
|
||||
|
||||
$XDG_CONFIG_HOME/git/config::
|
||||
Second user-specific configuration file. If $XDG_CONFIG_HOME is not set
|
||||
or empty, $HOME/.config/git/config will be used. Any single-valued
|
||||
variable set in this file will be overwritten by whatever is in
|
||||
~/.gitconfig. It is a good idea not to create this file if
|
||||
you sometimes use older versions of Git, as support for this
|
||||
file was added fairly recently.
|
||||
|
||||
$(prefix)/etc/gitconfig::
|
||||
System-wide configuration file.
|
||||
|
||||
|
@ -161,7 +161,7 @@ static int show_config(const char *key_, const char *value_, void *cb)
|
||||
static int get_value(const char *key_, const char *regex_)
|
||||
{
|
||||
int ret = -1;
|
||||
char *global = NULL, *repo_config = NULL;
|
||||
char *global = NULL, *xdg = NULL, *repo_config = NULL;
|
||||
const char *system_wide = NULL, *local;
|
||||
struct config_include_data inc = CONFIG_INCLUDE_INIT;
|
||||
config_fn_t fn;
|
||||
@ -169,12 +169,10 @@ static int get_value(const char *key_, const char *regex_)
|
||||
|
||||
local = given_config_file;
|
||||
if (!local) {
|
||||
const char *home = getenv("HOME");
|
||||
local = repo_config = git_pathdup("config");
|
||||
if (home)
|
||||
global = xstrdup(mkpath("%s/.gitconfig", home));
|
||||
if (git_config_system())
|
||||
system_wide = git_etc_gitconfig();
|
||||
home_config_paths(&global, &xdg, "config");
|
||||
}
|
||||
|
||||
if (use_key_regexp) {
|
||||
@ -229,6 +227,8 @@ static int get_value(const char *key_, const char *regex_)
|
||||
|
||||
if (do_all && system_wide)
|
||||
git_config_from_file(fn, system_wide, data);
|
||||
if (do_all && xdg)
|
||||
git_config_from_file(fn, xdg, data);
|
||||
if (do_all && global)
|
||||
git_config_from_file(fn, global, data);
|
||||
if (do_all)
|
||||
@ -238,6 +238,8 @@ static int get_value(const char *key_, const char *regex_)
|
||||
git_config_from_file(fn, local, data);
|
||||
if (!do_all && !seen && global)
|
||||
git_config_from_file(fn, global, data);
|
||||
if (!do_all && !seen && xdg)
|
||||
git_config_from_file(fn, xdg, data);
|
||||
if (!do_all && !seen && system_wide)
|
||||
git_config_from_file(fn, system_wide, data);
|
||||
|
||||
@ -255,6 +257,7 @@ static int get_value(const char *key_, const char *regex_)
|
||||
free_strings:
|
||||
free(repo_config);
|
||||
free(global);
|
||||
free(xdg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -379,13 +382,20 @@ int cmd_config(int argc, const char **argv, const char *prefix)
|
||||
}
|
||||
|
||||
if (use_global_config) {
|
||||
char *home = getenv("HOME");
|
||||
if (home) {
|
||||
char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
|
||||
char *user_config = NULL;
|
||||
char *xdg_config = NULL;
|
||||
|
||||
home_config_paths(&user_config, &xdg_config, "config");
|
||||
|
||||
if (access(user_config, R_OK) && !access(xdg_config, R_OK) &&
|
||||
(actions == ACTION_LIST ||
|
||||
actions == ACTION_GET_COLOR ||
|
||||
actions == ACTION_GET_COLORBOOL))
|
||||
given_config_file = xdg_config;
|
||||
else if (user_config)
|
||||
given_config_file = user_config;
|
||||
} else {
|
||||
else
|
||||
die("$HOME not set");
|
||||
}
|
||||
}
|
||||
else if (use_system_config)
|
||||
given_config_file = git_etc_gitconfig();
|
||||
|
3
cache.h
3
cache.h
@ -619,6 +619,8 @@ extern char *git_snpath(char *buf, size_t n, const char *fmt, ...)
|
||||
__attribute__((format (printf, 3, 4)));
|
||||
extern char *git_pathdup(const char *fmt, ...)
|
||||
__attribute__((format (printf, 1, 2)));
|
||||
extern char *mkpathdup(const char *fmt, ...)
|
||||
__attribute__((format (printf, 1, 2)));
|
||||
|
||||
/* Return a statically allocated filename matching the sha1 signature */
|
||||
extern char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
|
||||
@ -708,6 +710,7 @@ int set_shared_perm(const char *path, int mode);
|
||||
int safe_create_leading_directories(char *path);
|
||||
int safe_create_leading_directories_const(const char *path);
|
||||
int mkdir_in_gitdir(const char *path);
|
||||
extern void home_config_paths(char **global, char **xdg, char *file);
|
||||
extern char *expand_user_path(const char *path);
|
||||
const char *enter_repo(const char *path, int strict);
|
||||
static inline int is_absolute_path(const char *path)
|
||||
|
23
config.c
23
config.c
@ -929,7 +929,10 @@ int git_config_system(void)
|
||||
int git_config_early(config_fn_t fn, void *data, const char *repo_config)
|
||||
{
|
||||
int ret = 0, found = 0;
|
||||
const char *home = NULL;
|
||||
char *xdg_config = NULL;
|
||||
char *user_config = NULL;
|
||||
|
||||
home_config_paths(&user_config, &xdg_config, "config");
|
||||
|
||||
if (git_config_system() && !access(git_etc_gitconfig(), R_OK)) {
|
||||
ret += git_config_from_file(fn, git_etc_gitconfig(),
|
||||
@ -937,14 +940,14 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)
|
||||
found += 1;
|
||||
}
|
||||
|
||||
home = getenv("HOME");
|
||||
if (home) {
|
||||
char buf[PATH_MAX];
|
||||
char *user_config = mksnpath(buf, sizeof(buf), "%s/.gitconfig", home);
|
||||
if (!access(user_config, R_OK)) {
|
||||
ret += git_config_from_file(fn, user_config, data);
|
||||
found += 1;
|
||||
}
|
||||
if (!access(xdg_config, R_OK)) {
|
||||
ret += git_config_from_file(fn, xdg_config, data);
|
||||
found += 1;
|
||||
}
|
||||
|
||||
if (!access(user_config, R_OK)) {
|
||||
ret += git_config_from_file(fn, user_config, data);
|
||||
found += 1;
|
||||
}
|
||||
|
||||
if (repo_config && !access(repo_config, R_OK)) {
|
||||
@ -963,6 +966,8 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)
|
||||
break;
|
||||
}
|
||||
|
||||
free(xdg_config);
|
||||
free(user_config);
|
||||
return ret == 0 ? found : ret;
|
||||
}
|
||||
|
||||
|
41
path.c
41
path.c
@ -87,6 +87,21 @@ char *git_pathdup(const char *fmt, ...)
|
||||
return xstrdup(path);
|
||||
}
|
||||
|
||||
char *mkpathdup(const char *fmt, ...)
|
||||
{
|
||||
char *path;
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
strbuf_vaddf(&sb, fmt, args);
|
||||
va_end(args);
|
||||
path = xstrdup(cleanup_path(sb.buf));
|
||||
|
||||
strbuf_release(&sb);
|
||||
return path;
|
||||
}
|
||||
|
||||
char *mkpath(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
@ -122,6 +137,32 @@ char *git_path(const char *fmt, ...)
|
||||
return cleanup_path(pathname);
|
||||
}
|
||||
|
||||
void home_config_paths(char **global, char **xdg, char *file)
|
||||
{
|
||||
char *xdg_home = getenv("XDG_CONFIG_HOME");
|
||||
char *home = getenv("HOME");
|
||||
char *to_free = NULL;
|
||||
|
||||
if (!home) {
|
||||
if (global)
|
||||
*global = NULL;
|
||||
} else {
|
||||
if (!xdg_home) {
|
||||
to_free = mkpathdup("%s/.config", home);
|
||||
xdg_home = to_free;
|
||||
}
|
||||
if (global)
|
||||
*global = mkpathdup("%s/.gitconfig", home);
|
||||
}
|
||||
|
||||
if (!xdg_home)
|
||||
*xdg = NULL;
|
||||
else
|
||||
*xdg = mkpathdup("%s/git/%s", xdg_home, file);
|
||||
|
||||
free(to_free);
|
||||
}
|
||||
|
||||
char *git_path_submodule(const char *path, const char *fmt, ...)
|
||||
{
|
||||
char *pathname = get_pathname();
|
||||
|
70
t/t1306-xdg-files.sh
Executable file
70
t/t1306-xdg-files.sh
Executable file
@ -0,0 +1,70 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright (c) 2012 Valentin Duperray, Lucien Kong, Franck Jonas,
|
||||
# Thomas Nguy, Khoi Nguyen
|
||||
# Grenoble INP Ensimag
|
||||
#
|
||||
|
||||
test_description='Compatibility with $XDG_CONFIG_HOME/git/ files'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
test_expect_success 'read config: xdg file exists and ~/.gitconfig doesn'\''t' '
|
||||
mkdir -p .config/git &&
|
||||
echo "[alias]" >.config/git/config &&
|
||||
echo " myalias = !echo in_config" >>.config/git/config &&
|
||||
echo in_config >expected &&
|
||||
git myalias >actual &&
|
||||
test_cmp expected actual
|
||||
'
|
||||
|
||||
|
||||
test_expect_success 'read config: xdg file exists and ~/.gitconfig exists' '
|
||||
>.gitconfig &&
|
||||
echo "[alias]" >.gitconfig &&
|
||||
echo " myalias = !echo in_gitconfig" >>.gitconfig &&
|
||||
echo in_gitconfig >expected &&
|
||||
git myalias >actual &&
|
||||
test_cmp expected actual
|
||||
'
|
||||
|
||||
|
||||
test_expect_success 'read with --get: xdg file exists and ~/.gitconfig doesn'\''t' '
|
||||
rm .gitconfig &&
|
||||
echo "[user]" >.config/git/config &&
|
||||
echo " name = read_config" >>.config/git/config &&
|
||||
echo read_config >expected &&
|
||||
git config --get user.name >actual &&
|
||||
test_cmp expected actual
|
||||
'
|
||||
|
||||
|
||||
test_expect_success 'read with --get: xdg file exists and ~/.gitconfig exists' '
|
||||
>.gitconfig &&
|
||||
echo "[user]" >.gitconfig &&
|
||||
echo " name = read_gitconfig" >>.gitconfig &&
|
||||
echo read_gitconfig >expected &&
|
||||
git config --get user.name >actual &&
|
||||
test_cmp expected actual
|
||||
'
|
||||
|
||||
|
||||
test_expect_success 'read with --list: xdg file exists and ~/.gitconfig doesn'\''t' '
|
||||
rm .gitconfig &&
|
||||
echo user.name=read_config >expected &&
|
||||
git config --global --list >actual &&
|
||||
test_cmp expected actual
|
||||
'
|
||||
|
||||
|
||||
test_expect_success 'read with --list: xdg file exists and ~/.gitconfig exists' '
|
||||
>.gitconfig &&
|
||||
echo "[user]" >.gitconfig &&
|
||||
echo " name = read_gitconfig" >>.gitconfig &&
|
||||
echo user.name=read_gitconfig >expected &&
|
||||
git config --global --list >actual &&
|
||||
test_cmp expected actual
|
||||
'
|
||||
|
||||
|
||||
test_done
|
Loading…
Reference in New Issue
Block a user