Re: [PATCH] config: read system-wide defaults from /etc/gitconfig

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]