Subject: Re: [PATCH] git-new-workdir: support submodules

From: Duy Nguyen <[email-masked]>
Date: Wed, 28 Jan 2015 17:50:07 +0700

On Tue, Jan 27, 2015 at 06:35:41PM +0100, Jens Lehmann wrote:
> > One way to do so might be to move the bits it stores in the config
> > file to somewhere else that is more closely tied to the checkout
> > state and handle that similar to .git/index and .git/HEAD when it
> > comes to multiple work-trees.
> 
> Yup, the idea of separating config entries into worktree and repo
> specific files sounds like the solution for these problems.

OK, would this work? This PoC patch adds a config key namespace
local.* that is written to $GIT_DIR/config.local instead of
$GIT_DIR/config (I still need to ban local.* in global config
files). This config.local is loaded togethr with $GIT_DIR/config.

For nd/multiple-work-trees we can transparently map
$GIT_DIR/config.local to $SUPER/worktrees/<id>/config.local. For
git-new-workdir.sh, perhaps we can teach include.path to make
config.local path relative to where the config symlink is, not where
the symlink target is.

We can then teach setup.c to read local.core.worktree if core.worktree
is not present, and more apdation in git-submodule.sh.. I don't expect
big changes because git-submodule.sh just needs to read some other
config keys and dont need to care if git-new-workdir.sh or
nd/multiple-work-trees is being used.

-- 8< --
diff --git a/config.c b/config.c
index 752e2e2..237bd8e 100644
--- a/config.c
+++ b/config.c
@@ -1177,6 +1177,15 @@ int git_config_system(void)
 	return !git_env_bool("GIT_CONFIG_NOSYSTEM", 0);
 }
 
+static int config_local_filter(const char *var, const char *value, void *data)
+{
+	struct config_include_data *inc = data;
+
+	if (!starts_with(var, "local."))
+		return error("$GIT_DIR/config.local can only contain local.*");
+	return inc->fn(var, value, inc->data);
+}
+
 int git_config_early(config_fn_t fn, void *data, const char *repo_config)
 {
 	int ret = 0, found = 0;
@@ -1202,8 +1211,19 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)
 	}
 
 	if (repo_config && !access_or_die(repo_config, R_OK, 0)) {
+		char *wt_config;
 		ret += git_config_from_file(fn, repo_config, data);
 		found += 1;
+		wt_config = git_pathdup("config.local");
+		if (!access_or_die(wt_config, R_OK, 0)) {
+			struct config_include_data inc = CONFIG_INCLUDE_INIT;
+			inc.fn = fn;
+			inc.data = data;
+			ret += git_config_from_file(config_local_filter,
+						    wt_config, &inc);
+			found += 1;
+		}
+		free(wt_config);
 	}
 
 	switch (git_config_from_parameters(fn, data)) {
@@ -1942,8 +1962,12 @@ int git_config_set_multivar_in_file(const char *config_filename,
 
 	store.multi_replace = multi_replace;
 
-	if (!config_filename)
-		config_filename = filename_buf = git_pathdup("config");
+	if (!config_filename) {
+		if (starts_with(key, "local."))
+			config_filename = filename_buf = git_pathdup("config.local");
+		else
+			config_filename = filename_buf = git_pathdup("config");
+	}
 
 	/*
 	 * The lock serves a purpose in addition to locking: the new
-- 8< --