Johannes Schindelin <Johannes.Schindelin@xxxxxx> writes: >> I think we need to have a way to disable this setting, perhaps >> via an environment variable. > > Yes. Just set GIT_CONFIG=/what/ever, and it no longer reads from > ~/.gitconfig or $prefix/etc/gitconfig. I think GIT_CONFIG and GIT_LOCAL_CONFIG environment variables are seriously misdesigned. At least, I do not think of a sane way to make use of them. For one thing, when they are set, truly per-repository variables such as repositoryformatversion, legacyheaders and sharedrepository are all ignored. What I would think is sensible would be simply to: - $GIT_CONFIG_SYSTEM environment, if set, names a file to be read first. It defaults to /etc/gitconfig. You can set it to /dev/null to avoid using /etc/gitconfig if you have specific need. - Then $HOME/.gitconfig is read. - Then $GIT_DIR/config is read. Information read from later files overrides the earlier ones, as before. I am not quite sure how $GIT_CONFIG and $GIT_CONFIG_LOCAL were meant to be used. Are there any *real* users? With lack of information on the intended uses of these two environment variables, I hacked up the following tweaks on top of the above defined semantics, to imitate what I _think_ was the original intention. The hacked one goes like this: - $GIT_CONFIG environment, if set, names a file to be read first. We read it first. - If $GIT_CONFIG is unset, then $GIT_CONFIG_SYSTEM (or /etc/gitconfig) and $HOME/.gitconfig are read, as above. - Next file to be read is $GIT_CONFIG_LOCAL (if set) or $GIT_DIR/config. When reading this file, if we read from $GIT_CONFIG earlier, we read only "core.*" section from it. The difference from the original, aside from the additional business with /etc/gitconfig, is that this updated one does read from $GIT_DIR/config (or $GIT_CONFIG_LOCAL) to avoid missing more important per-repo variables. Since I did not understand why $GIT_CONFIG makes the remaining configuration files to be totally skipped in the original, I added hacks to make the last step to read only minimally. I'd rather not to have the hacks to deal with GIT_CONFIG and GIT_CONFIG_LOCAL I did in this patch, but I do not know enough to tell if they are meaningless hacks to imitate ill-defined original semantics, or if they still cover useful use cases these two environment variables were originally invented to satisfy. --- Makefile | 10 +++++-- cache.h | 4 +++ config.c | 84 +++++++++++++++++++++++++++++++++++++++---------------------- 3 files changed, 65 insertions(+), 33 deletions(-) diff --git a/Makefile b/Makefile index ebecbbd..4232465 100644 --- a/Makefile +++ b/Makefile @@ -122,6 +122,7 @@ STRIP ?= strip prefix = $(HOME) bindir = $(prefix)/bin +etcdir = $(prefix)/etc gitexecdir = $(bindir) template_dir = $(prefix)/share/git-core/templates/ # DESTDIR= @@ -142,7 +143,7 @@ GITWEB_FAVICON = git-favicon.png GITWEB_SITE_HEADER = GITWEB_SITE_FOOTER = -export prefix bindir gitexecdir template_dir +export prefix bindir etcdir gitexecdir template_dir CC = gcc AR = ar @@ -587,6 +588,7 @@ SHA1_HEADER_SQ = $(subst ','\'',$(SHA1_HEADER)) DESTDIR_SQ = $(subst ','\'',$(DESTDIR)) bindir_SQ = $(subst ','\'',$(bindir)) +etcdir_SQ = $(subst ','\'',$(etcdir)) gitexecdir_SQ = $(subst ','\'',$(gitexecdir)) template_dir_SQ = $(subst ','\'',$(template_dir)) prefix_SQ = $(subst ','\'',$(prefix)) @@ -596,7 +598,9 @@ PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH)) LIBS = $(GITLIBS) $(EXTLIBS) -BASIC_CFLAGS += -DSHA1_HEADER='$(SHA1_HEADER_SQ)' $(COMPAT_CFLAGS) +BASIC_CFLAGS += -DSHA1_HEADER='$(SHA1_HEADER_SQ)' +BASIC_CFLAGS += -DGIT_CONFIG_SYSTEM='"$(etcdir_SQ)/gitconfig"' +BASIC_CFLAGS += $(COMPAT_CFLAGS) LIB_OBJS += $(COMPAT_OBJS) ALL_CFLAGS += $(BASIC_CFLAGS) diff --git a/cache.h b/cache.h index c62b0b0..2b4e26d 100644 --- a/cache.h +++ b/cache.h @@ -125,6 +125,10 @@ extern int cache_errno; #define TEMPLATE_DIR_ENVIRONMENT "GIT_TEMPLATE_DIR" #define CONFIG_ENVIRONMENT "GIT_CONFIG" #define CONFIG_LOCAL_ENVIRONMENT "GIT_CONFIG_LOCAL" +#define CONFIG_SYSTEM_ENVIRONMENT "GIT_CONFIG_SYSTEM" +#ifndef GIT_CONFIG_SYSTEM +#define GIT_CONFIG_SYSTEM "/etc/gitconfig" +#endif #define EXEC_PATH_ENVIRONMENT "GIT_EXEC_PATH" extern int is_bare_repository_cfg; diff --git a/config.c b/config.c index c938aa0..7ec0d9a 100644 --- a/config.c +++ b/config.c @@ -107,7 +107,7 @@ static inline int iskeychar(int c) return isalnum(c) || c == '-'; } -static int get_value(config_fn_t fn, char *name, unsigned int len) +static int get_value(config_fn_t fn, char *name, unsigned int len, int core_only) { int c; char *value; @@ -135,6 +135,8 @@ static int get_value(config_fn_t fn, char *name, unsigned int len) if (!value) return -1; } + if (core_only && strncmp(name, "core.", 5)) + return 0; return fn(name, value); } @@ -193,7 +195,7 @@ static int get_base_var(char *name) } } -static int git_parse_file(config_fn_t fn) +static int git_parse_file(config_fn_t fn, int core_only) { int comment = 0; int baselen = 0; @@ -225,7 +227,8 @@ static int git_parse_file(config_fn_t fn) if (!isalpha(c)) break; var[baselen] = tolower(c); - if (get_value(fn, var, baselen+1) < 0) + + if (get_value(fn, var, baselen+1, core_only) < 0) break; } die("bad config file line %d in %s", config_linenr, config_file_name); @@ -356,50 +359,71 @@ int git_default_config(const char *var, const char *value) return 0; } -int git_config_from_file(config_fn_t fn, const char *filename) +static int git_config_from_file_1(config_fn_t fn, const char *filename, int core_only, int missing_ok) { int ret; FILE *f = fopen(filename, "r"); - ret = -1; + ret = missing_ok ? 0 : -1; if (f) { config_file = f; config_file_name = filename; config_linenr = 1; - ret = git_parse_file(fn); + ret = git_parse_file(fn, core_only); fclose(f); config_file_name = NULL; } return ret; } +int git_config_from_file(config_fn_t fn, const char *filename) +{ + return git_config_from_file_1(fn, filename, 0, 0); +} + int git_config(config_fn_t fn) { + /* + * If GIT_CONFIG environment is set, then it is read first. + * If GIT_CONFIG environment is not set, + * GIT_CONFIG_SYSTEM (default /etc/gitconfig) is read next. + * Then $HOME/.gitconfig is read. + * + * Then, if GIT_CONFIG_LOCAL is set, it is read. + * Otherwise "$GIT_DIR/config" is read. + * + * However, if we read from GIT_CONFIG environment earlier, we + * only read "core.*" section in the last step. + */ 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(CONFIG_ENVIRONMENT); - if (!filename) { - home = getenv("HOME"); - filename = getenv(CONFIG_LOCAL_ENVIRONMENT); - if (!filename) - filename = repo_config = xstrdup(git_path("config")); - } - - if (home) { - char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); - if (!access(user_config, R_OK)) - ret = git_config_from_file(fn, user_config); - free(user_config); - } - - ret += git_config_from_file(fn, filename); - free(repo_config); + int core_only; + char *cfg; + char path[PATH_MAX]; + + cfg = getenv(CONFIG_ENVIRONMENT); + if (cfg) { + ret += git_config_from_file_1(fn, cfg, 0, 1); + core_only = 1; + } + else { + core_only = 0; + cfg = getenv(CONFIG_SYSTEM_ENVIRONMENT); + if (!cfg) + cfg = GIT_CONFIG_SYSTEM; + ret += git_config_from_file_1(fn, cfg, 0, 1); + + cfg = getenv("HOME"); + if (cfg) { + snprintf(path, sizeof(path), "%s/.gitconfig", cfg); + ret += git_config_from_file_1(fn, path, 0, 1); + } + } + cfg = getenv(CONFIG_LOCAL_ENVIRONMENT); + if (!cfg) { + strcpy(path, git_path("config")); + cfg = path; + } + ret += git_config_from_file_1(fn, cfg, core_only, 1); return ret; } - To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html