From 7f29f7a95c906250c9c99d08242c2c4084c48d24 Mon Sep 17 00:00:00 2001 From: Petr Baudis Date: Sun, 18 Jun 2006 01:23:58 +0200 Subject: [PATCH 1/5] Support for extracting configuration from different files Add $GIT_CONFIG environment variable whose content is used instead of .git/config if set. Also add $GIT_CONFIG_LOCAL as a forward-compatibility cue for whenever we will finally come to support] global configuration files (properly). Signed-off-by: Petr Baudis Signed-off-by: Junio C Hamano --- Documentation/git-repo-config.txt | 12 ++++++++++++ config.c | 12 +++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/Documentation/git-repo-config.txt b/Documentation/git-repo-config.txt index d5142e0dc..803c0d5ca 100644 --- a/Documentation/git-repo-config.txt +++ b/Documentation/git-repo-config.txt @@ -73,6 +73,18 @@ OPTIONS List all variables set in .git/config. +ENVIRONMENT +----------- + +GIT_CONFIG:: + Take the configuration from the given file instead of .git/config. + +GIT_CONFIG_LOCAL:: + Currently the same as $GIT_CONFIG; when Git will support global + configuration files, this will cause it to take the configuration + from the global configuration file in addition to the given file. + + EXAMPLE ------- diff --git a/config.c b/config.c index 984c75f5d..d46eb6d82 100644 --- a/config.c +++ b/config.c @@ -317,7 +317,17 @@ int git_config_from_file(config_fn_t fn, const char *filename) int git_config(config_fn_t fn) { - return git_config_from_file(fn, git_path("config")); + const char *filename = git_path("config"); + /* Forward-compatibility cue: $GIT_CONFIG makes git read _only_ + * the given config file, $GIT_CONFIG_LOCAL will make it process + * it in addition to the global config file, the same way it would + * the per-repository config file otherwise. */ + if (getenv("GIT_CONFIG")) { + filename = getenv("GIT_CONFIG"); + } else if (getenv("GIT_CONFIG_LOCAL")) { + filename = getenv("GIT_CONFIG_LOCAL"); + } + return git_config_from_file(fn, filename); } /* From 9c3796fc0474ac6fc77da4886a246a37a7fbe856 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 20 Jun 2006 00:51:58 +0200 Subject: [PATCH 2/5] Fix setting config variables with an alternative GIT_CONFIG When setting a config variable, git_config_set() ignored the variables GIT_CONFIG and GIT_CONFIG_LOCAL. Now, when GIT_CONFIG_LOCAL is set, it will write to that file. If not, GIT_CONFIG is checked, and only as a fallback, the change is written to $GIT_DIR/config. Add a test for it, and also future-proof the test for the upcoming $HOME/.gitconfig support. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- config.c | 15 ++++++++++++--- t/Makefile | 2 +- t/t1300-repo-config.sh | 24 ++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 4 deletions(-) diff --git a/config.c b/config.c index d46eb6d82..37862d429 100644 --- a/config.c +++ b/config.c @@ -500,10 +500,19 @@ int git_config_set_multivar(const char* key, const char* value, int i, dot; int fd = -1, in_fd; int ret; - char* config_filename = strdup(git_path("config")); - char* lock_file = strdup(git_path("config.lock")); + char* config_filename; + char* lock_file; const char* last_dot = strrchr(key, '.'); + config_filename = getenv("GIT_CONFIG"); + if (!config_filename) { + config_filename = getenv("GIT_CONFIG_LOCAL"); + if (!config_filename) + config_filename = git_path("config"); + } + config_filename = strdup(config_filename); + lock_file = strdup(mkpath("%s.lock", config_filename)); + /* * Since "key" actually contains the section name and the real * key name separated by a dot, we have to know where the dot is. @@ -610,7 +619,7 @@ int git_config_set_multivar(const char* key, const char* value, * As a side effect, we make sure to transform only a valid * existing config file. */ - if (git_config(store_aux)) { + if (git_config_from_file(store_aux, config_filename)) { fprintf(stderr, "invalid config file\n"); free(store.key); if (store.value_regex != NULL) { diff --git a/t/Makefile b/t/Makefile index 549598575..632c55f6d 100644 --- a/t/Makefile +++ b/t/Makefile @@ -19,7 +19,7 @@ endif all: $(T) clean $(T): - @echo "*** $@ ***"; '$(SHELL_PATH_SQ)' $@ $(GIT_TEST_OPTS) + @echo "*** $@ ***"; GIT_CONFIG=.git/config '$(SHELL_PATH_SQ)' $@ $(GIT_TEST_OPTS) clean: rm -fr trash diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index 8260d57b6..0de249774 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -309,5 +309,29 @@ EOF test_expect_success 'new variable inserts into proper section' 'cmp .git/config expect' +cat > other-config << EOF +[ein] + bahn = strasse +EOF + +cat > expect << EOF +ein.bahn=strasse +EOF + +GIT_CONFIG=other-config git-repo-config -l > output + +test_expect_success 'alternative GIT_CONFIG' 'cmp output expect' + +GIT_CONFIG=other-config git-repo-config anwohner.park ausweis + +cat > expect << EOF +[ein] + bahn = strasse +[anwohner] + park = ausweis +EOF + +test_expect_success '--set in alternative GIT_CONFIG' 'cmp other-config expect' + test_done From 5f1a63e0efc750c54a25644a36cf2905495a9b93 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 20 Jun 2006 01:48:03 +0200 Subject: [PATCH 3/5] Read configuration also from $HOME/.gitconfig This patch is based on Pasky's, with three notable differences: - I did not yet update the documentation - I named it .gitconfig, not .gitrc - git-repo-config does not barf when a unique key is overridden locally The last means that if you have something like [alias] l = log --stat -M in ~/.gitconfig, and [alias] l = log --stat -M next.. in $GIT_DIR/config, then git-repo-config alias.l returns only one value, namely the value from $GIT_DIR/config. If you set the environment variable GIT_CONFIG, $HOME/.gitconfig is not read, and neither $GIT_DIR/config, but $GIT_CONFIG instead. If you set GIT_CONFIG_LOCAL instead, it is interpreted instead of $GIT_DIR/config, but $HOME/.gitconfig is still read. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- config.c | 34 +++++++++++++++++++++++++--------- repo-config.c | 39 +++++++++++++++++++++++++++++++++------ 2 files changed, 58 insertions(+), 15 deletions(-) diff --git a/config.c b/config.c index 37862d429..d064f429c 100644 --- a/config.c +++ b/config.c @@ -317,17 +317,33 @@ int git_config_from_file(config_fn_t fn, const char *filename) int git_config(config_fn_t fn) { - const char *filename = git_path("config"); - /* Forward-compatibility cue: $GIT_CONFIG makes git read _only_ - * the given config file, $GIT_CONFIG_LOCAL will make it process - * it in addition to the global config file, the same way it would - * the per-repository config file otherwise. */ - if (getenv("GIT_CONFIG")) { - filename = getenv("GIT_CONFIG"); - } else if (getenv("GIT_CONFIG_LOCAL")) { + int ret = 0; + char *repo_config = NULL; + const char *home = NULL, *filename; + + /* $GIT_CONFIG makes git read _only_ the given config file, + * $GIT_CONFIG_LOCAL will make it process it in addition to the + * global config file, the same way it would the per-repository + * config file otherwise. */ + filename = getenv("GIT_CONFIG"); + if (!filename) { + home = getenv("HOME"); filename = getenv("GIT_CONFIG_LOCAL"); + if (!filename) + filename = repo_config = strdup(git_path("config")); } - return git_config_from_file(fn, filename); + + if (home) { + char *user_config = strdup(mkpath("%s/.gitconfig", home)); + if (access(user_config, R_OK) > 0) + ret = git_config_from_file(fn, user_config); + free(user_config); + } + + ret += git_config_from_file(fn, filename); + if (repo_config) + free(repo_config); + return ret; } /* diff --git a/repo-config.c b/repo-config.c index 08fc4cc57..03f108fe2 100644 --- a/repo-config.c +++ b/repo-config.c @@ -64,7 +64,22 @@ static int show_config(const char* key_, const char* value_) static int get_value(const char* key_, const char* regex_) { + int ret = -1; char *tl; + char *global = NULL, *repo_config = NULL; + const char *local; + + local = getenv("GIT_CONFIG"); + if (!local) { + const char *home = getenv("HOME"); + local = getenv("GIT_CONFIG_LOCAL"); + if (!local) + local = repo_config; + else + local = repo_config = strdup(git_path("config")); + if (home) + global = strdup(mkpath("%s/.gitconfig", home)); + } key = strdup(key_); for (tl=key+strlen(key)-1; tl >= key && *tl != '.'; --tl) @@ -76,7 +91,7 @@ static int get_value(const char* key_, const char* regex_) key_regexp = (regex_t*)malloc(sizeof(regex_t)); if (regcomp(key_regexp, key, REG_EXTENDED)) { fprintf(stderr, "Invalid key pattern: %s\n", key_); - return -1; + goto free_strings; } } @@ -89,11 +104,16 @@ static int get_value(const char* key_, const char* regex_) regexp = (regex_t*)malloc(sizeof(regex_t)); if (regcomp(regexp, regex_, REG_EXTENDED)) { fprintf(stderr, "Invalid pattern: %s\n", regex_); - return -1; + goto free_strings; } } - git_config(show_config); + if (do_all && global) + git_config_from_file(show_config, global); + git_config_from_file(show_config, local); + if (!do_all && !seen && global) + git_config_from_file(show_config, global); + free(key); if (regexp) { regfree(regexp); @@ -101,9 +121,16 @@ static int get_value(const char* key_, const char* regex_) } if (do_all) - return !seen; - - return (seen == 1) ? 0 : 1; + ret = !seen; + else + ret = (seen == 1) ? 0 : 1; + +free_strings: + if (repo_config) + free(repo_config); + if (global) + free(global); + return ret; } int main(int argc, const char **argv) From 92a28be0ce12a50e0e53268be99130c2ef504c7e Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 20 Jun 2006 09:45:53 +0200 Subject: [PATCH 4/5] repo-config: Fix late-night bug This bug was hidden by the "future-proofing" of the test. Sigh. When neither GIT_CONFIG nor GIT_CONFIG_LOCAL is set, do not use NULL, but $GIT_DIR/config. Instead of using $GIT_DIR/config when only GIT_CONFIG_LOCAL is set. Sorry. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- repo-config.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/repo-config.c b/repo-config.c index 03f108fe2..ab8f1afee 100644 --- a/repo-config.c +++ b/repo-config.c @@ -74,8 +74,6 @@ static int get_value(const char* key_, const char* regex_) const char *home = getenv("HOME"); local = getenv("GIT_CONFIG_LOCAL"); if (!local) - local = repo_config; - else local = repo_config = strdup(git_path("config")); if (home) global = strdup(mkpath("%s/.gitconfig", home)); From e33d0611c0dd438ed9c1960518540c707201707a Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 20 Jun 2006 09:51:09 +0200 Subject: [PATCH 5/5] git_config: access() returns 0 on success, not > 0 Another late-night bug. Sorry again. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.c b/config.c index d064f429c..3e077d4c6 100644 --- a/config.c +++ b/config.c @@ -335,7 +335,7 @@ int git_config(config_fn_t fn) if (home) { char *user_config = strdup(mkpath("%s/.gitconfig", home)); - if (access(user_config, R_OK) > 0) + if (!access(user_config, R_OK)) ret = git_config_from_file(fn, user_config); free(user_config); }