Skip to content

Commit

Permalink
Merge branch 'mm/config-xdg'
Browse files Browse the repository at this point in the history
Teach git to read various information from $XDG_CONFIG_HOME/git/ to allow
the user to avoid cluttering $HOME.

* mm/config-xdg:
  config: write to $XDG_CONFIG_HOME/git/config file when appropriate
  Let core.attributesfile default to $XDG_CONFIG_HOME/git/attributes
  Let core.excludesfile default to $XDG_CONFIG_HOME/git/ignore
  config: read (but not write) from $XDG_CONFIG_HOME/git/config file
  • Loading branch information
Junio C Hamano committed Jul 9, 2012
2 parents 8228a23 + 0e8593d commit d02d7ac
Show file tree
Hide file tree
Showing 11 changed files with 272 additions and 33 deletions.
8 changes: 6 additions & 2 deletions Documentation/config.txt
Original file line number Diff line number Diff line change
Expand Up @@ -484,7 +484,9 @@ core.excludesfile::
'.git/info/exclude', git looks into this file for patterns
of files which are not meant to be tracked. "`~/`" is expanded
to the value of `$HOME` and "`~user/`" to the specified user's
home directory. See linkgit:gitignore[5].
home directory. Its default value is $XDG_CONFIG_HOME/git/ignore.
If $XDG_CONFIG_HOME is either not set or empty, $HOME/.config/git/ignore
is used instead. See linkgit:gitignore[5].

core.askpass::
Some commands (e.g. svn and http interfaces) that interactively
Expand All @@ -499,7 +501,9 @@ core.attributesfile::
In addition to '.gitattributes' (per-directory) and
'.git/info/attributes', git looks into this file for attributes
(see linkgit:gitattributes[5]). Path expansions are made the same
way as for `core.excludesfile`.
way as for `core.excludesfile`. Its default value is
$XDG_CONFIG_HOME/git/attributes. If $XDG_CONFIG_HOME is either not
set or empty, $HOME/.config/git/attributes is used instead.

core.editor::
Commands such as `commit` and `tag` that lets you edit
Expand Down
17 changes: 13 additions & 4 deletions Documentation/git-config.txt
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,11 @@ OPTIONS

--global::
For writing options: write to global ~/.gitconfig file rather than
the repository .git/config.
the repository .git/config, write to $XDG_CONFIG_HOME/git/config file
if this file exists and the ~/.gitconfig file doesn't.
+
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>>.

Expand Down Expand Up @@ -194,7 +195,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::
Expand All @@ -204,6 +205,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.

Expand Down
2 changes: 2 additions & 0 deletions Documentation/gitattributes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ repositories (i.e., attributes of interest to all users) should go into
`.gitattributes` files. Attributes that should affect all repositories
for a single user should be placed in a file specified by the
`core.attributesfile` configuration option (see linkgit:git-config[1]).
Its default value is $XDG_CONFIG_HOME/git/attributes. If $XDG_CONFIG_HOME
is either not set or empty, $HOME/.config/git/attributes is used instead.
Attributes for all users on a system should be placed in the
`$(prefix)/etc/gitattributes` file.

Expand Down
4 changes: 3 additions & 1 deletion Documentation/gitignore.txt
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ the repository but are specific to one user's workflow) should go into
the `$GIT_DIR/info/exclude` file. Patterns which a user wants git to
ignore in all situations (e.g., backup or temporary files generated by
the user's editor of choice) generally go into a file specified by
`core.excludesfile` in the user's `~/.gitconfig`.
`core.excludesfile` in the user's `~/.gitconfig`. Its default value is
$XDG_CONFIG_HOME/git/ignore. If $XDG_CONFIG_HOME is either not set or empty,
$HOME/.config/git/ignore is used instead.

The underlying git plumbing tools, such as
'git ls-files' and 'git read-tree', read
Expand Down
17 changes: 10 additions & 7 deletions attr.c
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,7 @@ static int git_attr_system(void)
static void bootstrap_attr_stack(void)
{
struct attr_stack *elem;
char *xdg_attributes_file;

if (attr_stack)
return;
Expand All @@ -515,13 +516,15 @@ static void bootstrap_attr_stack(void)
}
}

if (git_attributes_file) {
elem = read_attr_from_file(git_attributes_file, 1);
if (elem) {
elem->origin = NULL;
elem->prev = attr_stack;
attr_stack = elem;
}
if (!git_attributes_file) {
home_config_paths(NULL, &xdg_attributes_file, "attributes");
git_attributes_file = xdg_attributes_file;
}
elem = read_attr_from_file(git_attributes_file, 1);
if (elem) {
elem->origin = NULL;
elem->prev = attr_stack;
attr_stack = elem;
}

if (!is_bare_repository() || direction == GIT_ATTR_INDEX) {
Expand Down
25 changes: 16 additions & 9 deletions builtin/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -161,20 +161,18 @@ 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;
void *data;

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) {
Expand Down Expand Up @@ -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)
Expand 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);

Expand All @@ -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;
}

Expand Down Expand Up @@ -379,13 +382,17 @@ 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))
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();
Expand Down
3 changes: 3 additions & 0 deletions cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -622,6 +622,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)));
Expand Down Expand Up @@ -711,6 +713,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)
Expand Down
23 changes: 14 additions & 9 deletions config.c
Original file line number Diff line number Diff line change
Expand Up @@ -929,22 +929,25 @@ 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(),
data);
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)) {
Expand All @@ -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;
}

Expand Down
7 changes: 6 additions & 1 deletion dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -1303,12 +1303,17 @@ int remove_dir_recursively(struct strbuf *path, int flag)
void setup_standard_excludes(struct dir_struct *dir)
{
const char *path;
char *xdg_path;

dir->exclude_per_dir = ".gitignore";
path = git_path("info/exclude");
if (!excludes_file) {
home_config_paths(NULL, &xdg_path, "ignore");
excludes_file = xdg_path;
}
if (!access(path, R_OK))
add_excludes_from_file(dir, path);
if (excludes_file && !access(excludes_file, R_OK))
if (!access(excludes_file, R_OK))
add_excludes_from_file(dir, excludes_file);
}

Expand Down
41 changes: 41 additions & 0 deletions path.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand Down
Loading

0 comments on commit d02d7ac

Please sign in to comment.