All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/5] Split .git/config in multiple worktree setup
@ 2015-12-02 19:13 Nguyễn Thái Ngọc Duy
  2015-12-02 19:13 ` [PATCH 1/5] dir.c: clean the entire struct in clear_exclude_list() Nguyễn Thái Ngọc Duy
                   ` (6 more replies)
  0 siblings, 7 replies; 53+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-12-02 19:13 UTC (permalink / raw)
  To: git
  Cc: Michael J Gruber, Max Kirillov, Jens Lehmann,
	Nguyễn Thái Ngọc Duy

Let's restart this. From the last discussion [1], we need to make
core.worktree per-worktree for submodules to work. We also need
core.sparseCheckout per-worktree.

This series adds a pattern list, with .gitignore syntax mostly, that
split config var set into two sets, the per-worktree set will be
stored in .git/worktrees/*/config.worktree instead. The pattern list
consists of default patterns, built in git binary, and user ones in
.git/info/config.worktree.

I have marked a few obvious config vars as per-worktree. There may be
more to mark, Max did go over them last time so I'll let him to add
more if submodule needs it.

[1] http://article.gmane.org/gmane.comp.version-control.git/266520

Nguyễn Thái Ngọc Duy (5):
  dir.c: clean the entire struct in clear_exclude_list()
  config.c: move worktree-specific variables to .git/worktrees/...
  setup.c: remove special case of core.worktree and core.bare
  worktree: make core.sparseCheckout and core.ignoreStat per-worktree
  git-worktree.txt: mention about the config file split

 Documentation/config.txt               |  13 ++-
 Documentation/git-worktree.txt         |  13 +++
 Documentation/gitrepository-layout.txt |  12 +++
 builtin/config.c                       |   9 ++
 cache.h                                |   2 +-
 config.c                               | 153 +++++++++++++++++++++++++++++++--
 dir.c                                  |   6 +-
 dir.h                                  |   1 +
 setup.c                                |  62 ++++++-------
 t/t2025-worktree-add.sh                |  26 ++++++
 10 files changed, 250 insertions(+), 47 deletions(-)

-- 
2.2.0.513.g477eb31

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH 1/5] dir.c: clean the entire struct in clear_exclude_list()
  2015-12-02 19:13 [PATCH 0/5] Split .git/config in multiple worktree setup Nguyễn Thái Ngọc Duy
@ 2015-12-02 19:13 ` Nguyễn Thái Ngọc Duy
  2015-12-02 19:13 ` [PATCH 2/5] config.c: move worktree-specific variables to .git/worktrees/ Nguyễn Thái Ngọc Duy
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 53+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-12-02 19:13 UTC (permalink / raw)
  To: git
  Cc: Michael J Gruber, Max Kirillov, Jens Lehmann,
	Nguyễn Thái Ngọc Duy

Make sure "el" can be reuseable again. The problem was el->alloc is
not cleared and may cause segfaults next time because add_exclude()
thinks el->excludes (being NULL) has enough space. Just clear the
entire struct to be safe.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 dir.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/dir.c b/dir.c
index d2a8f06..b8b4576 100644
--- a/dir.c
+++ b/dir.c
@@ -564,9 +564,7 @@ void clear_exclude_list(struct exclude_list *el)
 	free(el->excludes);
 	free(el->filebuf);
 
-	el->nr = 0;
-	el->excludes = NULL;
-	el->filebuf = NULL;
+	memset(el, 0, sizeof(*el));
 }
 
 static void trim_trailing_spaces(char *buf)
-- 
2.2.0.513.g477eb31

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH 2/5] config.c: move worktree-specific variables to .git/worktrees/...
  2015-12-02 19:13 [PATCH 0/5] Split .git/config in multiple worktree setup Nguyễn Thái Ngọc Duy
  2015-12-02 19:13 ` [PATCH 1/5] dir.c: clean the entire struct in clear_exclude_list() Nguyễn Thái Ngọc Duy
@ 2015-12-02 19:13 ` Nguyễn Thái Ngọc Duy
  2015-12-06  7:47   ` Eric Sunshine
  2015-12-02 19:13 ` [PATCH 3/5] setup.c: remove special case of core.worktree and core.bare Nguyễn Thái Ngọc Duy
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 53+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-12-02 19:13 UTC (permalink / raw)
  To: git
  Cc: Michael J Gruber, Max Kirillov, Jens Lehmann,
	Nguyễn Thái Ngọc Duy

.git/info/config.worktree is a pattern list that splits .git/config in
to sets: the worktree set matches the patterns, the commmon set does
not.

In normal worktrees, both sets are stored in .git/config. The
config.worktree has no effect. Nothing is changed.

In linked worktrees, the common and worktree sets are read from and
saved to .git/config and .git/config.worktree respectively. Config
keys in .git/config that belong to the worktree set is ignored. Those
are for the main worktree only. Similarly, keys not matching the
patterns come from .git/config, duplicate keys from
.git/config.worktree are ignored.

The effect is similar to the $GIT_DIR/$GIT_COMMON_DIR split, we can
define that some vars can be shared and some cannot. And as a result
of the $GIT_DIR/$GIT_COMMON_DIR split, config.worktree is actually
found at .git/worktrees/<id>/config.worktree.

Throwing the exclude mechanism into this means reading config files
will be slower. But unless somebody reads thousands of keys, it should
not be noticable. The nice thing is we don't have to introduce yet
another pattern syntax.

In future, we might want to have a shared config file to contain
common worktree-specific settings, so that we have some good defaults,
but still allow customization. Or we could twist the above logic a
bit: for linked worktrees, read _all_ variables in config.worktree
regardless of the patterns. But let's wait and see..

Helped-by: Max Kirillov <max@max630.net>
Helped-by: Jens Lehmann <Jens.Lehmann@web.de>
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/config.txt               |   4 +
 Documentation/gitrepository-layout.txt |  12 +++
 builtin/config.c                       |   9 +++
 cache.h                                |   2 +-
 config.c                               | 143 +++++++++++++++++++++++++++++++--
 dir.c                                  |   2 +-
 dir.h                                  |   1 +
 setup.c                                |   2 +-
 t/t2025-worktree-add.sh                |  26 ++++++
 9 files changed, 191 insertions(+), 10 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 391a0c3..5c6cd4b 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -8,6 +8,10 @@ is used to store the configuration for that repository, and
 fallback values for the `.git/config` file. The file `/etc/gitconfig`
 can be used to store a system-wide default configuration.
 
+Linked worktrees (see linkgit:git-worktree[1]) also have a
+worktree-specific file "config.worktree". See
+linkgit:gitrepository-layout[5] for more information.
+
 The configuration variables are used by both the Git plumbing
 and the porcelains. The variables are divided into sections, wherein
 the fully qualified variable name of the variable itself is the last
diff --git a/Documentation/gitrepository-layout.txt b/Documentation/gitrepository-layout.txt
index 577ee84..62f7e33 100644
--- a/Documentation/gitrepository-layout.txt
+++ b/Documentation/gitrepository-layout.txt
@@ -212,6 +212,12 @@ info/sparse-checkout::
 	This file stores sparse checkout patterns.
 	See also: linkgit:git-read-tree[1].
 
+info/config.worktree:
+	This file stores the configuration variable pattern list where
+	$GIT_DIR/config.worktree is used as storage instead of
+	$GIT_DIR/config. The syntax is the same as .gitignore except
+	that '.' is considered the separator instead of '/'.
+
 remotes::
 	Stores shorthands for URL and default refnames for use
 	when interacting with remote repositories via 'git fetch',
@@ -276,6 +282,12 @@ worktrees/<id>/link::
 	file. It is used to detect if the linked repository is
 	manually removed.
 
+worktrees/<id>/config.worktree::
+	This file contains worktree-specific configuration
+	variables. The list of variables is controlled by
+	$GIT_COMMON_DIR/info/config.worktree. The same variables in
+	$GIT_COMMON_DIR/config are ignored.
+
 SEE ALSO
 --------
 linkgit:git-init[1],
diff --git a/builtin/config.c b/builtin/config.c
index adc7727..2b4d56e 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -533,6 +533,15 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 		default:
 			usage_with_options(builtin_config_usage, builtin_config_options);
 		}
+
+	/*
+	 * For set operations, --local could be either config or
+	 * config.worktree. Let config.c determine the path based on
+	 * config keys.
+	 */
+	if (use_local_config && actions != ACTION_LIST)
+		given_config_source.file = NULL;
+
 	if (omit_values &&
 	    !(actions == ACTION_LIST || actions == ACTION_GET_REGEXP)) {
 		error("--name-only is only applicable to --list or --get-regexp");
diff --git a/cache.h b/cache.h
index 3ba0b8f..27bc3bc 100644
--- a/cache.h
+++ b/cache.h
@@ -1468,7 +1468,7 @@ extern void git_config(config_fn_t fn, void *);
 extern int git_config_with_options(config_fn_t fn, void *,
 				   struct git_config_source *config_source,
 				   int respect_includes);
-extern int git_config_early(config_fn_t fn, void *, const char *repo_config);
+extern int git_config_early(config_fn_t fn, void *, const char *repo_config, const char *worktree_config);
 extern int git_parse_ulong(const char *, unsigned long *);
 extern int git_parse_maybe_bool(const char *);
 extern int git_config_int(const char *, const char *);
diff --git a/config.c b/config.c
index 248a21a..75c45e1 100644
--- a/config.c
+++ b/config.c
@@ -13,6 +13,7 @@
 #include "hashmap.h"
 #include "string-list.h"
 #include "utf8.h"
+#include "dir.h"
 
 struct config_source {
 	struct config_source *prev;
@@ -38,6 +39,7 @@ struct config_source {
 };
 
 static struct config_source *cf;
+static struct exclude_list config_local;
 
 static int zlib_compression_seen;
 
@@ -89,6 +91,73 @@ static long config_buf_ftell(struct config_source *conf)
 	return conf->u.buf.pos;
 }
 
+static void load_info_config_worktree(void)
+{
+	struct exclude_list *el = &config_local;
+	struct strbuf sb = STRBUF_INIT;
+	int i, lineno = 1;
+	char *buf, *entry;
+	size_t size;
+
+	clear_exclude_list(el);
+
+	if (strbuf_read_file(&sb,
+			     git_path("info/config.worktree"),
+			     128) <= 0) {
+		strbuf_release(&sb);
+		return;
+	}
+	strbuf_addch(&sb, '\n');
+	el->filebuf = buf = strbuf_detach(&sb, &size);
+
+	for (i = 0; i < size; i++)
+		if (buf[i] == '.')
+			buf[i] = '/';
+		else
+			buf[i] = tolower(buf[i]);
+
+	entry = buf;
+	for (i = 0; i < size; i++) {
+		if (buf[i] == '\n') {
+			if (entry != buf + i && entry[0] != '#') {
+				buf[i - (i && buf[i-1] == '\r')] = 0;
+				trim_trailing_spaces(entry);
+				add_exclude(entry, "", 0, el, lineno);
+			}
+			lineno++;
+			entry = buf + i + 1;
+		}
+	}
+
+	/*
+	 * avoid base name matching because it may confusion in
+	 * non-directory context.
+	 */
+	for (i = 0; i < el->nr; i++)
+		el->excludes[i]->flags &= ~EXC_FLAG_NODIR;
+}
+
+static int is_config_local(const char *key_)
+{
+	static struct strbuf key = STRBUF_INIT;
+	int i, dtype;
+
+	if (!config_local.nr)
+		return 0;
+
+	strbuf_reset(&key);
+	strbuf_addstr(&key, key_);
+	for (i = 0; i < key.len; i++) {
+		if (key.buf[i] == '.')
+			key.buf[i] = '/';
+		else
+			key.buf[i] = tolower(key.buf[i]);
+	}
+	dtype = DT_REG;
+	return is_excluded_from_list(key.buf, key.len, "", &dtype,
+				     &config_local) > 0;
+}
+
 #define MAX_INCLUDE_DEPTH 10
 static const char include_depth_advice[] =
 "exceeded maximum include depth (%d) while including\n"
@@ -1184,7 +1253,29 @@ int git_config_system(void)
 	return !git_env_bool("GIT_CONFIG_NOSYSTEM", 0);
 }
 
-int git_config_early(config_fn_t fn, void *data, const char *repo_config)
+static int config_worktree_filter_in(const char *var,
+				     const char *value, void *data)
+{
+	struct config_include_data *inc = data;
+
+	if (!is_config_local(var))
+		return error("%s in config.worktree is ignored", var);
+	return inc->fn(var, value, inc->data);
+}
+
+static int config_worktree_filter_out(const char *var,
+				      const char *value, void *data)
+{
+	struct config_include_data *inc = data;
+
+	if (is_config_local(var))
+		return 0;	/* these are for main worktree only */
+
+	return inc->fn(var, value, inc->data);
+}
+
+int git_config_early(config_fn_t fn, void *data, const char *repo_config,
+		     const char *worktree_config)
 {
 	int ret = 0, found = 0;
 	char *xdg_config = xdg_config_home("config");
@@ -1206,7 +1297,25 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)
 		found += 1;
 	}
 
-	if (repo_config && !access_or_die(repo_config, R_OK, 0)) {
+	if (worktree_config) {
+		struct config_include_data inc = CONFIG_INCLUDE_INIT;
+
+		load_info_config_worktree();
+
+		inc.fn = fn;
+		inc.data = data;
+		if (!access_or_die(worktree_config, R_OK, 0)) {
+			ret += git_config_from_file(config_worktree_filter_in,
+						    worktree_config, &inc);
+			found += 1;
+		}
+
+		if (repo_config && !access_or_die(repo_config, R_OK, 0)) {
+			ret += git_config_from_file(config_worktree_filter_out,
+						    repo_config, &inc);
+			found += 1;
+		}
+	} else if (repo_config && !access_or_die(repo_config, R_OK, 0)) {
 		ret += git_config_from_file(fn, repo_config, data);
 		found += 1;
 	}
@@ -1232,6 +1341,7 @@ int git_config_with_options(config_fn_t fn, void *data,
 			    int respect_includes)
 {
 	char *repo_config = NULL;
+	char *worktree_config = NULL;
 	int ret;
 	struct config_include_data inc = CONFIG_INCLUDE_INIT;
 
@@ -1254,9 +1364,11 @@ int git_config_with_options(config_fn_t fn, void *data,
 		return git_config_from_blob_ref(fn, config_source->blob, data);
 
 	repo_config = git_pathdup("config");
-	ret = git_config_early(fn, data, repo_config);
-	if (repo_config)
-		free(repo_config);
+	if (git_common_dir_env)
+		worktree_config = git_pathdup("config.worktree");
+	ret = git_config_early(fn, data, repo_config, worktree_config);
+	free(repo_config);
+	free(worktree_config);
 	return ret;
 }
 
@@ -1925,6 +2037,24 @@ int git_config_key_is_valid(const char *key)
 	return !git_config_parse_key_1(key, NULL, NULL, 1);
 }
 
+static const char *get_config_filename(const char *config_filename,
+				       const char *key,
+				       char **filename_buf)
+{
+	if (config_filename)
+		return config_filename;
+	if (!git_common_dir_env) {
+		config_filename = *filename_buf = git_pathdup("config");
+		return config_filename;
+	}
+	load_info_config_worktree();
+	if (!is_config_local(key))
+		config_filename = *filename_buf = git_pathdup("config");
+	else
+		config_filename = *filename_buf = git_pathdup("config.worktree");
+	return config_filename;
+}
+
 /*
  * If value==NULL, unset in (remove from) config,
  * if value_regex!=NULL, disregard key/value pairs where value does not match.
@@ -1968,8 +2098,7 @@ 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");
+	config_filename = get_config_filename(config_filename, key, &filename_buf);
 
 	/*
 	 * The lock serves a purpose in addition to locking: the new
diff --git a/dir.c b/dir.c
index b8b4576..9522b89 100644
--- a/dir.c
+++ b/dir.c
@@ -567,7 +567,7 @@ void clear_exclude_list(struct exclude_list *el)
 	memset(el, 0, sizeof(*el));
 }
 
-static void trim_trailing_spaces(char *buf)
+void trim_trailing_spaces(char *buf)
 {
 	char *p, *last_space = NULL;
 
diff --git a/dir.h b/dir.h
index 7b5855d..52ded83 100644
--- a/dir.h
+++ b/dir.h
@@ -248,6 +248,7 @@ extern void clear_exclude_list(struct exclude_list *el);
 extern void clear_directory(struct dir_struct *dir);
 extern int file_exists(const char *);
 
+extern void trim_trailing_spaces(char *buf);
 extern int is_inside_dir(const char *dir);
 extern int dir_inside_of(const char *subdir, const char *dir);
 
diff --git a/setup.c b/setup.c
index d343725..0047d40 100644
--- a/setup.c
+++ b/setup.c
@@ -404,7 +404,7 @@ static int check_repository_format_gently(const char *gitdir, int *nongit_ok)
 	 * Use a gentler version of git_config() to check if this repo
 	 * is a good one.
 	 */
-	git_config_early(fn, NULL, repo_config);
+	git_config_early(fn, NULL, repo_config, NULL);
 	if (GIT_REPO_VERSION_READ < repository_format_version) {
 		if (!nongit_ok)
 			die ("Expected git repo version <= %d, found %d",
diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh
index 3694174..e8d8da4 100755
--- a/t/t2025-worktree-add.sh
+++ b/t/t2025-worktree-add.sh
@@ -198,4 +198,30 @@ test_expect_success 'local clone from linked checkout' '
 	( cd here-clone && git fsck )
 '
 
+test_expect_success 'setting worktree.foo goes to config.worktree' '
+	echo worKtree.Foo >> .git/info/config.worktree &&
+	git worktree add wt.foo HEAD &&
+	git config woRKtree.FOO barrrr &&
+	git --git-dir=wt.foo/.git config woRKtree.FOO bar &&
+	cat >expect <<\EOF &&
+[woRKtree]
+	FOO = bar
+EOF
+	test_cmp expect .git/worktrees/wt.foo/config.worktree &&
+	git --git-dir=wt.foo/.git config woRktree.foo >actual2 &&
+	echo bar >expect2 &&
+	test_cmp expect2 actual2 &&
+	test_path_is_missing .git/config.worktree &&
+	git config WORKTREE.FOO >actual3 &&
+	echo barrrr >expect3 &&
+	test_cmp expect3 actual3
+'
+
+test_expect_success 'shared config still goes to config' '
+	git config random.key randomValue &&
+	git --git-dir=wt.foo/.git config random.key >actual &&
+	echo randomValue >expect &&
+	test_cmp expect actual
+'
+
 test_done
-- 
2.2.0.513.g477eb31

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH 3/5] setup.c: remove special case of core.worktree and core.bare
  2015-12-02 19:13 [PATCH 0/5] Split .git/config in multiple worktree setup Nguyễn Thái Ngọc Duy
  2015-12-02 19:13 ` [PATCH 1/5] dir.c: clean the entire struct in clear_exclude_list() Nguyễn Thái Ngọc Duy
  2015-12-02 19:13 ` [PATCH 2/5] config.c: move worktree-specific variables to .git/worktrees/ Nguyễn Thái Ngọc Duy
@ 2015-12-02 19:13 ` Nguyễn Thái Ngọc Duy
  2015-12-02 19:13 ` [PATCH 4/5] worktree: make core.sparseCheckout and core.ignoreStat per-worktree Nguyễn Thái Ngọc Duy
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 53+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-12-02 19:13 UTC (permalink / raw)
  To: git
  Cc: Michael J Gruber, Max Kirillov, Jens Lehmann,
	Nguyễn Thái Ngọc Duy

core.worktree and core.bare, which are treated specially in 31e26eb [1],
are now moved to info/core.worktree and the special treatment
reverted. The test "$GIT_DIR/common overrides core.worktree" in t1501
from 31e26eb verifies that the behavior is still correct after this
change.

A note about core.bare. On the surface it does not make sense for
core.bare to be worktree specific. It's made so in order to "grow" new
worktrees from a bare repo. In these new linked worktrees, core.bare
will be hidden away and worktree-related commands won't complain about
bare repository.

[1] 31e26eb (setup.c: support multi-checkout repo setup - 2014-11-30)

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/config.txt |  4 ++++
 config.c                 |  8 +++++++
 setup.c                  | 62 ++++++++++++++++++++++--------------------------
 3 files changed, 40 insertions(+), 34 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 5c6cd4b..09a8b57 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -454,6 +454,8 @@ linkgit:git-init[1] when the repository was created.  By default a
 repository that ends in "/.git" is assumed to be not bare (bare =
 false), while all other repositories are assumed to be bare (bare
 = true).
++
+This variable is per-worktree in multiple working tree setup.
 
 core.worktree::
 	Set the path to the root of the working tree.
@@ -478,6 +480,8 @@ still use "/different/path" as the root of the work tree and can cause
 confusion unless you know what you are doing (e.g. you are creating a
 read-only snapshot of the same index to a location different from the
 repository's usual working tree).
++
+This variable is per-worktree in multiple working tree setup.
 
 core.logAllRefUpdates::
 	Enable the reflog. Updates to a ref <ref> is logged to the file
diff --git a/config.c b/config.c
index 75c45e1..54a6219 100644
--- a/config.c
+++ b/config.c
@@ -91,6 +91,11 @@ static long config_buf_ftell(struct config_source *conf)
 	return conf->u.buf.pos;
 }
 
+static const char* default_config_worktree[] = {
+	"core/bare",
+	"core/worktree"
+};
+
 static void load_info_config_worktree(void)
 {
 	struct exclude_list *el = &config_local;
@@ -101,6 +106,9 @@ static void load_info_config_worktree(void)
 
 	clear_exclude_list(el);
 
+	for (i = 0; i < ARRAY_SIZE(default_config_worktree); i++)
+		add_exclude(default_config_worktree[i], "", 0, el, 0);
+
 	if (strbuf_read_file(&sb,
 			     git_path("info/config.worktree"),
 			     128) <= 0) {
diff --git a/setup.c b/setup.c
index 0047d40..c088d45 100644
--- a/setup.c
+++ b/setup.c
@@ -355,43 +355,20 @@ void setup_work_tree(void)
 	initialized = 1;
 }
 
-static int check_repo_format(const char *var, const char *value, void *cb)
-{
-	const char *ext;
-
-	if (strcmp(var, "core.repositoryformatversion") == 0)
-		repository_format_version = git_config_int(var, value);
-	else if (strcmp(var, "core.sharedrepository") == 0)
-		shared_repository = git_config_perm(var, value);
-	else if (skip_prefix(var, "extensions.", &ext)) {
-		/*
-		 * record any known extensions here; otherwise,
-		 * we fall through to recording it as unknown, and
-		 * check_repository_format will complain
-		 */
-		if (!strcmp(ext, "noop"))
-			;
-		else if (!strcmp(ext, "preciousobjects"))
-			repository_format_precious_objects = git_config_bool(var, value);
-		else
-			string_list_append(&unknown_extensions, ext);
-	}
-	return 0;
-}
-
 static int check_repository_format_gently(const char *gitdir, int *nongit_ok)
 {
 	struct strbuf sb = STRBUF_INIT;
+	struct strbuf sb2 = STRBUF_INIT;
 	const char *repo_config;
-	config_fn_t fn;
+	const char *worktree_config = NULL;
 	int ret = 0;
 
 	string_list_clear(&unknown_extensions, 0);
 
-	if (get_common_dir(&sb, gitdir))
-		fn = check_repo_format;
-	else
-		fn = check_repository_format_version;
+	if (get_common_dir(&sb, gitdir)) {
+		strbuf_addf(&sb2, "%s/config.worktree", gitdir);
+		worktree_config = sb2.buf;
+	}
 	strbuf_addstr(&sb, "/config");
 	repo_config = sb.buf;
 
@@ -404,7 +381,8 @@ static int check_repository_format_gently(const char *gitdir, int *nongit_ok)
 	 * Use a gentler version of git_config() to check if this repo
 	 * is a good one.
 	 */
-	git_config_early(fn, NULL, repo_config, NULL);
+	git_config_early(check_repository_format_version, NULL,
+			 repo_config, worktree_config);
 	if (GIT_REPO_VERSION_READ < repository_format_version) {
 		if (!nongit_ok)
 			die ("Expected git repo version <= %d, found %d",
@@ -431,6 +409,7 @@ static int check_repository_format_gently(const char *gitdir, int *nongit_ok)
 	}
 
 	strbuf_release(&sb);
+	strbuf_release(&sb2);
 	return ret;
 }
 
@@ -963,10 +942,25 @@ int git_config_perm(const char *var, const char *value)
 
 int check_repository_format_version(const char *var, const char *value, void *cb)
 {
-	int ret = check_repo_format(var, value, cb);
-	if (ret)
-		return ret;
-	if (strcmp(var, "core.bare") == 0) {
+	const char *ext;
+
+	if (strcmp(var, "core.repositoryformatversion") == 0)
+		repository_format_version = git_config_int(var, value);
+	else if (strcmp(var, "core.sharedrepository") == 0)
+		shared_repository = git_config_perm(var, value);
+	else if (skip_prefix(var, "extensions.", &ext)) {
+		/*
+		 * record any known extensions here; otherwise,
+		 * we fall through to recording it as unknown, and
+		 * check_repository_format will complain
+		 */
+		if (!strcmp(ext, "noop"))
+			;
+		else if (!strcmp(ext, "preciousobjects"))
+			repository_format_precious_objects = git_config_bool(var, value);
+		else
+			string_list_append(&unknown_extensions, ext);
+	} else if (strcmp(var, "core.bare") == 0) {
 		is_bare_repository_cfg = git_config_bool(var, value);
 		if (is_bare_repository_cfg == 1)
 			inside_work_tree = -1;
-- 
2.2.0.513.g477eb31

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH 4/5] worktree: make core.sparseCheckout and core.ignoreStat per-worktree
  2015-12-02 19:13 [PATCH 0/5] Split .git/config in multiple worktree setup Nguyễn Thái Ngọc Duy
                   ` (2 preceding siblings ...)
  2015-12-02 19:13 ` [PATCH 3/5] setup.c: remove special case of core.worktree and core.bare Nguyễn Thái Ngọc Duy
@ 2015-12-02 19:13 ` Nguyễn Thái Ngọc Duy
  2015-12-02 19:13 ` [PATCH 5/5] git-worktree.txt: mention about the config file split Nguyễn Thái Ngọc Duy
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 53+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-12-02 19:13 UTC (permalink / raw)
  To: git
  Cc: Michael J Gruber, Max Kirillov, Jens Lehmann,
	Nguyễn Thái Ngọc Duy

The first one must be per-worktree because info/sparse-checkout
already is. The second one shares the same nature and should also be
per-worktree.

Note, because info/config.worktree uses .gitignore syntax, you can
negate a default pattern and revert it back to per-repo..

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/config.txt | 5 ++++-
 config.c                 | 2 ++
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 09a8b57..aff1431 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -435,7 +435,8 @@ Git will not normally detect changes to those files.
 This is useful on systems where lstat() calls are very slow, such as
 CIFS/Microsoft Windows.
 +
-False by default.
+False by default. This variable is per-worktree in multiple working
+tree setup.
 
 core.preferSymlinkRefs::
 	Instead of the default "symref" format for HEAD
@@ -736,6 +737,8 @@ the 'GIT_NOTES_REF' environment variable.  See linkgit:git-notes[1].
 core.sparseCheckout::
 	Enable "sparse checkout" feature. See section "Sparse checkout" in
 	linkgit:git-read-tree[1] for more information.
++
+This variable is per-worktree in multiple working tree setup.
 
 core.abbrev::
 	Set the length object names are abbreviated to.  If unspecified,
diff --git a/config.c b/config.c
index 54a6219..fdf38da 100644
--- a/config.c
+++ b/config.c
@@ -93,6 +93,8 @@ static long config_buf_ftell(struct config_source *conf)
 
 static const char* default_config_worktree[] = {
 	"core/bare",
+	"core/ignorestat",
+	"core/sparsecheckout",
 	"core/worktree"
 };
 
-- 
2.2.0.513.g477eb31

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH 5/5] git-worktree.txt: mention about the config file split
  2015-12-02 19:13 [PATCH 0/5] Split .git/config in multiple worktree setup Nguyễn Thái Ngọc Duy
                   ` (3 preceding siblings ...)
  2015-12-02 19:13 ` [PATCH 4/5] worktree: make core.sparseCheckout and core.ignoreStat per-worktree Nguyễn Thái Ngọc Duy
@ 2015-12-02 19:13 ` Nguyễn Thái Ngọc Duy
  2015-12-06  8:02   ` Eric Sunshine
  2015-12-03  6:15 ` [PATCH 0/5] Split .git/config in multiple worktree setup Max Kirillov
  2015-12-27  3:14 ` [PATCH v2 0/6] " Nguyễn Thái Ngọc Duy
  6 siblings, 1 reply; 53+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-12-02 19:13 UTC (permalink / raw)
  To: git
  Cc: Michael J Gruber, Max Kirillov, Jens Lehmann,
	Nguyễn Thái Ngọc Duy

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/git-worktree.txt | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 5b9ad04..299e4f2 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -147,6 +147,19 @@ to `/path/main/.git/worktrees/test-next` then a file named
 `test-next` entry from being pruned.  See
 linkgit:gitrepository-layout[5] for details.
 
+Similar to the file system split in ".git", the repository config file
+is also split. Certain variables, for example core.worktree, are
+per-worktree while the majority of variables are still shared (see
+linkgit:git-config[1] for details). Shared variables and per-working
+tree ones that belong to the main working tree are in .git/config.
+Per-working tree variables for working tree X are in
+$GIT_COMMON_DIR/worktrees/X/config.worktree. Even though per-working
+tree variables for the main working tree are in the default config
+place, they are invisible from all linked working trees.  You can make
+more config variables per-working tree by adding them in
+.git/info/config.worktree (see linkgit:gitrepository-layout[5] for
+details).
+
 LIST OUTPUT FORMAT
 ------------------
 The worktree list command has two output formats.  The default format shows the
-- 
2.2.0.513.g477eb31

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* Re: [PATCH 0/5] Split .git/config in multiple worktree setup
  2015-12-02 19:13 [PATCH 0/5] Split .git/config in multiple worktree setup Nguyễn Thái Ngọc Duy
                   ` (4 preceding siblings ...)
  2015-12-02 19:13 ` [PATCH 5/5] git-worktree.txt: mention about the config file split Nguyễn Thái Ngọc Duy
@ 2015-12-03  6:15 ` Max Kirillov
  2015-12-03  8:07   ` Duy Nguyen
  2015-12-27  3:14 ` [PATCH v2 0/6] " Nguyễn Thái Ngọc Duy
  6 siblings, 1 reply; 53+ messages in thread
From: Max Kirillov @ 2015-12-03  6:15 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy
  Cc: git, Michael J Gruber, Max Kirillov, Jens Lehmann

On Wed, Dec 02, 2015 at 08:13:41PM +0100, Nguyễn Thái Ngọc Duy wrote:
> Let's restart this. From the last discussion [1], we need to make
> core.worktree per-worktree for submodules to work. We also need
> core.sparseCheckout per-worktree.

Thank you. It would be nice to have it, so that features
like submodules work fully.

Now there are extensions support, would it make sense to
mark repositories which use per-worktree config with an
extension? It could clearly separate 2.5-style
multi-worktree repositories (which might exist already
around) from the new format. The extension could be set by
'worktree add' while creating first worktree, for example.

> This series adds a pattern list, with .gitignore syntax mostly, that
> split config var set into two sets, the per-worktree set will be
> stored in .git/worktrees/*/config.worktree instead. The pattern list
> consists of default patterns, built in git binary, and user ones in
> .git/info/config.worktree.

Using builtin defaults might be confusing for users -
editing the info/config.worktree they must keep in mind the
list of defaults (which they seem to don't know). Also, if
anybody wants to extend the default list (like myself, for
submodules), should they edit the info/config.worktree in
provided template of extend the builtin list? What was wrong
with the default in template?

-- 
Max

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 0/5] Split .git/config in multiple worktree setup
  2015-12-03  6:15 ` [PATCH 0/5] Split .git/config in multiple worktree setup Max Kirillov
@ 2015-12-03  8:07   ` Duy Nguyen
  2015-12-03 19:52     ` Junio C Hamano
  2015-12-03 20:53     ` Max Kirillov
  0 siblings, 2 replies; 53+ messages in thread
From: Duy Nguyen @ 2015-12-03  8:07 UTC (permalink / raw)
  To: Max Kirillov; +Cc: Git Mailing List, Michael J Gruber, Jens Lehmann

On Thu, Dec 3, 2015 at 7:15 AM, Max Kirillov <max@max630.net> wrote:
> On Wed, Dec 02, 2015 at 08:13:41PM +0100, Nguyễn Thái Ngọc Duy wrote:
>> Let's restart this. From the last discussion [1], we need to make
>> core.worktree per-worktree for submodules to work. We also need
>> core.sparseCheckout per-worktree.
>
> Thank you. It would be nice to have it, so that features
> like submodules work fully.
>
> Now there are extensions support, would it make sense to
> mark repositories which use per-worktree config with an
> extension? It could clearly separate 2.5-style
> multi-worktree repositories (which might exist already
> around) from the new format. The extension could be set by
> 'worktree add' while creating first worktree, for example.

Hmm.. I didn't think of this. If we add this as a repo extension, then
we could use git/config for shared vars only, main worktree specific
vars can stay in .git/config.worktree while linked worktree's in
.git/worktrees/*/config.worktree. Neat.

>> This series adds a pattern list, with .gitignore syntax mostly, that
>> split config var set into two sets, the per-worktree set will be
>> stored in .git/worktrees/*/config.worktree instead. The pattern list
>> consists of default patterns, built in git binary, and user ones in
>> .git/info/config.worktree.
>
> Using builtin defaults might be confusing for users -
> editing the info/config.worktree they must keep in mind the
> list of defaults (which they seem to don't know).

All per-worktree variables are marked so in config.txt

> Also, if
> anybody wants to extend the default list (like myself, for
> submodules), should they edit the info/config.worktree in
> provided template of extend the builtin list? What was wrong
> with the default in template?

If a variable _must_ be per-worktree or something will break, then it
should belong to the builtin list (so the user is less likely to mess
with it). If it may or may not be per-worktree, depending on one's
preference, then we can keep this in info/config.worktree. I made the
builtin list for that reason (user not breaking stuff accidentally)
and another one, which is upgrade issue. Suppose you introduce a new
per-worktree variable in the new git version. If it's in the builtin
list, we don't have to update every repo's info/config,worktree.
-- 
Duy

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 0/5] Split .git/config in multiple worktree setup
  2015-12-03  8:07   ` Duy Nguyen
@ 2015-12-03 19:52     ` Junio C Hamano
  2015-12-03 21:00       ` Max Kirillov
  2015-12-03 20:53     ` Max Kirillov
  1 sibling, 1 reply; 53+ messages in thread
From: Junio C Hamano @ 2015-12-03 19:52 UTC (permalink / raw)
  To: Duy Nguyen; +Cc: Max Kirillov, Git Mailing List, Michael J Gruber, Jens Lehmann

Duy Nguyen <pclouds@gmail.com> writes:

> If a variable _must_ be per-worktree or something will break, then it
> should belong to the builtin list (so the user is less likely to mess
> with it). If it may or may not be per-worktree, depending on one's
> preference, then we can keep this in info/config.worktree. I made the
> builtin list for that reason (user not breaking stuff accidentally)
> and another one, which is upgrade issue. Suppose you introduce a new
> per-worktree variable in the new git version. If it's in the builtin
> list, we don't have to update every repo's info/config,worktree.

I agree with your reasoning to have built-in set of files that are
per-worktree. I actually prefer *not* to have any configurability
to avoid confusion between users.

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 0/5] Split .git/config in multiple worktree setup
  2015-12-03  8:07   ` Duy Nguyen
  2015-12-03 19:52     ` Junio C Hamano
@ 2015-12-03 20:53     ` Max Kirillov
  2015-12-04 15:57       ` Duy Nguyen
  1 sibling, 1 reply; 53+ messages in thread
From: Max Kirillov @ 2015-12-03 20:53 UTC (permalink / raw)
  To: Duy Nguyen; +Cc: Max Kirillov, Git Mailing List, Michael J Gruber, Jens Lehmann

On Thu, Dec 03, 2015 at 09:07:07AM +0100, Duy Nguyen wrote:
> On Thu, Dec 3, 2015 at 7:15 AM, Max Kirillov <max@max630.net> wrote:
>> Using builtin defaults might be confusing for users -
>> editing the info/config.worktree they must keep in mind the
>> list of defaults (which they seem to don't know).
> 
> All per-worktree variables are marked so in config.txt

If I were user I would like the list to be more explicit.

>> Also, if
>> anybody wants to extend the default list (like myself, for
>> submodules), should they edit the info/config.worktree in
>> provided template of extend the builtin list? What was wrong
>> with the default in template?
> 
> Suppose you introduce a new
> per-worktree variable in the new git version. If it's in the builtin
> list, we don't have to update every repo's info/config,worktree.

But how do you see it? Let's, for example, git-N consider
some variable as per-repository, and user does have it their
.git/config. Then git-N+1 considers it as per-worktree. How
does it find the variable while opening some existing
worktree? Then, if user sets the variable in some worktree
using git-N+1, git-N will no longer be able to see the
correct variable value. Does this mean that any change in
builtin list should cause repository incompatibility?

With defaults written in the info/config.worktree file the
issue do not exist at all: you can open repository created
with a git version with some default list of per-worktree
veriables with a version with other default list. It all
would work.

If user decides to change the actual list of default
per-worktree variable it is always can be done explcitly,
with some provided convenience command for example.

-- 
Max

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 0/5] Split .git/config in multiple worktree setup
  2015-12-03 19:52     ` Junio C Hamano
@ 2015-12-03 21:00       ` Max Kirillov
  0 siblings, 0 replies; 53+ messages in thread
From: Max Kirillov @ 2015-12-03 21:00 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Duy Nguyen, Max Kirillov, Git Mailing List, Michael J Gruber,
	Jens Lehmann

On Thu, Dec 03, 2015 at 11:52:43AM -0800, Junio C Hamano wrote:
> I actually prefer *not* to have any configurability
> to avoid confusion between users.

This could be an approach. But because of upgrade issues
which I described in the other response it looks like this
decision is not easy to change in a later version. So the
list should be decided here and now for each existing
variable, and later for any new one, and preferable never
changed after that.

-- 
Max

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 0/5] Split .git/config in multiple worktree setup
  2015-12-03 20:53     ` Max Kirillov
@ 2015-12-04 15:57       ` Duy Nguyen
  0 siblings, 0 replies; 53+ messages in thread
From: Duy Nguyen @ 2015-12-04 15:57 UTC (permalink / raw)
  To: Max Kirillov, Junio C Hamano
  Cc: Git Mailing List, Michael J Gruber, Jens Lehmann

On Thu, Dec 3, 2015 at 9:53 PM, Max Kirillov <max@max630.net> wrote:
> On Thu, Dec 03, 2015 at 09:07:07AM +0100, Duy Nguyen wrote:
>> On Thu, Dec 3, 2015 at 7:15 AM, Max Kirillov <max@max630.net> wrote:
>>> Using builtin defaults might be confusing for users -
>>> editing the info/config.worktree they must keep in mind the
>>> list of defaults (which they seem to don't know).
>>
>> All per-worktree variables are marked so in config.txt
>
> If I were user I would like the list to be more explicit.

I wouldn't. I mean, I have more than a dozen of git repos lying
around, some I don't even remember where. Should I check git release
notes at every upgrade then fix up _all_ of my repos? That's something
I rather not do.

>>> Also, if
>>> anybody wants to extend the default list (like myself, for
>>> submodules), should they edit the info/config.worktree in
>>> provided template of extend the builtin list? What was wrong
>>> with the default in template?
>>
>> Suppose you introduce a new
>> per-worktree variable in the new git version. If it's in the builtin
>> list, we don't have to update every repo's info/config,worktree.
>
> But how do you see it? Let's, for example, git-N consider
> some variable as per-repository, and user does have it their
> .git/config. Then git-N+1 considers it as per-worktree. How
> does it find the variable while opening some existing
> worktree? Then, if user sets the variable in some worktree
> using git-N+1, git-N will no longer be able to see the
> correct variable value. Does this mean that any change in
> builtin list should cause repository incompatibility?

Behavior differences between git versions have been alway will always
be the problem. Yes providing some forward compatibility (by storing
some logic outside the binary in this case) helps, but I don't think
it eliminates it. If incompatibilities may lead to a big problem, then
we can always make the new behavior an "repo extension" to stop older
binaries from accessing the touched repos.

Most of the time there's only one git version being used. So it should
not be a big problem. But yes, if a repo is shared over network, then
multiple git versions accessing the same repo can happen.

On Thu, Dec 3, 2015 at 8:52 PM, Junio C Hamano <gitster@pobox.com> wrote:
> I agree with your reasoning to have built-in set of files that are
> per-worktree. I actually prefer *not* to have any configurability
> to avoid confusion between users.

There are a set of variables where whether they are shared or
per-worktree is pretty much preference. For example, core.ignoreCase.
What if I put one worktree on that case-insensitive file system? This
gives the user some flexibility in managing those variables. _But_
they can also manage another way with include.path (or a new variant
that is worktree-aware), with a bit of work.

So killing info/core.worktree is not a bad idea. Even better, we can
avoid pulling exclude machinery in. But yeah, need to sort out the
upgrade issue Max mentioned first.
-- 
Duy

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 2/5] config.c: move worktree-specific variables to .git/worktrees/...
  2015-12-02 19:13 ` [PATCH 2/5] config.c: move worktree-specific variables to .git/worktrees/ Nguyễn Thái Ngọc Duy
@ 2015-12-06  7:47   ` Eric Sunshine
  2015-12-06 10:22     ` Duy Nguyen
  0 siblings, 1 reply; 53+ messages in thread
From: Eric Sunshine @ 2015-12-06  7:47 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy
  Cc: Git List, Michael J Gruber, Max Kirillov, Jens Lehmann

On Wed, Dec 2, 2015 at 2:13 PM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:
> .git/info/config.worktree is a pattern list that splits .git/config in
> to sets: the worktree set matches the patterns, the commmon set does
> not.
>
> In normal worktrees, both sets are stored in .git/config. The
> config.worktree has no effect. Nothing is changed.
>
> In linked worktrees, the common and worktree sets are read from and
> saved to .git/config and .git/config.worktree respectively. Config
> keys in .git/config that belong to the worktree set is ignored. Those
> are for the main worktree only. Similarly, keys not matching the
> patterns come from .git/config, duplicate keys from
> .git/config.worktree are ignored.
>
> The effect is similar to the $GIT_DIR/$GIT_COMMON_DIR split, we can
> define that some vars can be shared and some cannot. And as a result
> of the $GIT_DIR/$GIT_COMMON_DIR split, config.worktree is actually
> found at .git/worktrees/<id>/config.worktree.

Why does this worktree-specific file need/have a .worktree suffix?

> Throwing the exclude mechanism into this means reading config files
> will be slower. But unless somebody reads thousands of keys, it should
> not be noticable. The nice thing is we don't have to introduce yet
> another pattern syntax.
>
> In future, we might want to have a shared config file to contain
> common worktree-specific settings, so that we have some good defaults,
> but still allow customization. Or we could twist the above logic a
> bit: for linked worktrees, read _all_ variables in config.worktree
> regardless of the patterns. But let's wait and see..
>
> Helped-by: Max Kirillov <max@max630.net>
> Helped-by: Jens Lehmann <Jens.Lehmann@web.de>
> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
> ---
> diff --git a/config.c b/config.c
> @@ -89,6 +91,73 @@ static long config_buf_ftell(struct config_source *conf)
> +static void load_info_config_worktree(void)
> +{
> +       struct exclude_list *el = &config_local;
> +       struct strbuf sb = STRBUF_INIT;
> +       int i, lineno = 1;
> +       char *buf, *entry;
> +       size_t size;
> +
> +       clear_exclude_list(el);
> +
> +       if (strbuf_read_file(&sb,
> +                            git_path("info/config.worktree"),
> +                            128) <= 0) {
> +               strbuf_release(&sb);
> +               return;
> +       }
> +       strbuf_addch(&sb, '\n');
> +       el->filebuf = buf = strbuf_detach(&sb, &size);
> +
> +       for (i = 0; i < size; i++)
> +               if (buf[i] == '.')
> +                       buf[i] = '/';
> +               else
> +                       buf[i] = tolower(buf[i]);
> +
> +       entry = buf;
> +       for (i = 0; i < size; i++) {
> +               if (buf[i] == '\n') {
> +                       if (entry != buf + i && entry[0] != '#') {
> +                               buf[i - (i && buf[i-1] == '\r')] = 0;
> +                               trim_trailing_spaces(entry);
> +                               add_exclude(entry, "", 0, el, lineno);
> +                       }
> +                       lineno++;
> +                       entry = buf + i + 1;
> +               }
> +       }
> +
> +       /*
> +        * avoid base name matching because it may confusion in

s/may/may cause/

> +        * non-directory context.
> +        */
> +       for (i = 0; i < el->nr; i++)
> +               el->excludes[i]->flags &= ~EXC_FLAG_NODIR;
> +}
> +
> +static int is_config_local(const char *key_)
> +{
> +       static struct strbuf key = STRBUF_INIT;
> +       int i, dtype;
> +
> +       if (!config_local.nr)
> +               return 0;
> +
> +       strbuf_reset(&key);
> +       strbuf_addstr(&key, key_);

Why does 'key' need to be static considering that it is overwritten on
each call and its value is never accessed after the function returns?

> +       for (i = 0; i < key.len; i++) {
> +               if (key.buf[i] == '.')
> +                       key.buf[i] = '/';
> +               else
> +                       key.buf[i] = tolower(key.buf[i]);
> +       }
> +       dtype = DT_REG;
> +       return is_excluded_from_list(key.buf, key.len, "", &dtype,
> +                                    &config_local) > 0;
> +}
> diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh
> @@ -198,4 +198,30 @@ test_expect_success 'local clone from linked checkout' '
> +test_expect_success 'setting worktree.foo goes to config.worktree' '
> +       echo worKtree.Foo >> .git/info/config.worktree &&

Perhaps? s/>> />/

> +       git worktree add wt.foo HEAD &&
> +       git config woRKtree.FOO barrrr &&
> +       git --git-dir=wt.foo/.git config woRKtree.FOO bar &&
> +       cat >expect <<\EOF &&
> +[woRKtree]
> +       FOO = bar
> +EOF
> +       test_cmp expect .git/worktrees/wt.foo/config.worktree &&
> +       git --git-dir=wt.foo/.git config woRktree.foo >actual2 &&
> +       echo bar >expect2 &&
> +       test_cmp expect2 actual2 &&
> +       test_path_is_missing .git/config.worktree &&
> +       git config WORKTREE.FOO >actual3 &&
> +       echo barrrr >expect3 &&
> +       test_cmp expect3 actual3
> +'
> +
> +test_expect_success 'shared config still goes to config' '
> +       git config random.key randomValue &&
> +       git --git-dir=wt.foo/.git config random.key >actual &&

What about also testing the opposite scenario?

    git --git-dir=wt.foo/.git  config random.key randomValue &&
    git config random.key >actual &&

> +       echo randomValue >expect &&
> +       test_cmp expect actual
> +'
> +
>  test_done
> --
> 2.2.0.513.g477eb31

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 5/5] git-worktree.txt: mention about the config file split
  2015-12-02 19:13 ` [PATCH 5/5] git-worktree.txt: mention about the config file split Nguyễn Thái Ngọc Duy
@ 2015-12-06  8:02   ` Eric Sunshine
  0 siblings, 0 replies; 53+ messages in thread
From: Eric Sunshine @ 2015-12-06  8:02 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy
  Cc: Git List, Michael J Gruber, Max Kirillov, Jens Lehmann

On Wed, Dec 2, 2015 at 2:13 PM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:
> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
> ---
> diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
> @@ -147,6 +147,19 @@ to `/path/main/.git/worktrees/test-next` then a file named
>  `test-next` entry from being pruned.  See
>  linkgit:gitrepository-layout[5] for details.
>
> +Similar to the file system split in ".git", the repository config file
> +is also split. Certain variables, for example core.worktree, are
> +per-worktree while the majority of variables are still shared (see
> +linkgit:git-config[1] for details). Shared variables and per-working
> +tree ones that belong to the main working tree are in .git/config.
> +Per-working tree variables for working tree X are in
> +$GIT_COMMON_DIR/worktrees/X/config.worktree. Even though per-working

Existing examples in the DETAILS section call this "test-next" rather
than "X", so perhaps s/X/test-next/g ?

> +tree variables for the main working tree are in the default config
> +place, they are invisible from all linked working trees.  You can make
> +more config variables per-working tree by adding them in
> +.git/info/config.worktree (see linkgit:gitrepository-layout[5] for
> +details).
> +
>  LIST OUTPUT FORMAT
>  ------------------
>  The worktree list command has two output formats.  The default format shows the
> --
> 2.2.0.513.g477eb31

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 2/5] config.c: move worktree-specific variables to .git/worktrees/...
  2015-12-06  7:47   ` Eric Sunshine
@ 2015-12-06 10:22     ` Duy Nguyen
  0 siblings, 0 replies; 53+ messages in thread
From: Duy Nguyen @ 2015-12-06 10:22 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: Git List, Michael J Gruber, Max Kirillov, Jens Lehmann

On Sun, Dec 6, 2015 at 8:47 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:
> On Wed, Dec 2, 2015 at 2:13 PM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:
>> .git/info/config.worktree is a pattern list that splits .git/config in
>> to sets: the worktree set matches the patterns, the commmon set does
>> not.
>>
>> In normal worktrees, both sets are stored in .git/config. The
>> config.worktree has no effect. Nothing is changed.
>>
>> In linked worktrees, the common and worktree sets are read from and
>> saved to .git/config and .git/config.worktree respectively. Config
>> keys in .git/config that belong to the worktree set is ignored. Those
>> are for the main worktree only. Similarly, keys not matching the
>> patterns come from .git/config, duplicate keys from
>> .git/config.worktree are ignored.
>>
>> The effect is similar to the $GIT_DIR/$GIT_COMMON_DIR split, we can
>> define that some vars can be shared and some cannot. And as a result
>> of the $GIT_DIR/$GIT_COMMON_DIR split, config.worktree is actually
>> found at .git/worktrees/<id>/config.worktree.
>
> Why does this worktree-specific file need/have a .worktree suffix?

I think in the beginning it was supposed to support git-new-workdir as
well. With a separate name, you can symlink .git/config back to
original repo and create a new .git/config.worktree. The actual code
in this patch does not support this though. I guess as 'git worktree'
is maturing, we probably don't have to worry about git-new-workdir and
could drop .worktree suffix.

>> +static int is_config_local(const char *key_)
>> +{
>> +       static struct strbuf key = STRBUF_INIT;
>> +       int i, dtype;
>> +
>> +       if (!config_local.nr)
>> +               return 0;
>> +
>> +       strbuf_reset(&key);
>> +       strbuf_addstr(&key, key_);
>
> Why does 'key' need to be static considering that it is overwritten on
> each call and its value is never accessed after the function returns?

Mostly to avoid re-allocation because this function will be called for
every configuration variable. But this may be premature optimization.
On top of that, if we go with builtin per-worktree list only as being
discussed, then we can drop exclude machinery, we don't have to
preprocess "key" and we can finally kill this "strbuf key".

>> @@ -198,4 +198,30 @@ test_expect_success 'local clone from linked checkout' '
>> +test_expect_success 'setting worktree.foo goes to config.worktree' '
>> +       echo worKtree.Foo >> .git/info/config.worktree &&
>
> Perhaps? s/>> />/

Yeah. In the previous iteration, config.worktree would contain the
default list (core.worktree and stuff) so > may force following tests
to re-initialize config.worktree again. But that's now gone and >
makes more sense.

>> +test_expect_success 'shared config still goes to config' '
>> +       git config random.key randomValue &&
>> +       git --git-dir=wt.foo/.git config random.key >actual &&
>
> What about also testing the opposite scenario?
>
>     git --git-dir=wt.foo/.git  config random.key randomValue &&
>     git config random.key >actual &&

Yep. Will do.
-- 
Duy

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v2 0/6] Split .git/config in multiple worktree setup
  2015-12-02 19:13 [PATCH 0/5] Split .git/config in multiple worktree setup Nguyễn Thái Ngọc Duy
                   ` (5 preceding siblings ...)
  2015-12-03  6:15 ` [PATCH 0/5] Split .git/config in multiple worktree setup Max Kirillov
@ 2015-12-27  3:14 ` Nguyễn Thái Ngọc Duy
  2015-12-27  3:14   ` [PATCH v2 1/6] Define new repo extension to manage multiple worktree behaviors Nguyễn Thái Ngọc Duy
                     ` (7 more replies)
  6 siblings, 8 replies; 53+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-12-27  3:14 UTC (permalink / raw)
  To: git
  Cc: git, max, Jens.Lehmann, Junio C Hamano,
	Nguyễn Thái Ngọc Duy

New design. We now define multiworktree behavior with config var
extensions.worktree. Latest git must support all older behavior
versions. If config file says "version 1", even if latest version is
3, git must behave like version 1. This covers all aspects of
multi-worktree, not just config files.

With that foundation, we can now build version 1 (version 0 is what
is already released). Version 1 stores per-worktree config in
$GIT_DIR/worktrees/.../config. The list of config vars is hard coded.
New list requires new worktree version.

The hard coded list actually supports precise variable name matching,
or prefix matching (e.g. submodule.*). I don't suppose we need full
fnmatch to support submodules.

include.path is now extended a bit to give the user an opportunity to
change the config split. The user can turn a shared config into
per-worktree (but not the other way around). It's done by allowing env
expansion in include.path. So if you specify

    include.path = $GIT_DIR/abc

"abc" will always be per-worktree.

Upgrade support is manual (for now). When a new worktree is added, we
can bump from version 0 (i.e. extensions.worktree is missing) to 1.
But that's it. We can't safely bump 1 to 2 automatically.

The code in this series is not meant to be run (I didn't even test
it). It's just in case my C expresses my ideas better than my English.

Nguyễn Thái Ngọc Duy (6):
  Define new repo extension to manage multiple worktree behaviors
  config.c: move worktree-specific variables to .git/worktrees/...
  setup.c: remove special case of core.worktree and core.bare
  worktree: make core.sparseCheckout and core.ignoreStat per-worktree
  config.c: allow to un-share certain config in multi-worktree setup
  worktree: bump worktree version to 1 on "worktree add"

 Documentation/config.txt                       |   4 +
 Documentation/git-worktree.txt                 |  12 ++
 Documentation/gitrepository-layout.txt         |   5 +
 Documentation/technical/repository-version.txt |   9 ++
 builtin/config.c                               |   9 ++
 builtin/worktree.c                             |  33 ++++++
 cache.h                                        |   4 +-
 config.c                                       | 151 +++++++++++++++++++++++--
 environment.c                                  |  14 +++
 setup.c                                        |  65 +++++------
 10 files changed, 264 insertions(+), 42 deletions(-)

-- 
2.3.0.rc1.137.g477eb31

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v2 1/6] Define new repo extension to manage multiple worktree behaviors
  2015-12-27  3:14 ` [PATCH v2 0/6] " Nguyễn Thái Ngọc Duy
@ 2015-12-27  3:14   ` Nguyễn Thái Ngọc Duy
  2015-12-27  3:14   ` [PATCH v2 2/6] config.c: move worktree-specific variables to .git/worktrees/ Nguyễn Thái Ngọc Duy
                     ` (6 subsequent siblings)
  7 siblings, 0 replies; 53+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-12-27  3:14 UTC (permalink / raw)
  To: git
  Cc: git, max, Jens.Lehmann, Junio C Hamano,
	Nguyễn Thái Ngọc Duy

Multiple worktree setup is still evolving and its behavior may be
changed in future. But we do not want to break existing worktree
setups. A new set of extensions, worktree=X, is recognized to tell Git
what multiple worktree "version" is being used so that Git can
behavior accordingly.

This extension has no use yet. The first one will be config split.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/technical/repository-version.txt | 6 ++++++
 cache.h                                        | 1 +
 environment.c                                  | 1 +
 setup.c                                        | 3 +++
 4 files changed, 11 insertions(+)

diff --git a/Documentation/technical/repository-version.txt b/Documentation/technical/repository-version.txt
index 00ad379..c680528 100644
--- a/Documentation/technical/repository-version.txt
+++ b/Documentation/technical/repository-version.txt
@@ -86,3 +86,9 @@ for testing format-1 compatibility.
 When the config key `extensions.preciousObjects` is set to `true`,
 objects in the repository MUST NOT be deleted (e.g., by `git-prune` or
 `git repack -d`).
+
+`worktree`
+~~~~~~~~~~~~~~
+
+Define behavior in multiple worktree setup. The value specifies the
+version. Default version is zero.
diff --git a/cache.h b/cache.h
index c63fcc1..fa0a64b 100644
--- a/cache.h
+++ b/cache.h
@@ -725,6 +725,7 @@ extern int grafts_replace_parents;
 #define GIT_REPO_VERSION_READ 1
 extern int repository_format_version;
 extern int repository_format_precious_objects;
+extern int repository_format_worktree_version;
 extern int check_repository_format(void);
 
 #define MTIME_CHANGED	0x0001
diff --git a/environment.c b/environment.c
index 2da7fe2..a3f17ed 100644
--- a/environment.c
+++ b/environment.c
@@ -27,6 +27,7 @@ int warn_on_object_refname_ambiguity = 1;
 int ref_paranoia = -1;
 int repository_format_version;
 int repository_format_precious_objects;
+int repository_format_worktree_version;
 const char *git_commit_encoding;
 const char *git_log_output_encoding;
 int shared_repository = PERM_UMASK;
diff --git a/setup.c b/setup.c
index d343725..2f41648 100644
--- a/setup.c
+++ b/setup.c
@@ -373,6 +373,9 @@ static int check_repo_format(const char *var, const char *value, void *cb)
 			;
 		else if (!strcmp(ext, "preciousobjects"))
 			repository_format_precious_objects = git_config_bool(var, value);
+		else if (!strcmp(ext, "worktree"))
+			repository_format_worktree_version =
+				git_config_ulong(var, value);
 		else
 			string_list_append(&unknown_extensions, ext);
 	}
-- 
2.3.0.rc1.137.g477eb31

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v2 2/6] config.c: move worktree-specific variables to .git/worktrees/...
  2015-12-27  3:14 ` [PATCH v2 0/6] " Nguyễn Thái Ngọc Duy
  2015-12-27  3:14   ` [PATCH v2 1/6] Define new repo extension to manage multiple worktree behaviors Nguyễn Thái Ngọc Duy
@ 2015-12-27  3:14   ` Nguyễn Thái Ngọc Duy
  2015-12-27  3:14   ` [PATCH v2 3/6] setup.c: remove special case of core.worktree and core.bare Nguyễn Thái Ngọc Duy
                     ` (5 subsequent siblings)
  7 siblings, 0 replies; 53+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-12-27  3:14 UTC (permalink / raw)
  To: git
  Cc: git, max, Jens.Lehmann, Junio C Hamano,
	Nguyễn Thái Ngọc Duy

In multiple worktree setup, a set of variables will be read from
$GIT_DIR/worktrees/<id>/config instead of $GIT_DIR/config, when the
config variables are accessed from a linked worktree. When accessed
from the main worktree, the same set is still read from $GIT_DIR/config.

This mechanism is needed because we do have worktree-specific config
variables such as core.worktree. But for now, no config variable is
marked per-worktree (so can't test yet).

This is the new behavior when repo extension worktree=1 is defined.

Helped-by: Max Kirillov <max@max630.net>
Helped-by: Jens Lehmann <Jens.Lehmann@web.de>
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/config.txt               |   4 ++
 Documentation/git-worktree.txt         |  11 +++
 Documentation/gitrepository-layout.txt |   5 ++
 builtin/config.c                       |   9 +++
 cache.h                                |   2 +-
 config.c                               | 121 +++++++++++++++++++++++++++++++--
 setup.c                                |   2 +-
 7 files changed, 145 insertions(+), 9 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index f617886..d507b8a 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -8,6 +8,10 @@ is used to store the configuration for that repository, and
 fallback values for the `.git/config` file. The file `/etc/gitconfig`
 can be used to store a system-wide default configuration.
 
+Linked worktrees (see linkgit:git-worktree[1]) also have a
+worktree-specific file config. See linkgit:gitrepository-layout[5] for
+more information.
+
 The configuration variables are used by both the Git plumbing
 and the porcelains. The variables are divided into sections, wherein
 the fully qualified variable name of the variable itself is the last
diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 5b9ad04..bc0734c 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -147,6 +147,17 @@ to `/path/main/.git/worktrees/test-next` then a file named
 `test-next` entry from being pruned.  See
 linkgit:gitrepository-layout[5] for details.
 
+Similar to the file system split in ".git", the repository config file
+is also split. Certain variables, for example core.worktree, are
+per-worktree while the majority of variables are still shared (see
+linkgit:git-config[1] for details). Shared variables and per-working
+tree ones that belong to the main working tree are in .git/config.
+Per-working tree variables for working tree X are in
+$GIT_COMMON_DIR/worktrees/X/config. Even though per-working tree
+variables for the main working tree are in the default config place,
+they are invisible from all linked working trees. The following
+configuration variables are per working directory:
+
 LIST OUTPUT FORMAT
 ------------------
 The worktree list command has two output formats.  The default format shows the
diff --git a/Documentation/gitrepository-layout.txt b/Documentation/gitrepository-layout.txt
index 577ee84..cf724e6 100644
--- a/Documentation/gitrepository-layout.txt
+++ b/Documentation/gitrepository-layout.txt
@@ -276,6 +276,11 @@ worktrees/<id>/link::
 	file. It is used to detect if the linked repository is
 	manually removed.
 
+worktrees/<id>/config::
+	This file contains worktree-specific configuration
+	variables. See the list of variables in linkgit:git-worktree[1].
+	The same variables in $GIT_COMMON_DIR/config are ignored.
+
 SEE ALSO
 --------
 linkgit:git-init[1],
diff --git a/builtin/config.c b/builtin/config.c
index adc7727..2b4d56e 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -533,6 +533,15 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 		default:
 			usage_with_options(builtin_config_usage, builtin_config_options);
 		}
+
+	/*
+	 * For set operations, --local could be either config or
+	 * config.worktree. Let config.c determine the path based on
+	 * config keys.
+	 */
+	if (use_local_config && actions != ACTION_LIST)
+		given_config_source.file = NULL;
+
 	if (omit_values &&
 	    !(actions == ACTION_LIST || actions == ACTION_GET_REGEXP)) {
 		error("--name-only is only applicable to --list or --get-regexp");
diff --git a/cache.h b/cache.h
index fa0a64b..10f4ff8 100644
--- a/cache.h
+++ b/cache.h
@@ -1494,7 +1494,7 @@ extern void git_config(config_fn_t fn, void *);
 extern int git_config_with_options(config_fn_t fn, void *,
 				   struct git_config_source *config_source,
 				   int respect_includes);
-extern int git_config_early(config_fn_t fn, void *, const char *repo_config);
+extern int git_config_early(config_fn_t fn, void *, const char *repo_config, const char *worktree_config);
 extern int git_parse_ulong(const char *, unsigned long *);
 extern int git_parse_maybe_bool(const char *);
 extern int git_config_int(const char *, const char *);
diff --git a/config.c b/config.c
index 86a5eb2..7d94f21 100644
--- a/config.c
+++ b/config.c
@@ -37,10 +37,25 @@ struct config_source {
 	long (*do_ftell)(struct config_source *c);
 };
 
+struct config_pattern {
+	unsigned int prefix;
+	unsigned int len;
+	const char *pattern;
+};
+
 static struct config_source *cf;
 
 static int zlib_compression_seen;
 
+static struct config_pattern worktree_v1[] = {
+	{ 0, 0, NULL }
+};
+
+static struct config_pattern *worktree_patterns[] = {
+	NULL,
+	worktree_v1
+};
+
 /*
  * Default config_set that contains key-value pairs from the usual set of config
  * config files (i.e repo specific .git/config, user wide ~/.gitconfig, XDG
@@ -89,6 +104,34 @@ static long config_buf_ftell(struct config_source *conf)
 	return conf->u.buf.pos;
 }
 
+static int is_config_local(const char *key_)
+{
+	int len;
+	struct config_pattern *cp;
+
+	if (repository_format_worktree_version < 0 ||
+	    repository_format_worktree_version >= ARRAY_SIZE(worktree_patterns))
+		die("unknown config version %d", repository_format_worktree_version);
+
+	cp = worktree_patterns[repository_format_worktree_version];
+	if (!cp)
+		return 0;
+	len = strlen(key_);
+	for (; ; cp++) {
+		if (!cp->pattern)
+			return 0;
+		if (!cp->len)
+			cp->len = strlen(cp->pattern);
+		if (len < cp->len)
+			continue;
+		if (strncmp(key_, cp->pattern, len))
+			continue;
+		if (!cp->prefix && len > cp->len)
+			continue;
+		return 1;
+	}
+}
+
 #define MAX_INCLUDE_DEPTH 10
 static const char include_depth_advice[] =
 "exceeded maximum include depth (%d) while including\n"
@@ -1184,7 +1227,36 @@ int git_config_system(void)
 	return !git_env_bool("GIT_CONFIG_NOSYSTEM", 0);
 }
 
-int git_config_early(config_fn_t fn, void *data, const char *repo_config)
+static char *worktree_config_path(void)
+{
+	struct strbuf sb = STRBUF_INIT;
+	strbuf_addf(&sb, "%s/config", get_git_dir());
+	return strbuf_detach(&sb, NULL);
+}
+
+static int config_worktree_filter_in(const char *var,
+				     const char *value, void *data)
+{
+	struct config_include_data *inc = data;
+
+	if (!is_config_local(var))
+		return error("%s in per-worktree config file is ignored", var);
+	return inc->fn(var, value, inc->data);
+}
+
+static int config_worktree_filter_out(const char *var,
+				      const char *value, void *data)
+{
+	struct config_include_data *inc = data;
+
+	if (is_config_local(var))
+		return 0;	/* these are for main worktree only */
+
+	return inc->fn(var, value, inc->data);
+}
+
+int git_config_early(config_fn_t fn, void *data, const char *repo_config,
+		     const char *worktree_config)
 {
 	int ret = 0, found = 0;
 	char *xdg_config = xdg_config_home("config");
@@ -1206,7 +1278,23 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)
 		found += 1;
 	}
 
-	if (repo_config && !access_or_die(repo_config, R_OK, 0)) {
+	if (worktree_config) {
+		struct config_include_data inc = CONFIG_INCLUDE_INIT;
+
+		inc.fn = fn;
+		inc.data = data;
+		if (!access_or_die(worktree_config, R_OK, 0)) {
+			ret += git_config_from_file(config_worktree_filter_in,
+						    worktree_config, &inc);
+			found += 1;
+		}
+
+		if (repo_config && !access_or_die(repo_config, R_OK, 0)) {
+			ret += git_config_from_file(config_worktree_filter_out,
+						    repo_config, &inc);
+			found += 1;
+		}
+	} else if (repo_config && !access_or_die(repo_config, R_OK, 0)) {
 		ret += git_config_from_file(fn, repo_config, data);
 		found += 1;
 	}
@@ -1232,6 +1320,7 @@ int git_config_with_options(config_fn_t fn, void *data,
 			    int respect_includes)
 {
 	char *repo_config = NULL;
+	char *worktree_config = NULL;
 	int ret;
 	struct config_include_data inc = CONFIG_INCLUDE_INIT;
 
@@ -1254,9 +1343,11 @@ int git_config_with_options(config_fn_t fn, void *data,
 		return git_config_from_blob_ref(fn, config_source->blob, data);
 
 	repo_config = git_pathdup("config");
-	ret = git_config_early(fn, data, repo_config);
-	if (repo_config)
-		free(repo_config);
+	if (git_common_dir_env)
+		worktree_config = worktree_config_path();
+	ret = git_config_early(fn, data, repo_config, worktree_config);
+	free(repo_config);
+	free(worktree_config);
 	return ret;
 }
 
@@ -1925,6 +2016,23 @@ int git_config_key_is_valid(const char *key)
 	return !git_config_parse_key_1(key, NULL, NULL, 1);
 }
 
+static const char *get_config_filename(const char *config_filename,
+				       const char *key,
+				       char **filename_buf)
+{
+	if (config_filename)
+		return config_filename;
+	if (!git_common_dir_env) {
+		config_filename = *filename_buf = git_pathdup("config");
+		return config_filename;
+	}
+	if (!is_config_local(key))
+		config_filename = *filename_buf = git_pathdup("config");
+	else
+		config_filename = *filename_buf = worktree_config_path();
+	return config_filename;
+}
+
 /*
  * If value==NULL, unset in (remove from) config,
  * if value_regex!=NULL, disregard key/value pairs where value does not match.
@@ -1968,8 +2076,7 @@ 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");
+	config_filename = get_config_filename(config_filename, key, &filename_buf);
 
 	/*
 	 * The lock serves a purpose in addition to locking: the new
diff --git a/setup.c b/setup.c
index 2f41648..9196945 100644
--- a/setup.c
+++ b/setup.c
@@ -407,7 +407,7 @@ static int check_repository_format_gently(const char *gitdir, int *nongit_ok)
 	 * Use a gentler version of git_config() to check if this repo
 	 * is a good one.
 	 */
-	git_config_early(fn, NULL, repo_config);
+	git_config_early(fn, NULL, repo_config, NULL);
 	if (GIT_REPO_VERSION_READ < repository_format_version) {
 		if (!nongit_ok)
 			die ("Expected git repo version <= %d, found %d",
-- 
2.3.0.rc1.137.g477eb31

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v2 3/6] setup.c: remove special case of core.worktree and core.bare
  2015-12-27  3:14 ` [PATCH v2 0/6] " Nguyễn Thái Ngọc Duy
  2015-12-27  3:14   ` [PATCH v2 1/6] Define new repo extension to manage multiple worktree behaviors Nguyễn Thái Ngọc Duy
  2015-12-27  3:14   ` [PATCH v2 2/6] config.c: move worktree-specific variables to .git/worktrees/ Nguyễn Thái Ngọc Duy
@ 2015-12-27  3:14   ` Nguyễn Thái Ngọc Duy
  2015-12-27  3:14   ` [PATCH v2 4/6] worktree: make core.sparseCheckout and core.ignoreStat per-worktree Nguyễn Thái Ngọc Duy
                     ` (4 subsequent siblings)
  7 siblings, 0 replies; 53+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-12-27  3:14 UTC (permalink / raw)
  To: git
  Cc: git, max, Jens.Lehmann, Junio C Hamano,
	Nguyễn Thái Ngọc Duy

core.worktree and core.bare, which are treated specially in 31e26eb [1],
are now defined per-worktree with repo extension worktree=1 and the
special treatment reverted. The test "$GIT_DIR/common overrides
core.worktree" in t1501 from 31e26eb verifies that the behavior is
still correct after this change.

A note about core.bare. On the surface it does not make sense for
core.bare to be worktree specific. It's made so in order to "grow" new
worktrees from a bare repo. In these new linked worktrees, core.bare
will be hidden away and worktree-related commands won't complain about
bare repository.

[1] 31e26eb (setup.c: support multi-checkout repo setup - 2014-11-30)

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/git-worktree.txt                 |  1 +
 Documentation/technical/repository-version.txt |  3 ++
 config.c                                       |  2 +
 setup.c                                        | 68 ++++++++++++--------------
 4 files changed, 37 insertions(+), 37 deletions(-)

diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index bc0734c..087b35e 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -157,6 +157,7 @@ $GIT_COMMON_DIR/worktrees/X/config. Even though per-working tree
 variables for the main working tree are in the default config place,
 they are invisible from all linked working trees. The following
 configuration variables are per working directory:
+core.bare, core.worktree.
 
 LIST OUTPUT FORMAT
 ------------------
diff --git a/Documentation/technical/repository-version.txt b/Documentation/technical/repository-version.txt
index c680528..fc2cdb9 100644
--- a/Documentation/technical/repository-version.txt
+++ b/Documentation/technical/repository-version.txt
@@ -92,3 +92,6 @@ objects in the repository MUST NOT be deleted (e.g., by `git-prune` or
 
 Define behavior in multiple worktree setup. The value specifies the
 version. Default version is zero.
+
+In version 1, the following config variables are per-worktree:
+core.bare, core.worktree.
diff --git a/config.c b/config.c
index 7d94f21..c2ea91b 100644
--- a/config.c
+++ b/config.c
@@ -48,6 +48,8 @@ static struct config_source *cf;
 static int zlib_compression_seen;
 
 static struct config_pattern worktree_v1[] = {
+	{ 0, 0, "core.bare" },
+	{ 0, 0, "core.worktree" },
 	{ 0, 0, NULL }
 };
 
diff --git a/setup.c b/setup.c
index 9196945..b49d61e 100644
--- a/setup.c
+++ b/setup.c
@@ -355,46 +355,20 @@ void setup_work_tree(void)
 	initialized = 1;
 }
 
-static int check_repo_format(const char *var, const char *value, void *cb)
-{
-	const char *ext;
-
-	if (strcmp(var, "core.repositoryformatversion") == 0)
-		repository_format_version = git_config_int(var, value);
-	else if (strcmp(var, "core.sharedrepository") == 0)
-		shared_repository = git_config_perm(var, value);
-	else if (skip_prefix(var, "extensions.", &ext)) {
-		/*
-		 * record any known extensions here; otherwise,
-		 * we fall through to recording it as unknown, and
-		 * check_repository_format will complain
-		 */
-		if (!strcmp(ext, "noop"))
-			;
-		else if (!strcmp(ext, "preciousobjects"))
-			repository_format_precious_objects = git_config_bool(var, value);
-		else if (!strcmp(ext, "worktree"))
-			repository_format_worktree_version =
-				git_config_ulong(var, value);
-		else
-			string_list_append(&unknown_extensions, ext);
-	}
-	return 0;
-}
-
 static int check_repository_format_gently(const char *gitdir, int *nongit_ok)
 {
 	struct strbuf sb = STRBUF_INIT;
+	struct strbuf sb2 = STRBUF_INIT;
 	const char *repo_config;
-	config_fn_t fn;
+	const char *worktree_config = NULL;
 	int ret = 0;
 
 	string_list_clear(&unknown_extensions, 0);
 
-	if (get_common_dir(&sb, gitdir))
-		fn = check_repo_format;
-	else
-		fn = check_repository_format_version;
+	if (get_common_dir(&sb, gitdir)) {
+		strbuf_addf(&sb2, "%s/config.worktree", gitdir);
+		worktree_config = sb2.buf;
+	}
 	strbuf_addstr(&sb, "/config");
 	repo_config = sb.buf;
 
@@ -407,7 +381,8 @@ static int check_repository_format_gently(const char *gitdir, int *nongit_ok)
 	 * Use a gentler version of git_config() to check if this repo
 	 * is a good one.
 	 */
-	git_config_early(fn, NULL, repo_config, NULL);
+	git_config_early(check_repository_format_version, NULL,
+			 repo_config, worktree_config);
 	if (GIT_REPO_VERSION_READ < repository_format_version) {
 		if (!nongit_ok)
 			die ("Expected git repo version <= %d, found %d",
@@ -434,6 +409,7 @@ static int check_repository_format_gently(const char *gitdir, int *nongit_ok)
 	}
 
 	strbuf_release(&sb);
+	strbuf_release(&sb2);
 	return ret;
 }
 
@@ -966,10 +942,28 @@ int git_config_perm(const char *var, const char *value)
 
 int check_repository_format_version(const char *var, const char *value, void *cb)
 {
-	int ret = check_repo_format(var, value, cb);
-	if (ret)
-		return ret;
-	if (strcmp(var, "core.bare") == 0) {
+	const char *ext;
+
+	if (strcmp(var, "core.repositoryformatversion") == 0)
+		repository_format_version = git_config_int(var, value);
+	else if (strcmp(var, "core.sharedrepository") == 0)
+		shared_repository = git_config_perm(var, value);
+	else if (skip_prefix(var, "extensions.", &ext)) {
+		/*
+		 * record any known extensions here; otherwise,
+		 * we fall through to recording it as unknown, and
+		 * check_repository_format will complain
+		 */
+		if (!strcmp(ext, "noop"))
+			;
+		else if (!strcmp(ext, "preciousobjects"))
+			repository_format_precious_objects = git_config_bool(var, value);
+		else if (!strcmp(ext, "worktree"))
+			repository_format_worktree_version =
+				git_config_ulong(var, value);
+		else
+			string_list_append(&unknown_extensions, ext);
+	} else if (strcmp(var, "core.bare") == 0) {
 		is_bare_repository_cfg = git_config_bool(var, value);
 		if (is_bare_repository_cfg == 1)
 			inside_work_tree = -1;
-- 
2.3.0.rc1.137.g477eb31

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v2 4/6] worktree: make core.sparseCheckout and core.ignoreStat per-worktree
  2015-12-27  3:14 ` [PATCH v2 0/6] " Nguyễn Thái Ngọc Duy
                     ` (2 preceding siblings ...)
  2015-12-27  3:14   ` [PATCH v2 3/6] setup.c: remove special case of core.worktree and core.bare Nguyễn Thái Ngọc Duy
@ 2015-12-27  3:14   ` Nguyễn Thái Ngọc Duy
  2015-12-27  3:14   ` [PATCH v2 5/6] config.c: allow to un-share certain config in multi-worktree setup Nguyễn Thái Ngọc Duy
                     ` (3 subsequent siblings)
  7 siblings, 0 replies; 53+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-12-27  3:14 UTC (permalink / raw)
  To: git
  Cc: git, max, Jens.Lehmann, Junio C Hamano,
	Nguyễn Thái Ngọc Duy

The first one must be per-worktree because info/sparse-checkout
already is. The second one shares the same nature and should also be
per-worktree.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/git-worktree.txt                 | 2 +-
 Documentation/technical/repository-version.txt | 2 +-
 config.c                                       | 2 ++
 3 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 087b35e..bc6a26e 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -157,7 +157,7 @@ $GIT_COMMON_DIR/worktrees/X/config. Even though per-working tree
 variables for the main working tree are in the default config place,
 they are invisible from all linked working trees. The following
 configuration variables are per working directory:
-core.bare, core.worktree.
+core.bare, core.ignorestat, core.sparsecheckout, core.worktree.
 
 LIST OUTPUT FORMAT
 ------------------
diff --git a/Documentation/technical/repository-version.txt b/Documentation/technical/repository-version.txt
index fc2cdb9..4fc113b 100644
--- a/Documentation/technical/repository-version.txt
+++ b/Documentation/technical/repository-version.txt
@@ -94,4 +94,4 @@ Define behavior in multiple worktree setup. The value specifies the
 version. Default version is zero.
 
 In version 1, the following config variables are per-worktree:
-core.bare, core.worktree.
+core.bare, core.ignorestat, core.sparsecheckout, core.worktree.
diff --git a/config.c b/config.c
index c2ea91b..5aa1379 100644
--- a/config.c
+++ b/config.c
@@ -49,6 +49,8 @@ static int zlib_compression_seen;
 
 static struct config_pattern worktree_v1[] = {
 	{ 0, 0, "core.bare" },
+	{ 0, 0, "core.ignorestat" },
+	{ 0, 0, "core.sparsecheckout" },
 	{ 0, 0, "core.worktree" },
 	{ 0, 0, NULL }
 };
-- 
2.3.0.rc1.137.g477eb31

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v2 5/6] config.c: allow to un-share certain config in multi-worktree setup
  2015-12-27  3:14 ` [PATCH v2 0/6] " Nguyễn Thái Ngọc Duy
                     ` (3 preceding siblings ...)
  2015-12-27  3:14   ` [PATCH v2 4/6] worktree: make core.sparseCheckout and core.ignoreStat per-worktree Nguyễn Thái Ngọc Duy
@ 2015-12-27  3:14   ` Nguyễn Thái Ngọc Duy
  2015-12-27  3:14   ` [PATCH v2 6/6] worktree: bump worktree version to 1 on "worktree add" Nguyễn Thái Ngọc Duy
                     ` (2 subsequent siblings)
  7 siblings, 0 replies; 53+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-12-27  3:14 UTC (permalink / raw)
  To: git
  Cc: git, max, Jens.Lehmann, Junio C Hamano,
	Nguyễn Thái Ngọc Duy

Repo ext worktree=1 provides a set of config vars that _must_ be
per-worktree. However, the user may want to make some more config vars
per-worktree, depending on their workflow.

include.path is extended to make this possible. If the given path is
in the form "$GIT_xyz/abc" then "$GIT_xyz" will be expanded using the
corresponding environment variable. To unshare, the user can save
config in, for example, $GIT_DIR/worktrees/<id>/config.worktree and
specify this in $GIT_DIR/config

    include.path = $GIT_DIR/config.worktree

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 cache.h       |  1 +
 config.c      | 26 ++++++++++++++++++++++++++
 environment.c | 13 +++++++++++++
 3 files changed, 40 insertions(+)

diff --git a/cache.h b/cache.h
index 10f4ff8..cc00ca1 100644
--- a/cache.h
+++ b/cache.h
@@ -454,6 +454,7 @@ extern int is_bare_repository(void);
 extern int is_inside_git_dir(void);
 extern char *git_work_tree_cfg;
 extern int is_inside_work_tree(void);
+extern const char *get_git_env(const char *name);
 extern const char *get_git_dir(void);
 extern const char *get_git_common_dir(void);
 extern int is_git_directory(const char *path);
diff --git a/config.c b/config.c
index 5aa1379..eb951f5 100644
--- a/config.c
+++ b/config.c
@@ -155,6 +155,32 @@ static int handle_path_include(const char *path, struct config_include_data *inc
 	expanded = expand_user_path(path);
 	if (!expanded)
 		return error("Could not expand include path '%s'", path);
+
+	if (starts_with(expanded, "$GIT_")) {
+		char *slash = expanded;
+		const char *base = NULL;
+		struct strbuf sb = STRBUF_INIT;
+
+		while (*slash && !is_dir_sep(*slash))
+			slash++;
+
+		if (*slash) {
+			char saved_slash = *slash;
+			*slash = '\0';
+			base = get_git_env(expanded + 1);
+			*slash = saved_slash;
+		}
+
+		if (!base) {
+			free(expanded);
+			return error("Could not expand include path '%s'", path);
+		}
+
+		strbuf_addstr(&sb, real_path(base));
+		strbuf_addstr(&sb, slash);
+		free(expanded);
+		expanded = strbuf_detach(&sb, NULL);
+	}
 	path = expanded;
 
 	/*
diff --git a/environment.c b/environment.c
index a3f17ed..7a1d62e 100644
--- a/environment.c
+++ b/environment.c
@@ -321,3 +321,16 @@ const char *get_commit_output_encoding(void)
 {
 	return git_commit_encoding ? git_commit_encoding : "UTF-8";
 }
+
+const char *get_git_env(const char *name)
+{
+	if (!strcmp(name, GIT_DIR_ENVIRONMENT))
+		return get_git_dir();
+	else if (!strcmp(name, GIT_WORK_TREE_ENVIRONMENT))
+		return get_git_work_tree();
+	else if (!strcmp(name, GIT_COMMON_DIR_ENVIRONMENT))
+		return get_git_common_dir();
+	// else if ... check environment.c
+	else
+		return getenv(name);
+}
-- 
2.3.0.rc1.137.g477eb31

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v2 6/6] worktree: bump worktree version to 1 on "worktree add"
  2015-12-27  3:14 ` [PATCH v2 0/6] " Nguyễn Thái Ngọc Duy
                     ` (4 preceding siblings ...)
  2015-12-27  3:14   ` [PATCH v2 5/6] config.c: allow to un-share certain config in multi-worktree setup Nguyễn Thái Ngọc Duy
@ 2015-12-27  3:14   ` Nguyễn Thái Ngọc Duy
  2016-01-11 22:43   ` [PATCH v2 0/6] Split .git/config in multiple worktree setup Max Kirillov
  2016-01-26 11:44   ` [PATCH v3 " Nguyễn Thái Ngọc Duy
  7 siblings, 0 replies; 53+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-12-27  3:14 UTC (permalink / raw)
  To: git
  Cc: git, max, Jens.Lehmann, Junio C Hamano,
	Nguyễn Thái Ngọc Duy

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin/worktree.c | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/builtin/worktree.c b/builtin/worktree.c
index 475b958..2ec9c36 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -184,6 +184,37 @@ static const char *worktree_basename(const char *path, int *olen)
 	return name;
 }
 
+static int git_config_set_int(const char *key, int value)
+{
+	struct strbuf sb = STRBUF_INIT;
+	int ret;
+
+	strbuf_addf(&sb, "%d", value);
+	ret = git_config_set(key, sb.buf);
+	strbuf_release(&sb);
+	return ret;
+}
+
+static void upgrade_worktree_version(void)
+{
+	if (repository_format_worktree_version != 0)
+		/*
+		 * XXX: anything else to do when upgrading from
+		 * version X to Y? Also, the user may want to stick to
+		 * a particular version if multiple git versions
+		 * operate on this repo. In that case, do not
+		 * automatically bump version up.
+		 */
+		return;
+	repository_format_worktree_version = 1;
+	if (repository_format_version < 2)
+		repository_format_version = 2;
+	git_config_set_int("core.repositoryformatversion",
+			   repository_format_version);
+	git_config_set_int("extensions.worktree",
+			   repository_format_worktree_version);
+}
+
 static int add_worktree(const char *path, const char *refname,
 			const struct add_opts *opts)
 {
@@ -268,6 +299,8 @@ static int add_worktree(const char *path, const char *refname,
 	strbuf_addf(&sb, "%s/commondir", sb_repo.buf);
 	write_file(sb.buf, "../..");
 
+	upgrade_worktree_version();
+
 	fprintf_ln(stderr, _("Preparing %s (identifier %s)"), path, name);
 
 	argv_array_pushf(&child_env, "%s=%s", GIT_DIR_ENVIRONMENT, sb_git.buf);
-- 
2.3.0.rc1.137.g477eb31

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 0/6] Split .git/config in multiple worktree setup
  2015-12-27  3:14 ` [PATCH v2 0/6] " Nguyễn Thái Ngọc Duy
                     ` (5 preceding siblings ...)
  2015-12-27  3:14   ` [PATCH v2 6/6] worktree: bump worktree version to 1 on "worktree add" Nguyễn Thái Ngọc Duy
@ 2016-01-11 22:43   ` Max Kirillov
  2016-01-26 11:44   ` [PATCH v3 " Nguyễn Thái Ngọc Duy
  7 siblings, 0 replies; 53+ messages in thread
From: Max Kirillov @ 2016-01-11 22:43 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy
  Cc: git, git, Jens.Lehmann, Junio C Hamano

Hi.

On Sun, Dec 27, 2015 at 10:14:33AM +0700, Nguyễn Thái Ngọc Duy wrote:
> Upgrade support is manual (for now). When a new worktree is added, we
> can bump from version 0 (i.e. extensions.worktree is missing) to 1.
> But that's it. We can't safely bump 1 to 2 automatically.

Maybe, bumping should happen only if there is no worktree so
far. If there is already, then worktree left to be 0 or
whatever it is. Then it can be bumped directly to the last
supported version.

Otherwise sounds ok. I have checked how it works and did not
read the code carefully, since you it's not ready yet.

-- 
Max

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v3 0/6] Split .git/config in multiple worktree setup
  2015-12-27  3:14 ` [PATCH v2 0/6] " Nguyễn Thái Ngọc Duy
                     ` (6 preceding siblings ...)
  2016-01-11 22:43   ` [PATCH v2 0/6] Split .git/config in multiple worktree setup Max Kirillov
@ 2016-01-26 11:44   ` Nguyễn Thái Ngọc Duy
  2016-01-26 11:44     ` [PATCH v3 1/6] worktree: new repo extension to manage worktree behaviors Nguyễn Thái Ngọc Duy
                       ` (6 more replies)
  7 siblings, 7 replies; 53+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2016-01-26 11:44 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, max, git, Jens.Lehmann,
	Nguyễn Thái Ngọc Duy

I've changed my mind. So v3 is not a polished v2. It's quite different.
And I hope it's good different.

In v2, .git/config contains both shared part and the per-worktree part
(for main worktree). It's ugly, slow and hard to work with. v3 adds a
completly new config file for sharing. ".git/config" will not be shared
any more.

For any worktree, the new file .git/common/config is read first, then
either .git/config or .git/worktrees/xxx/config is read after. There's
no special per-worktree var list any more. Which is great. You want to
add per-worktree config vars, use "git config --local". You want to
add per-repo config vars, use (new) "git config --repo". You put a
variable in a wrong file, you're punished for it (and it's the same
today, say if you put core.worktree to /etc/gitconfig).

The only ugly part I see is how to deal with released git binaries,
how to make it reject the new config split (because otherwise it would
read incorrectly).

A lot more explanation is in patch 04/06. The series is also
available at https://github.com/pclouds/git/tree/worktree-config

Nguyễn Thái Ngọc Duy (6):
  worktree: new repo extension to manage worktree behaviors
  path.c: new (identical) list for worktree v1
  worktree: share .git/common in v1
  worktree: new config file hierarchy
  config: select .git/common/config with --repo
  worktree add: switch to worktree version 1

 Documentation/config.txt                       |   5 +-
 Documentation/git-config.txt                   |  14 +++-
 Documentation/git-worktree.txt                 |  31 +++++++-
 Documentation/gitrepository-layout.txt         |  12 +++
 Documentation/technical/repository-version.txt |   6 ++
 builtin/config.c                               |  19 +++--
 builtin/worktree.c                             |  95 ++++++++++++++++++++++
 cache.h                                        |   5 +-
 config.c                                       |  14 +++-
 environment.c                                  |   1 +
 path.c                                         |  40 +++++++++-
 setup.c                                        |  40 ++++++++--
 t/t2028-worktree-config.sh (new +x)            | 104 +++++++++++++++++++++++++
 13 files changed, 364 insertions(+), 22 deletions(-)
 create mode 100755 t/t2028-worktree-config.sh

-- 
2.7.0.288.g1d8ad15

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v3 1/6] worktree: new repo extension to manage worktree behaviors
  2016-01-26 11:44   ` [PATCH v3 " Nguyễn Thái Ngọc Duy
@ 2016-01-26 11:44     ` Nguyễn Thái Ngọc Duy
  2016-01-27 22:12       ` Junio C Hamano
  2016-01-30 13:59       ` Max Kirillov
  2016-01-26 11:44     ` [PATCH v3 2/6] path.c: new (identical) list for worktree v1 Nguyễn Thái Ngọc Duy
                       ` (5 subsequent siblings)
  6 siblings, 2 replies; 53+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2016-01-26 11:44 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, max, git, Jens.Lehmann,
	Nguyễn Thái Ngọc Duy

Multiple worktree setup is still evolving and its behavior may be
changed in future. But we do not want to break existing worktree
setups. A new set of extensions, worktree=X, is recognized to tell Git
what multiple worktree "version" is being used so that Git can
behavior accordingly.

This extension has no use yet. The first one will be config split.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/git-worktree.txt                 | 12 ++++++++++++
 Documentation/technical/repository-version.txt |  6 ++++++
 cache.h                                        |  1 +
 environment.c                                  |  1 +
 setup.c                                        |  3 +++
 5 files changed, 23 insertions(+)

diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 5b9ad04..048d7d6 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -106,6 +106,18 @@ OPTIONS
 --expire <time>::
 	With `prune`, only expire unused working trees older than <time>.
 
+WORKTREE VERSIONS AND MIGRATION
+-------------------------------
+Multiple worktree is still an experimental feature and evolving. Every
+time the behavior is changed, the "worktree version" is stepped
+up. Worktree version is stored as a configuration variable
+extensions.worktree.
+
+Version 0
+~~~~~~~~~
+This is the first release. Version 0 is implied if extensions.worktree
+does not exist.
+
 DETAILS
 -------
 Each linked working tree has a private sub-directory in the repository's
diff --git a/Documentation/technical/repository-version.txt b/Documentation/technical/repository-version.txt
index 00ad379..e4583c5 100644
--- a/Documentation/technical/repository-version.txt
+++ b/Documentation/technical/repository-version.txt
@@ -86,3 +86,9 @@ for testing format-1 compatibility.
 When the config key `extensions.preciousObjects` is set to `true`,
 objects in the repository MUST NOT be deleted (e.g., by `git-prune` or
 `git repack -d`).
+
+`worktree`
+~~~~~~~~~~
+
+Define behavior in multiple worktree setup. The value specifies the
+version. Default version is zero.
diff --git a/cache.h b/cache.h
index dfc459c..e742c46 100644
--- a/cache.h
+++ b/cache.h
@@ -727,6 +727,7 @@ extern int grafts_replace_parents;
 #define GIT_REPO_VERSION_READ 1
 extern int repository_format_version;
 extern int repository_format_precious_objects;
+extern int repository_format_worktree_version;
 extern int check_repository_format(void);
 
 #define MTIME_CHANGED	0x0001
diff --git a/environment.c b/environment.c
index 1cc4aab..1bd4a56 100644
--- a/environment.c
+++ b/environment.c
@@ -27,6 +27,7 @@ int warn_on_object_refname_ambiguity = 1;
 int ref_paranoia = -1;
 int repository_format_version;
 int repository_format_precious_objects;
+int repository_format_worktree_version;
 const char *git_commit_encoding;
 const char *git_log_output_encoding;
 int shared_repository = PERM_UMASK;
diff --git a/setup.c b/setup.c
index d343725..2f41648 100644
--- a/setup.c
+++ b/setup.c
@@ -373,6 +373,9 @@ static int check_repo_format(const char *var, const char *value, void *cb)
 			;
 		else if (!strcmp(ext, "preciousobjects"))
 			repository_format_precious_objects = git_config_bool(var, value);
+		else if (!strcmp(ext, "worktree"))
+			repository_format_worktree_version =
+				git_config_ulong(var, value);
 		else
 			string_list_append(&unknown_extensions, ext);
 	}
-- 
2.7.0.288.g1d8ad15

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v3 2/6] path.c: new (identical) list for worktree v1
  2016-01-26 11:44   ` [PATCH v3 " Nguyễn Thái Ngọc Duy
  2016-01-26 11:44     ` [PATCH v3 1/6] worktree: new repo extension to manage worktree behaviors Nguyễn Thái Ngọc Duy
@ 2016-01-26 11:44     ` Nguyễn Thái Ngọc Duy
  2016-01-27 22:18       ` Junio C Hamano
  2016-01-30 14:45       ` Max Kirillov
  2016-01-26 11:44     ` [PATCH v3 3/6] worktree: share .git/common in v1 Nguyễn Thái Ngọc Duy
                       ` (4 subsequent siblings)
  6 siblings, 2 replies; 53+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2016-01-26 11:44 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, max, git, Jens.Lehmann,
	Nguyễn Thái Ngọc Duy

Worktree v1 may have different .git file split than v0. Add support
code to change common file list based on extensions.worktree. The list
for now is identical to v0.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 path.c | 40 +++++++++++++++++++++++++++++++++++++---
 1 file changed, 37 insertions(+), 3 deletions(-)

diff --git a/path.c b/path.c
index 3cd155e..14adf5d 100644
--- a/path.c
+++ b/path.c
@@ -100,7 +100,7 @@ struct common_dir {
 	const char *dirname;
 };
 
-static struct common_dir common_list[] = {
+static struct common_dir common_list_v0[] = {
 	{ 0, 1, 0, "branches" },
 	{ 0, 1, 0, "hooks" },
 	{ 0, 1, 0, "info" },
@@ -123,6 +123,40 @@ static struct common_dir common_list[] = {
 	{ 0, 0, 0, NULL }
 };
 
+static struct common_dir common_list_v1[] = {
+	{ 0, 1, 0, "branches" },
+	{ 0, 1, 0, "hooks" },
+	{ 0, 1, 0, "info" },
+	{ 0, 0, 1, "info/sparse-checkout" },
+	{ 1, 1, 0, "logs" },
+	{ 1, 1, 1, "logs/HEAD" },
+	{ 0, 1, 1, "logs/refs/bisect" },
+	{ 0, 1, 0, "lost-found" },
+	{ 0, 1, 0, "objects" },
+	{ 0, 1, 0, "refs" },
+	{ 0, 1, 1, "refs/bisect" },
+	{ 0, 1, 0, "remotes" },
+	{ 0, 1, 0, "worktrees" },
+	{ 0, 1, 0, "rr-cache" },
+	{ 0, 1, 0, "svn" },
+	{ 0, 0, 0, "config" },
+	{ 1, 0, 0, "gc.pid" },
+	{ 0, 0, 0, "packed-refs" },
+	{ 0, 0, 0, "shallow" },
+	{ 0, 0, 0, NULL }
+};
+
+static struct common_dir *get_common_list(void)
+{
+	switch (repository_format_worktree_version) {
+	case 0: return common_list_v0;
+	case 1: return common_list_v1;
+	default:
+		die(_("unsupported worktree format version %d"),
+		    repository_format_worktree_version);
+	}
+}
+
 /*
  * A compressed trie.  A trie node consists of zero or more characters that
  * are common to all elements with this prefix, optionally followed by some
@@ -309,7 +343,7 @@ static void init_common_trie(void)
 	if (common_trie_done_setup)
 		return;
 
-	for (p = common_list; p->dirname; p++)
+	for (p = get_common_list(); p->dirname; p++)
 		add_to_trie(&common_trie, p->dirname, p);
 
 	common_trie_done_setup = 1;
@@ -356,7 +390,7 @@ void report_linked_checkout_garbage(void)
 		return;
 	strbuf_addf(&sb, "%s/", get_git_dir());
 	len = sb.len;
-	for (p = common_list; p->dirname; p++) {
+	for (p = get_common_list(); p->dirname; p++) {
 		const char *path = p->dirname;
 		if (p->ignore_garbage)
 			continue;
-- 
2.7.0.288.g1d8ad15

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v3 3/6] worktree: share .git/common in v1
  2016-01-26 11:44   ` [PATCH v3 " Nguyễn Thái Ngọc Duy
  2016-01-26 11:44     ` [PATCH v3 1/6] worktree: new repo extension to manage worktree behaviors Nguyễn Thái Ngọc Duy
  2016-01-26 11:44     ` [PATCH v3 2/6] path.c: new (identical) list for worktree v1 Nguyễn Thái Ngọc Duy
@ 2016-01-26 11:44     ` Nguyễn Thái Ngọc Duy
  2016-01-26 11:44     ` [PATCH v3 4/6] worktree: new config file hierarchy Nguyễn Thái Ngọc Duy
                       ` (3 subsequent siblings)
  6 siblings, 0 replies; 53+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2016-01-26 11:44 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, max, git, Jens.Lehmann,
	Nguyễn Thái Ngọc Duy

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/gitrepository-layout.txt | 4 ++++
 path.c                                 | 1 +
 2 files changed, 5 insertions(+)

diff --git a/Documentation/gitrepository-layout.txt b/Documentation/gitrepository-layout.txt
index 577ee84..771e362 100644
--- a/Documentation/gitrepository-layout.txt
+++ b/Documentation/gitrepository-layout.txt
@@ -250,6 +250,10 @@ commondir::
 modules::
 	Contains the git-repositories of the submodules.
 
+common::
+	This directory is seen from all working directories. It is
+	meant to share files that all working directories can see.
+
 worktrees::
 	Contains administrative data for linked
 	working trees. Each subdirectory contains the working tree-related
diff --git a/path.c b/path.c
index 14adf5d..3b85968 100644
--- a/path.c
+++ b/path.c
@@ -124,6 +124,7 @@ static struct common_dir common_list_v0[] = {
 };
 
 static struct common_dir common_list_v1[] = {
+	{ 0, 1, 0, "common" },
 	{ 0, 1, 0, "branches" },
 	{ 0, 1, 0, "hooks" },
 	{ 0, 1, 0, "info" },
-- 
2.7.0.288.g1d8ad15

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v3 4/6] worktree: new config file hierarchy
  2016-01-26 11:44   ` [PATCH v3 " Nguyễn Thái Ngọc Duy
                       ` (2 preceding siblings ...)
  2016-01-26 11:44     ` [PATCH v3 3/6] worktree: share .git/common in v1 Nguyễn Thái Ngọc Duy
@ 2016-01-26 11:44     ` Nguyễn Thái Ngọc Duy
  2016-01-27 22:22       ` Junio C Hamano
  2016-01-26 11:44     ` [PATCH v3 5/6] config: select .git/common/config with --repo Nguyễn Thái Ngọc Duy
                       ` (2 subsequent siblings)
  6 siblings, 1 reply; 53+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2016-01-26 11:44 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, max, git, Jens.Lehmann,
	Nguyễn Thái Ngọc Duy

($C stands for $GIT_COMMON_DIR for the rest of the message)

In main worktree, we read these config files in this order:

1) system config
2) XDG config
3) user config
4) $GIT_DIR/config

Currently linked worktrees share the same config file at step 4 with
main worktree. The problem is, not all config variables can be
shared. We need per-repo vars and per-worktree ones.

With this patch, since worktree v1, the repo config file (or worktree
config file in multi worktree context) is no longer shared. Main
worktree reads $C/config.  Linked worktrees read $C/worktrees/xxx/config
and a new file, $C/worktrees/config. Sharing is done via this new
file. The read hierarchy for a worktree becomes

1) system config
2) XDG config
3) user config
4) $C/common/config
5) $C/worktrees/xxx/config (or $C/config for main worktree)

Compare to an alternative scheme where $C/config contains both shared
variables and main-worktree-only ones, this is a cleaner design.

* We do not have to check every single variable name to see if it's
  shared or per-worktree when reading config files.

* We do not enforce any particular variable split. If a variable
  is in $C/worktrees/config, it is shared. Putting core.worktree in
  $C/worktrees/config is punished the same way the variable is put in
  $HOME/.gitconfig, for example.

* We will provide a new "git config --repo" to access this new config
  file. In single-worktree context, or worktree v0, --repo is an alias
  of --local.

There is one problem though. We store worktree version in config file
and expect that all worktrees must share the same version (i.e. read
the same config file). But the share-ness of per-repo config files is
changed based on worktree version. Where do we put extensions.worktree
then?

Worktree version detection is tweaked a bit in this case. The presence
of $C/worktrees/config implies worktree version 1+. The lack of it
implies wortree version 0.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/config.txt               |  5 +++--
 Documentation/git-worktree.txt         |  8 ++++++-
 Documentation/gitrepository-layout.txt |  8 +++++++
 cache.h                                |  4 +++-
 config.c                               | 14 ++++++++++--
 path.c                                 |  1 -
 setup.c                                | 37 +++++++++++++++++++++++++------
 t/t2028-worktree-config.sh (new +x)    | 40 ++++++++++++++++++++++++++++++++++
 8 files changed, 103 insertions(+), 14 deletions(-)
 create mode 100755 t/t2028-worktree-config.sh

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 07f7a3b..5009d98 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -2,8 +2,9 @@ CONFIGURATION FILE
 ------------------
 
 The Git configuration file contains a number of variables that affect
-the Git commands' behavior. The `.git/config` file in each repository
-is used to store the configuration for that repository, and
+the Git commands' behavior. The files `.git/config` and
+`.git/common/config` (see linkgit:git-worktree.txt[1]) are each
+repository is used to store the configuration for that repository, and
 `$HOME/.gitconfig` is used to store a per-user configuration as
 fallback values for the `.git/config` file. The file `/etc/gitconfig`
 can be used to store a system-wide default configuration.
diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 048d7d6..0846f2a 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -111,7 +111,13 @@ WORKTREE VERSIONS AND MIGRATION
 Multiple worktree is still an experimental feature and evolving. Every
 time the behavior is changed, the "worktree version" is stepped
 up. Worktree version is stored as a configuration variable
-extensions.worktree.
+extensions.worktree. Latest version is one.
+
+Version 1
+~~~~~~~~~
+In this version, the repository config file `.git/config` is not
+shared anymore. A new file, `.git/common/config`, read for all
+worktrees. Shared configuration should be stored here.
 
 Version 0
 ~~~~~~~~~
diff --git a/Documentation/gitrepository-layout.txt b/Documentation/gitrepository-layout.txt
index 771e362..d65345d 100644
--- a/Documentation/gitrepository-layout.txt
+++ b/Documentation/gitrepository-layout.txt
@@ -261,6 +261,11 @@ worktrees::
 	$GIT_COMMON_DIR is set, in which case
 	"$GIT_COMMON_DIR/worktrees" will be used instead.
 
+common/config::
+	Repository specific configuration file. Note that if this file
+	is present, it must contain the variable extensions.worktree
+	whose value must be one or above.
+
 worktrees/<id>/gitdir::
 	A text file containing the absolute path back to the .git file
 	that points to here. This is used to check if the linked
@@ -280,6 +285,9 @@ worktrees/<id>/link::
 	file. It is used to detect if the linked repository is
 	manually removed.
 
+worktrees/<id>/config::
+	Working tree specific configuration file.
+
 SEE ALSO
 --------
 linkgit:git-init[1],
diff --git a/cache.h b/cache.h
index e742c46..fa5e451 100644
--- a/cache.h
+++ b/cache.h
@@ -1497,7 +1497,9 @@ extern void git_config(config_fn_t fn, void *);
 extern int git_config_with_options(config_fn_t fn, void *,
 				   struct git_config_source *config_source,
 				   int respect_includes);
-extern int git_config_early(config_fn_t fn, void *, const char *repo_config);
+extern int git_config_early(config_fn_t fn, void *,
+			    const char *repo_common_config,
+			    const char *repo_config);
 extern int git_parse_ulong(const char *, unsigned long *);
 extern int git_parse_maybe_bool(const char *);
 extern int git_config_int(const char *, const char *);
diff --git a/config.c b/config.c
index 86a5eb2..a75926e 100644
--- a/config.c
+++ b/config.c
@@ -1184,7 +1184,9 @@ int git_config_system(void)
 	return !git_env_bool("GIT_CONFIG_NOSYSTEM", 0);
 }
 
-int git_config_early(config_fn_t fn, void *data, const char *repo_config)
+int git_config_early(config_fn_t fn, void *data,
+		     const char *repo_common_config,
+		     const char *repo_config)
 {
 	int ret = 0, found = 0;
 	char *xdg_config = xdg_config_home("config");
@@ -1206,6 +1208,11 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)
 		found += 1;
 	}
 
+	if (repo_common_config && !access_or_die(repo_common_config, R_OK, 0)) {
+		ret += git_config_from_file(fn, repo_common_config, data);
+		found += 1;
+	}
+
 	if (repo_config && !access_or_die(repo_config, R_OK, 0)) {
 		ret += git_config_from_file(fn, repo_config, data);
 		found += 1;
@@ -1231,6 +1238,7 @@ int git_config_with_options(config_fn_t fn, void *data,
 			    struct git_config_source *config_source,
 			    int respect_includes)
 {
+	struct strbuf repo_common_config = STRBUF_INIT;
 	char *repo_config = NULL;
 	int ret;
 	struct config_include_data inc = CONFIG_INCLUDE_INIT;
@@ -1253,10 +1261,12 @@ int git_config_with_options(config_fn_t fn, void *data,
 	else if (config_source && config_source->blob)
 		return git_config_from_blob_ref(fn, config_source->blob, data);
 
+	strbuf_addf(&repo_common_config, "%s/common/config", get_git_common_dir());
 	repo_config = git_pathdup("config");
-	ret = git_config_early(fn, data, repo_config);
+	ret = git_config_early(fn, data, repo_common_config.buf, repo_config);
 	if (repo_config)
 		free(repo_config);
+	strbuf_release(&repo_common_config);
 	return ret;
 }
 
diff --git a/path.c b/path.c
index 3b85968..aee9f59 100644
--- a/path.c
+++ b/path.c
@@ -140,7 +140,6 @@ static struct common_dir common_list_v1[] = {
 	{ 0, 1, 0, "worktrees" },
 	{ 0, 1, 0, "rr-cache" },
 	{ 0, 1, 0, "svn" },
-	{ 0, 0, 0, "config" },
 	{ 1, 0, 0, "gc.pid" },
 	{ 0, 0, 0, "packed-refs" },
 	{ 0, 0, 0, "shallow" },
diff --git a/setup.c b/setup.c
index 2f41648..7ca8ebe 100644
--- a/setup.c
+++ b/setup.c
@@ -385,18 +385,32 @@ static int check_repo_format(const char *var, const char *value, void *cb)
 static int check_repository_format_gently(const char *gitdir, int *nongit_ok)
 {
 	struct strbuf sb = STRBUF_INIT;
+	struct strbuf sb2 = STRBUF_INIT;
+	struct strbuf sb3 = STRBUF_INIT;
 	const char *repo_config;
+	const char *repo_common_config;
 	config_fn_t fn;
-	int ret = 0;
+	int ret = 0, has_common_dir;
 
 	string_list_clear(&unknown_extensions, 0);
 
-	if (get_common_dir(&sb, gitdir))
-		fn = check_repo_format;
-	else
+	has_common_dir = get_common_dir(&sb, gitdir);
+	strbuf_addf(&sb2, "%s/common/config", sb.buf);
+
+	if (access(sb2.buf, F_OK) == -1) { /* worktree v0 */
+		if (has_common_dir)
+			fn = check_repo_format;
+		else
+			fn = check_repository_format_version;
+		strbuf_addf(&sb3, "%s/config", sb.buf);
+		repo_common_config = NULL;
+		repo_config = sb3.buf;
+	} else {
 		fn = check_repository_format_version;
-	strbuf_addstr(&sb, "/config");
-	repo_config = sb.buf;
+		strbuf_addf(&sb3, "%s/config", gitdir);
+		repo_common_config = sb2.buf;
+		repo_config = sb3.buf;
+	}
 
 	/*
 	 * git_config() can't be used here because it calls git_pathdup()
@@ -407,7 +421,7 @@ static int check_repository_format_gently(const char *gitdir, int *nongit_ok)
 	 * Use a gentler version of git_config() to check if this repo
 	 * is a good one.
 	 */
-	git_config_early(fn, NULL, repo_config);
+	git_config_early(fn, NULL, repo_common_config, repo_config);
 	if (GIT_REPO_VERSION_READ < repository_format_version) {
 		if (!nongit_ok)
 			die ("Expected git repo version <= %d, found %d",
@@ -433,7 +447,16 @@ static int check_repository_format_gently(const char *gitdir, int *nongit_ok)
 		ret = -1;
 	}
 
+	if (repo_common_config && repository_format_worktree_version < 1)
+		die(_("worktree version must be one minimum in the presence of %s"),
+		    repo_common_config);
+	if (!repo_common_config && repository_format_worktree_version > 0)
+		die(_("worktree version must be zero if %s/common/config does not exist"),
+		    gitdir);
+
 	strbuf_release(&sb);
+	strbuf_release(&sb2);
+	strbuf_release(&sb3);
 	return ret;
 }
 
diff --git a/t/t2028-worktree-config.sh b/t/t2028-worktree-config.sh
new file mode 100755
index 0000000..5561788
--- /dev/null
+++ b/t/t2028-worktree-config.sh
@@ -0,0 +1,40 @@
+#!/bin/sh
+
+test_description="config file in multi worktree"
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+	test_commit start &&
+	git worktree add wt1 &&
+	git worktree add wt2
+'
+
+test_expect_success 'main config is shared in version 0' '
+	git config -f .git/config wt.name main &&
+	git config wt.name >actual &&
+	echo main >expected &&
+	test_cmp expected actual &&
+	git -C wt1 config wt.name >actual &&
+	test_cmp expected actual
+'
+
+test_expect_success 'main config is for main worktree only (v1)' '
+	mkdir .git/common &&
+	git config -f .git/common/config extensions.worktree 1 &&
+	git config wt.name >actual &&
+	echo main >expected &&
+	test_cmp expected actual &&
+	test_must_fail git -C wt1 config wt.name
+'
+
+test_expect_success 'worktrees/config is shared (v1)' '
+	git config -f .git/common/config some.thing is-shared &&
+	echo is-shared >expected &&
+	git config some.thing >actual &&
+	test_cmp expected actual &&
+	git -C wt1 config some.thing >actual &&
+	test_cmp expected actual
+'
+
+test_done
-- 
2.7.0.288.g1d8ad15

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v3 5/6] config: select .git/common/config with --repo
  2016-01-26 11:44   ` [PATCH v3 " Nguyễn Thái Ngọc Duy
                       ` (3 preceding siblings ...)
  2016-01-26 11:44     ` [PATCH v3 4/6] worktree: new config file hierarchy Nguyễn Thái Ngọc Duy
@ 2016-01-26 11:44     ` Nguyễn Thái Ngọc Duy
  2016-01-30 22:10       ` Max Kirillov
  2016-01-26 11:44     ` [PATCH v3 6/6] worktree add: switch to worktree version 1 Nguyễn Thái Ngọc Duy
  2016-01-27 22:23     ` [PATCH v3 0/6] Split .git/config in multiple worktree setup Junio C Hamano
  6 siblings, 1 reply; 53+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2016-01-26 11:44 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, max, git, Jens.Lehmann,
	Nguyễn Thái Ngọc Duy

This new option allows the user to write to or read from
.git/common/config in worktree v1. In worktree v0, --repo is an alias
of --local.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/git-config.txt           | 14 +++++++++++++-
 Documentation/git-worktree.txt         |  4 ++++
 Documentation/gitrepository-layout.txt | 10 +++++-----
 builtin/config.c                       | 19 ++++++++++++++-----
 t/t2028-worktree-config.sh             | 23 ++++++++++++++++++++++-
 5 files changed, 58 insertions(+), 12 deletions(-)

diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt
index 2608ca7..79fd453 100644
--- a/Documentation/git-config.txt
+++ b/Documentation/git-config.txt
@@ -47,7 +47,7 @@ checks or transformations are performed on the value.
 
 When reading, the values are read from the system, global and
 repository local configuration files by default, and options
-'--system', '--global', '--local' and '--file <filename>' can be
+'--system', '--global', '--repo', '--local' and '--file <filename>' can be
 used to tell the command to read from only that location (see <<FILES>>).
 
 When writing, the new value is written to the repository local
@@ -125,6 +125,18 @@ rather than from all available files.
 +
 See also <<FILES>>.
 
+--repo::
+
+	For writing options: write to the repository file
+	`.git/config` if the configuration variable extensions.worktree
+	is not specified or has the value zero, `.git/worktrees/config`
+	otherwise.
++
+For reading options: read only from the same file rather than from all
+available files.
++
+See also <<FILES>>.
+
 --local::
 	For writing options: write to the repository `.git/config` file.
 	This is	the default behavior.
diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 0846f2a..6082d4d 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -119,6 +119,10 @@ In this version, the repository config file `.git/config` is not
 shared anymore. A new file, `.git/common/config`, read for all
 worktrees. Shared configuration should be stored here.
 
+Use "git config --repo" to store shared configuration variables. Use
+"git config --local" to store per-worktree ones. This works even in
+single-worktree mode.
+
 Version 0
 ~~~~~~~~~
 This is the first release. Version 0 is implied if extensions.worktree
diff --git a/Documentation/gitrepository-layout.txt b/Documentation/gitrepository-layout.txt
index d65345d..56175f0 100644
--- a/Documentation/gitrepository-layout.txt
+++ b/Documentation/gitrepository-layout.txt
@@ -254,6 +254,11 @@ common::
 	This directory is seen from all working directories. It is
 	meant to share files that all working directories can see.
 
+common/config::
+	Repository specific configuration file. Note that if this file
+	is present, it must contain the variable extensions.worktree
+	whose value must be one or above.
+
 worktrees::
 	Contains administrative data for linked
 	working trees. Each subdirectory contains the working tree-related
@@ -261,11 +266,6 @@ worktrees::
 	$GIT_COMMON_DIR is set, in which case
 	"$GIT_COMMON_DIR/worktrees" will be used instead.
 
-common/config::
-	Repository specific configuration file. Note that if this file
-	is present, it must contain the variable extensions.worktree
-	whose value must be one or above.
-
 worktrees/<id>/gitdir::
 	A text file containing the absolute path back to the .git file
 	that points to here. This is used to check if the linked
diff --git a/builtin/config.c b/builtin/config.c
index adc7727..6aecd13 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -21,7 +21,7 @@ static char delim = '=';
 static char key_delim = ' ';
 static char term = '\n';
 
-static int use_global_config, use_system_config, use_local_config;
+static int use_global_config, use_system_config, use_local_config, use_repo_config;
 static struct git_config_source given_config_source;
 static int actions, types;
 static const char *get_color_slot, *get_colorbool_slot;
@@ -54,7 +54,8 @@ static struct option builtin_config_options[] = {
 	OPT_GROUP(N_("Config file location")),
 	OPT_BOOL(0, "global", &use_global_config, N_("use global config file")),
 	OPT_BOOL(0, "system", &use_system_config, N_("use system config file")),
-	OPT_BOOL(0, "local", &use_local_config, N_("use repository config file")),
+	OPT_BOOL(0, "repo", &use_repo_config, N_("use per-repository config file")),
+	OPT_BOOL(0, "local", &use_local_config, N_("use per-worktree config file")),
 	OPT_STRING('f', "file", &given_config_source.file, N_("file"), N_("use given config file")),
 	OPT_STRING(0, "blob", &given_config_source.blob, N_("blob-id"), N_("read config from given blob object")),
 	OPT_GROUP(N_("Action")),
@@ -460,7 +461,8 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 			     PARSE_OPT_STOP_AT_NON_OPTION);
 
 	if (use_global_config + use_system_config + use_local_config +
-	    !!given_config_source.file + !!given_config_source.blob > 1) {
+	    !!given_config_source.file + !!given_config_source.blob > 1 +
+	    use_repo_config) {
 		error("only one config file at a time.");
 		usage_with_options(builtin_config_usage, builtin_config_options);
 	}
@@ -492,9 +494,16 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 	}
 	else if (use_system_config)
 		given_config_source.file = git_etc_gitconfig();
-	else if (use_local_config)
+	else if (use_local_config ||
+		 (use_repo_config &&
+		  repository_format_worktree_version == 0))
 		given_config_source.file = git_pathdup("config");
-	else if (given_config_source.file) {
+	else if (use_repo_config) {
+		struct strbuf sb = STRBUF_INIT;
+
+		strbuf_addf(&sb, "%s/common/config", get_git_common_dir());
+		given_config_source.file = strbuf_detach(&sb, NULL);
+	} else if (given_config_source.file) {
 		if (!is_absolute_path(given_config_source.file) && prefix)
 			given_config_source.file =
 				xstrdup(prefix_filename(prefix,
diff --git a/t/t2028-worktree-config.sh b/t/t2028-worktree-config.sh
index 5561788..d11b2ce 100755
--- a/t/t2028-worktree-config.sh
+++ b/t/t2028-worktree-config.sh
@@ -19,6 +19,15 @@ test_expect_success 'main config is shared in version 0' '
 	test_cmp expected actual
 '
 
+test_expect_success 'config --repo on v0' '
+	git config --global new.var old-value &&
+	git config --repo new.var new-value &&
+	test_path_is_missing .git/common/config &&
+	git config --repo new.var >actual &&
+	echo new-value >expected &&
+	test_cmp expected actual
+'
+
 test_expect_success 'main config is for main worktree only (v1)' '
 	mkdir .git/common &&
 	git config -f .git/common/config extensions.worktree 1 &&
@@ -28,7 +37,7 @@ test_expect_success 'main config is for main worktree only (v1)' '
 	test_must_fail git -C wt1 config wt.name
 '
 
-test_expect_success 'worktrees/config is shared (v1)' '
+test_expect_success 'common/config is shared (v1)' '
 	git config -f .git/common/config some.thing is-shared &&
 	echo is-shared >expected &&
 	git config some.thing >actual &&
@@ -37,4 +46,16 @@ test_expect_success 'worktrees/config is shared (v1)' '
 	test_cmp expected actual
 '
 
+test_expect_success 'config --repo on v1' '
+	git config --global new.var1 old-value &&
+	git config --repo new.var1 new-value &&
+	grep var1 .git/common/config >/dev/null &&
+	git config --repo new.var1 >actual &&
+	echo new-value >expected &&
+	test_cmp expected actual &&
+	git -C wt2 config --repo new.var1 >actual &&
+	echo new-value >expected &&
+	test_cmp expected actual
+'
+
 test_done
-- 
2.7.0.288.g1d8ad15

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v3 6/6] worktree add: switch to worktree version 1
  2016-01-26 11:44   ` [PATCH v3 " Nguyễn Thái Ngọc Duy
                       ` (4 preceding siblings ...)
  2016-01-26 11:44     ` [PATCH v3 5/6] config: select .git/common/config with --repo Nguyễn Thái Ngọc Duy
@ 2016-01-26 11:44     ` Nguyễn Thái Ngọc Duy
  2016-02-01  5:33       ` Max Kirillov
  2016-01-27 22:23     ` [PATCH v3 0/6] Split .git/config in multiple worktree setup Junio C Hamano
  6 siblings, 1 reply; 53+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2016-01-26 11:44 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, max, git, Jens.Lehmann,
	Nguyễn Thái Ngọc Duy

The most obvious use case is, "git worktree add" creates the first
linked worktree. In this case, we should be able to move to latest
worktree version. The following happens:

 - common/config is created with extensions.worktree 1 and
   core.repositoryformatversion 1

 - all config keys except a few per-worktree are moved to
   common/config

 - per-worktree keys stay with the main worktree's config file

 - the main worktree config file also has worktree version explicitly
   set to 1. This is to prevent older Git binaries from reading it.

What if the repo already has another linked worktree and the user
wants to stay at version 0, maybe because multiple git binaries can
access this repo? "worktree add --version=0" can be used, but it's
really not recommended to stay at lower (and buggy) version.

A note about core.bare staying per-worktree. On the surface it does
not make sense for core.bare to be worktree specific. It's made so in
order to "grow" new worktrees from a bare repo. In these new linked
worktrees, core.bare will be hidden away and worktree-related commands
won't complain about bare repository.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/git-worktree.txt |  9 +++-
 builtin/worktree.c             | 95 ++++++++++++++++++++++++++++++++++++++++++
 t/t2028-worktree-config.sh     | 47 ++++++++++++++++++++-
 3 files changed, 148 insertions(+), 3 deletions(-)

diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 6082d4d..0d7d523 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -9,7 +9,7 @@ git-worktree - Manage multiple working trees
 SYNOPSIS
 --------
 [verse]
-'git worktree add' [-f] [--detach] [-b <new-branch>] <path> [<branch>]
+'git worktree add' [-f] [--detach] [-b <new-branch>] [--version=<N>] <path> [<branch>]
 'git worktree prune' [-n] [-v] [--expire <expire>]
 'git worktree list' [--porcelain]
 
@@ -89,6 +89,13 @@ OPTIONS
 	With `add`, detach HEAD in the new working tree. See "DETACHED HEAD"
 	in linkgit:git-checkout[1].
 
+--version=<N>::
+	By default when a new working directory is added, worktree
+	layout is automatically migrated to latest version. This
+	option can be used to specify only migrate to the specified
+	version, or no migrate at all if it's already current worktree
+	version.
+
 -n::
 --dry-run::
 	With `prune`, do not remove anything; just report what it would
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 475b958..551fe37 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -140,6 +140,7 @@ static char *junk_work_tree;
 static char *junk_git_dir;
 static int is_junk;
 static pid_t junk_pid;
+static int target_version = 1;
 
 static void remove_junk(void)
 {
@@ -184,6 +185,93 @@ static const char *worktree_basename(const char *path, int *olen)
 	return name;
 }
 
+struct key_data {
+	const char *key;
+	char *value;
+};
+
+static int get_one_key(const char *key, const char *value, void *cb)
+{
+	struct key_data *kd = cb;
+
+	if (!strcmp(key, kd->key))
+		kd->value = xstrdup(value);
+
+	return 0;
+}
+
+static char *get_key(const char *file, const char *key)
+{
+	struct key_data kd;
+
+	kd.key = key;
+	kd.value = NULL;
+	if (git_config_from_file(get_one_key, file, &kd))
+		return NULL;
+	return kd.value;
+}
+
+static void migrate_worktree_layout(void)
+{
+	const char *per_wortree_keys[] = {
+		"core.bare",
+		"core.ignorestat",
+		"core.sparsecheckout",
+		"core.worktree",
+		NULL
+	};
+	struct strbuf sb = STRBUF_INIT;
+	const char **key_p;
+
+	switch (repository_format_worktree_version) {
+	case 0:
+		strbuf_addf(&sb, "%s/common", get_git_common_dir());
+		if (mkdir_in_gitdir(sb.buf))
+			die_errno(_("failed to create directory %s"), sb.buf);
+		if (repository_format_version < 1 &&
+		    git_config_set("core.repositoryformatversion", "1"))
+			die(_("failed to set core.repositoryformatversion to one"));
+		if (git_config_set("extensions.worktree", "1"))
+			die(_("failed to set extensions.worktree to one"));
+		strbuf_addstr(&sb, "/config");
+		if (rename(git_path("config"), sb.buf))
+			die_errno(_("failed to set move config file to %s"),
+				  sb.buf);
+		for (key_p = per_wortree_keys; *key_p; key_p++) {
+			const char *key = *key_p;
+			char *value = get_key(sb.buf, key);
+
+			if (value) {
+				if (git_config_set(key, value))
+					die(_("failed to keep %s in main worktree's config file"), key);
+				if (git_config_set_in_file(sb.buf, key, NULL))
+					die(_("failed to delete %s in shared config file"), key);
+				free(value);
+			}
+		}
+
+		/*
+		 * we're still in version 0 in this process, this will
+		 * create a new file $GIT_COMMON_DIR/config with only
+		 * one key, extensions.worktree. This will force old
+		 * git binaries that do not understand v1 to bail out.
+		 */
+		if (repository_format_version < 1 &&
+		    git_config_set("core.repositoryformatversion", "1"))
+			die(_("failed to set core.repositoryformatversion to one"));
+		if (git_config_set("extensions.worktree", "1"))
+			die(_("failed to set extensions.worktree to one"));
+
+		repository_format_worktree_version = 1;
+		break;
+	case 1:
+		break;
+	default:
+		die(_("unsupported worktree format version %d"),
+		    repository_format_worktree_version);
+	}
+}
+
 static int add_worktree(const char *path, const char *refname,
 			const struct add_opts *opts)
 {
@@ -297,6 +385,9 @@ static int add_worktree(const char *path, const char *refname,
 		free(junk_git_dir);
 		junk_work_tree = NULL;
 		junk_git_dir = NULL;
+
+		while (repository_format_worktree_version < target_version)
+			migrate_worktree_layout();
 	}
 done:
 	strbuf_reset(&sb);
@@ -322,6 +413,8 @@ static int add(int ac, const char **av, const char *prefix)
 		OPT_STRING('B', NULL, &new_branch_force, N_("branch"),
 			   N_("create or reset a branch")),
 		OPT_BOOL(0, "detach", &opts.detach, N_("detach HEAD at named commit")),
+		OPT_INTEGER(0, "version", &target_version,
+			   N_("stay at this worktree version")),
 		OPT_END()
 	};
 
@@ -331,6 +424,8 @@ static int add(int ac, const char **av, const char *prefix)
 		die(_("-b, -B, and --detach are mutually exclusive"));
 	if (ac < 1 || ac > 2)
 		usage_with_options(worktree_usage, options);
+	if (target_version < 0 || target_version > 1)
+		die(_("invalid worktree version %d"), target_version);
 
 	path = prefix ? prefix_filename(prefix, strlen(prefix), av[0]) : av[0];
 	branch = ac < 2 ? "HEAD" : av[1];
diff --git a/t/t2028-worktree-config.sh b/t/t2028-worktree-config.sh
index d11b2ce..0d4cb8e 100755
--- a/t/t2028-worktree-config.sh
+++ b/t/t2028-worktree-config.sh
@@ -6,8 +6,8 @@ test_description="config file in multi worktree"
 
 test_expect_success 'setup' '
 	test_commit start &&
-	git worktree add wt1 &&
-	git worktree add wt2
+	git worktree add --version=0 wt1 &&
+	git worktree add --version=0 wt2
 '
 
 test_expect_success 'main config is shared in version 0' '
@@ -58,4 +58,47 @@ test_expect_success 'config --repo on v1' '
 	test_cmp expected actual
 '
 
+test_expect_success 'prepare worktree v0' '
+	test_create_repo repo-v0 &&
+	(
+		cd repo-v0 &&
+		test_commit v0 &&
+		git config core.sparsecheckout true &&
+		git config core.ignorestat true &&
+		git config core.worktree "$TEST_DIRECTORY" &&
+		git config share.key value
+	)
+'
+
+test_expect_success 'migrate v0 to v1' '
+	git -C repo-v0 worktree add --version=1 wt
+'
+
+test_expect_success 'after migration: main wortree has extensions.worktree' '
+	test "`git -C repo-v0 config core.repositoryformatversion`" = 1 &&
+	test "`git -C repo-v0 config extensions.worktree`" = 1
+'
+
+test_expect_success 'after migration: linked wortree has extensions.worktree' '
+	test "`git -C repo-v0/wt config core.repositoryformatversion`" = 1 &&
+	test "`git -C repo-v0/wt config extensions.worktree`" = 1
+'
+
+test_expect_success 'after migration: main wortree keeps per-worktree vars' '
+	test "`git -C repo-v0 config core.sparsecheckout`" = true &&
+	test "`git -C repo-v0 config core.ignorestat`" = true &&
+	test "`git -C repo-v0 config core.worktree`" = "$TEST_DIRECTORY"
+'
+
+test_expect_success 'after migration: linked wortree has no per-worktree vars' '
+	test_must_fail git -C repo-v0/wt config core.sparsecheckout &&
+	test_must_fail git -C repo-v0/wt config core.ignorestat &&
+	test_must_fail git -C repo-v0/wt config core.worktree
+'
+
+test_expect_success 'after migration: shared vars are shared' '
+	test "`git -C repo-v0 config share.key`" = value &&
+	test "`git -C repo-v0/wt config share.key`" = value
+'
+
 test_done
-- 
2.7.0.288.g1d8ad15

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* Re: [PATCH v3 1/6] worktree: new repo extension to manage worktree behaviors
  2016-01-26 11:44     ` [PATCH v3 1/6] worktree: new repo extension to manage worktree behaviors Nguyễn Thái Ngọc Duy
@ 2016-01-27 22:12       ` Junio C Hamano
  2016-01-28 12:11         ` Duy Nguyen
                           ` (2 more replies)
  2016-01-30 13:59       ` Max Kirillov
  1 sibling, 3 replies; 53+ messages in thread
From: Junio C Hamano @ 2016-01-27 22:12 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy; +Cc: git, max, git, Jens.Lehmann

Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:

> Multiple worktree setup is still evolving and its behavior may be
> changed in future. But we do not want to break existing worktree

s/be changed/change/

> setups. A new set of extensions, worktree=X, is recognized to tell Git
> what multiple worktree "version" is being used so that Git can
> behavior accordingly.

s/behavior/behave/

> +WORKTREE VERSIONS AND MIGRATION
> +-------------------------------
> +Multiple worktree is still an experimental feature and evolving. Every
> +time the behavior is changed, the "worktree version" is stepped
> +up. Worktree version is stored as a configuration variable
> +extensions.worktree.

s/stepped up/incremented/

More seriously, are we confident that the overall worktree support
is mature enough by now that once we add an experimental feature X
at version 1, we can promise to keep maintaining it forever at
version N for any positive integer N?  I hate to sound overly
negative, but I am getting an impression that we are not quite
there, and it is still not ready for production use.

It would be beneficial both for us and our users if we can keep our
hand untied for at least several more releases to allow us try
various random experimental features, fully intending to drop any of
them if the ideas do not pan out.

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v3 2/6] path.c: new (identical) list for worktree v1
  2016-01-26 11:44     ` [PATCH v3 2/6] path.c: new (identical) list for worktree v1 Nguyễn Thái Ngọc Duy
@ 2016-01-27 22:18       ` Junio C Hamano
  2016-01-30 14:45       ` Max Kirillov
  1 sibling, 0 replies; 53+ messages in thread
From: Junio C Hamano @ 2016-01-27 22:18 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy; +Cc: git, max, git, Jens.Lehmann

Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:

> +static struct common_dir common_list_v1[] = {
> +	...
> +};
> +
> +static struct common_dir *get_common_list(void)
> +{
> +	switch (repository_format_worktree_version) {
> +	case 0: return common_list_v0;
> +	case 1: return common_list_v1;

Why not an array whose elements are these common_list_v$N[]
instead of "switch"?  I.e.

static struct common_dir **common_list_version[] = {
	common_list_v0,
        common_list_v1,
};

static struct common_dir *get_common_list(void)
{
	int i = repository_format_worktree_version;
	if (i < ARRAY_SIZE(common_list_version))
		return common_list_version[i];
	die("I dunno about version %d", i);
}

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v3 4/6] worktree: new config file hierarchy
  2016-01-26 11:44     ` [PATCH v3 4/6] worktree: new config file hierarchy Nguyễn Thái Ngọc Duy
@ 2016-01-27 22:22       ` Junio C Hamano
  2016-01-28 12:03         ` Duy Nguyen
  0 siblings, 1 reply; 53+ messages in thread
From: Junio C Hamano @ 2016-01-27 22:22 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy; +Cc: git, max, git, Jens.Lehmann

Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:

> ($C stands for $GIT_COMMON_DIR for the rest of the message)
>
> In main worktree, we read these config files in this order:
>
> 1) system config
> 2) XDG config
> 3) user config
> 4) $GIT_DIR/config
>
> Currently linked worktrees share the same config file at step 4 with
> main worktree. The problem is, not all config variables can be
> shared. We need per-repo vars and per-worktree ones.
>
> With this patch, since worktree v1, the repo config file (or worktree
> config file in multi worktree context) is no longer shared. Main
> worktree reads $C/config.  Linked worktrees read $C/worktrees/xxx/config
> and a new file, $C/worktrees/config. Sharing is done via this new
> file. The read hierarchy for a worktree becomes
>
> 1) system config
> 2) XDG config
> 3) user config
> 4) $C/common/config
> 5) $C/worktrees/xxx/config (or $C/config for main worktree)
>
> Compare to an alternative scheme where $C/config contains both shared
> variables and main-worktree-only ones, this is a cleaner design.
>
> * We do not have to check every single variable name to see if it's
>   shared or per-worktree when reading config files.
>
> * We do not enforce any particular variable split. If a variable
>   is in $C/worktrees/config, it is shared. Putting core.worktree in
>   $C/worktrees/config is punished the same way the variable is put in
>   $HOME/.gitconfig, for example.
>
> * We will provide a new "git config --repo" to access this new config
>   file. In single-worktree context, or worktree v0, --repo is an alias
>   of --local.
>
> There is one problem though. We store worktree version in config file
> and expect that all worktrees must share the same version (i.e. read
> the same config file). But the share-ness of per-repo config files is
> changed based on worktree version. Where do we put extensions.worktree
> then?

I cannot see why it cannot live in $C/common/config, which would be
read as the fourth alternative in your earlier enumeration.  What I
am missing?

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v3 0/6] Split .git/config in multiple worktree setup
  2016-01-26 11:44   ` [PATCH v3 " Nguyễn Thái Ngọc Duy
                       ` (5 preceding siblings ...)
  2016-01-26 11:44     ` [PATCH v3 6/6] worktree add: switch to worktree version 1 Nguyễn Thái Ngọc Duy
@ 2016-01-27 22:23     ` Junio C Hamano
  6 siblings, 0 replies; 53+ messages in thread
From: Junio C Hamano @ 2016-01-27 22:23 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy; +Cc: git, max, git, Jens.Lehmann

Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:

> For any worktree, the new file .git/common/config is read first, then
> either .git/config or .git/worktrees/xxx/config is read after. There's
> no special per-worktree var list any more. Which is great. You want to
> add per-worktree config vars, use "git config --local". You want to
> add per-repo config vars, use (new) "git config --repo". You put a
> variable in a wrong file, you're punished for it (and it's the same
> today, say if you put core.worktree to /etc/gitconfig).

I think this is saner than the one before.

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v3 4/6] worktree: new config file hierarchy
  2016-01-27 22:22       ` Junio C Hamano
@ 2016-01-28 12:03         ` Duy Nguyen
  2016-01-28 18:45           ` Junio C Hamano
  0 siblings, 1 reply; 53+ messages in thread
From: Duy Nguyen @ 2016-01-28 12:03 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Git Mailing List, Max A.K., Michael J Gruber, Jens Lehmann

On Thu, Jan 28, 2016 at 5:22 AM, Junio C Hamano <gitster@pobox.com> wrote:
>> With this patch, since worktree v1, the repo config file (or worktree
>> config file in multi worktree context) is no longer shared. Main
>> worktree reads $C/config.  Linked worktrees read $C/worktrees/xxx/config
>> and a new file, $C/worktrees/config. Sharing is done via this new
>> file. The read hierarchy for a worktree becomes
>>
>> 1) system config
>> 2) XDG config
>> 3) user config
>> 4) $C/common/config
>> 5) $C/worktrees/xxx/config (or $C/config for main worktree)
>>
>> Compare to an alternative scheme where $C/config contains both shared
>> variables and main-worktree-only ones, this is a cleaner design.
>>
>> * We do not have to check every single variable name to see if it's
>>   shared or per-worktree when reading config files.
>>
>> * We do not enforce any particular variable split. If a variable
>>   is in $C/worktrees/config, it is shared. Putting core.worktree in
>>   $C/worktrees/config is punished the same way the variable is put in
>>   $HOME/.gitconfig, for example.
>>
>> * We will provide a new "git config --repo" to access this new config
>>   file. In single-worktree context, or worktree v0, --repo is an alias
>>   of --local.
>>
>> There is one problem though. We store worktree version in config file
>> and expect that all worktrees must share the same version (i.e. read
>> the same config file). But the share-ness of per-repo config files is
>> changed based on worktree version. Where do we put extensions.worktree
>> then?
>
> I cannot see why it cannot live in $C/common/config, which would be
> read as the fourth alternative in your earlier enumeration.  What I
> am missing?

I wasn't clear. The last paragraph is about already released git
binaries, which does not care about $C/common/config. Suppose you add
a new worktree with new git binary, which will move common stuff out
of .git/config to common/config, on a shared repo. If the old binary
reads that repo, it does not see common config, but it does not know
where common config is either.
-- 
Duy

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v3 1/6] worktree: new repo extension to manage worktree behaviors
  2016-01-27 22:12       ` Junio C Hamano
@ 2016-01-28 12:11         ` Duy Nguyen
  2016-01-30 14:20         ` Max Kirillov
  2016-02-01 18:39         ` [PATCH v3 1/6] worktree: new repo extension to manage worktree behaviors Dennis Kaarsemaker
  2 siblings, 0 replies; 53+ messages in thread
From: Duy Nguyen @ 2016-01-28 12:11 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Git Mailing List, Max A.K., Michael J Gruber, Jens Lehmann

On Thu, Jan 28, 2016 at 5:12 AM, Junio C Hamano <gitster@pobox.com> wrote:
>> +WORKTREE VERSIONS AND MIGRATION
>> +-------------------------------
>> +Multiple worktree is still an experimental feature and evolving. Every
>> +time the behavior is changed, the "worktree version" is stepped
>> +up. Worktree version is stored as a configuration variable
>> +extensions.worktree.
>
> s/stepped up/incremented/
>
> More seriously, are we confident that the overall worktree support
> is mature enough by now that once we add an experimental feature X
> at version 1, we can promise to keep maintaining it forever at
> version N for any positive integer N?  I hate to sound overly
> negative, but I am getting an impression that we are not quite
> there, and it is still not ready for production use.

I completely overlooked this config file issue in the first round, so
there's a good chance I will fail to realize it's still incomplete
again.

> It would be beneficial both for us and our users if we can keep our
> hand untied for at least several more releases to allow us try
> various random experimental features, fully intending to drop any of
> them if the ideas do not pan out.

Yes it's best if we can somehow communicate with the users about that.
If a line or two in release announcement is good enough, great.
Otherwise maybe print a line every time the user executes "git
worktree"?
-- 
Duy

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v3 4/6] worktree: new config file hierarchy
  2016-01-28 12:03         ` Duy Nguyen
@ 2016-01-28 18:45           ` Junio C Hamano
  2016-02-01  5:09             ` Duy Nguyen
  0 siblings, 1 reply; 53+ messages in thread
From: Junio C Hamano @ 2016-01-28 18:45 UTC (permalink / raw)
  To: Duy Nguyen, Git Mailing List, Max A.K., Michael J Gruber, Jens Lehmann

Duy Nguyen <pclouds@gmail.com> writes:

>> I cannot see why it cannot live in $C/common/config, which would be
>> read as the fourth alternative in your earlier enumeration.  What I
>> am missing?
>
> I wasn't clear. The last paragraph is about already released git
> binaries, which does not care about $C/common/config. Suppose you add
> a new worktree with new git binary, which will move common stuff out
> of .git/config to common/config, on a shared repo. If the old binary
> reads that repo, it does not see common config, but it does not know
> where common config is either.

Ah, OK.

Would it make it simpler to invent a specific value for 'xxx' that
denotes the main worktree (hence $C/worktrees/xxx/config will always
be read by worktrees including the primary one), not to add
$C/common/ anything, and use $C/config as the common one instead?

Then the repository format version can live in $C/config that would
be noticed by existing versions of Git.

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v3 1/6] worktree: new repo extension to manage worktree behaviors
  2016-01-26 11:44     ` [PATCH v3 1/6] worktree: new repo extension to manage worktree behaviors Nguyễn Thái Ngọc Duy
  2016-01-27 22:12       ` Junio C Hamano
@ 2016-01-30 13:59       ` Max Kirillov
  1 sibling, 0 replies; 53+ messages in thread
From: Max Kirillov @ 2016-01-30 13:59 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy
  Cc: git, Junio C Hamano, max, git, Jens.Lehmann

On Tue, Jan 26, 2016 at 06:44:40PM +0700, Nguyễn Thái Ngọc Duy wrote:
> +WORKTREE VERSIONS AND MIGRATION
> +-------------------------------
> +Multiple worktree is still an experimental feature and evolving. Every
> +time the behavior is changed, the "worktree version" is stepped
> +up. Worktree version is stored as a configuration variable
> +extensions.worktree.
> +
> +Version 0
> +~~~~~~~~~
> +This is the first release. Version 0 is implied if extensions.worktree
> +does not exist.
> +

...

> +`worktree`
> +~~~~~~~~~~
> +
> +Define behavior in multiple worktree setup. The value specifies the
> +version. Default version is zero.

This sounds too pessimistic. There is now a need to
introduce incompatible change, because there is no way to
make config separation. There would be a need to increase
the version regularly in case of previous option which
suggested to hardcode per-worktree versions, so that each
change of their list would need a version increase. Now
there is no need to increase the version beyond 1, so it can
be "version 0 is like in older gits, version 1 is separated
config file, and version 2 will never happen" :) The
extension parameter coould even be called like
"worktreeConfig" and be boolean.

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v3 1/6] worktree: new repo extension to manage worktree behaviors
  2016-01-27 22:12       ` Junio C Hamano
  2016-01-28 12:11         ` Duy Nguyen
@ 2016-01-30 14:20         ` Max Kirillov
  2016-01-31 16:42           ` Junio C Hamano
  2016-02-01 18:39         ` [PATCH v3 1/6] worktree: new repo extension to manage worktree behaviors Dennis Kaarsemaker
  2 siblings, 1 reply; 53+ messages in thread
From: Max Kirillov @ 2016-01-30 14:20 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Nguyễn Thái Ngọc Duy, git, max, git, Jens.Lehmann

On Wed, Jan 27, 2016 at 02:12:52PM -0800, Junio C Hamano wrote:
> More seriously, are we confident that the overall worktree support
> is mature enough by now that once we add an experimental feature X
> at version 1, we can promise to keep maintaining it forever at
> version N for any positive integer N?  I hate to sound overly
> negative, but I am getting an impression that we are not quite
> there, and it is still not ready for production use.

The worktree feature has been used by several people
already (me included), and do far the only issue which
requires change in repository layout is the config
separation. Isn't it enough to be confident?

As I noted in another email, I would not expect to be N>2
soon. At least not more likely than incompatible change
because of some other reason. And the support for an older
version can be as little as one-time upgrade to the current
N (preferably with confirmation from user).

> It would be beneficial both for us and our users if we can keep our
> hand untied for at least several more releases to allow us try
> various random experimental features, fully intending to drop any of
> them if the ideas do not pan out.

Users definitely would not benefit if there is release
feature with note "anything you do can be lost after you
install next version of git"

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v3 2/6] path.c: new (identical) list for worktree v1
  2016-01-26 11:44     ` [PATCH v3 2/6] path.c: new (identical) list for worktree v1 Nguyễn Thái Ngọc Duy
  2016-01-27 22:18       ` Junio C Hamano
@ 2016-01-30 14:45       ` Max Kirillov
  1 sibling, 0 replies; 53+ messages in thread
From: Max Kirillov @ 2016-01-30 14:45 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy
  Cc: git, Junio C Hamano, max, git, Jens.Lehmann

On Tue, Jan 26, 2016 at 06:44:41PM +0700, Nguyễn Thái Ngọc Duy wrote:
> Worktree v1 may have different .git file split than v0. Add support
> code to change common file list based on extensions.worktree. The list
> for now is identical to v0.

In the end this turned out to be needed only for "common"
which is not strictly necessary, as Junio pointed out, and
anyway could be done for v0 as well because "common" is not
used to be used before. So probably it is not needed at all.

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v3 5/6] config: select .git/common/config with --repo
  2016-01-26 11:44     ` [PATCH v3 5/6] config: select .git/common/config with --repo Nguyễn Thái Ngọc Duy
@ 2016-01-30 22:10       ` Max Kirillov
  2016-02-01  5:15         ` Duy Nguyen
  0 siblings, 1 reply; 53+ messages in thread
From: Max Kirillov @ 2016-01-30 22:10 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy
  Cc: git, Junio C Hamano, max, git, Jens.Lehmann

On Tue, Jan 26, 2016 at 06:44:44PM +0700, Nguyễn Thái Ngọc Duy wrote:
> This new option allows the user to write to or read from
> .git/common/config in worktree v1. In worktree v0, --repo is an alias
> of --local.

Looks like by default a value is always set in a local
config, which might be dangerous for remote.* or gc.*
parameters, for example. I think that even if reading is
done uniformly setting could depend on the actual variable
being set if no location specified.

>  	if (use_global_config + use_system_config + use_local_config +
> -	    !!given_config_source.file + !!given_config_source.blob > 1) {
> +	    !!given_config_source.file + !!given_config_source.blob > 1 +
> +	    use_repo_config) {
>  		error("only one config file at a time.");

Shouldn't "+ use_repo_config" do here to the left part of
comparison?

-- 
Max

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v3 1/6] worktree: new repo extension to manage worktree behaviors
  2016-01-30 14:20         ` Max Kirillov
@ 2016-01-31 16:42           ` Junio C Hamano
  2016-02-01  2:41             ` Stefan Monnier
  0 siblings, 1 reply; 53+ messages in thread
From: Junio C Hamano @ 2016-01-31 16:42 UTC (permalink / raw)
  To: Max Kirillov
  Cc: Nguyễn Thái Ngọc Duy, git, git, Jens.Lehmann

Max Kirillov <max@max630.net> writes:

> The worktree feature has been used by several people
> already (me included), and do far the only issue which
> requires change in repository layout is the config
> separation. Isn't it enough to be confident?

One lessor key phrase above is "so far", I think, and another one
you forgot to use is s/which requires/that we know &/, which to me
is a more serious one.  IOW, I do think it is premature for us to
say that that config split issue is the only thing, or to say that
the issue is best solved by changing the layout in the way being
discussed; the multiple-worktree feature needs more lab experience
for us to gain confidence.

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v3 1/6] worktree: new repo extension to manage worktree behaviors
  2016-01-31 16:42           ` Junio C Hamano
@ 2016-02-01  2:41             ` Stefan Monnier
  2016-02-01  2:47               ` Stefan Monnier
  2016-02-01  5:23               ` Duy Nguyen
  0 siblings, 2 replies; 53+ messages in thread
From: Stefan Monnier @ 2016-02-01  2:41 UTC (permalink / raw)
  To: git

> One lessor key phrase above is "so far", I think, and another one
> you forgot to use is s/which requires/that we know &/, which to me
> is a more serious one.  IOW, I do think it is premature for us to
> say that that config split issue is the only thing, or to say that
> the issue is best solved by changing the layout in the way being
> discussed; the multiple-worktree feature needs more lab experience
> for us to gain confidence.

As a heavy user of the git-new-worktree "hack / script", is there
something I can do to help "get more experience"?


        Stefan

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v3 1/6] worktree: new repo extension to manage worktree behaviors
  2016-02-01  2:41             ` Stefan Monnier
@ 2016-02-01  2:47               ` Stefan Monnier
  2016-02-01  5:23               ` Duy Nguyen
  1 sibling, 0 replies; 53+ messages in thread
From: Stefan Monnier @ 2016-02-01  2:47 UTC (permalink / raw)
  To: git

> As a heavy user of the git-new-worktree "hack / script", is there
                         ^^^^^^^^^^^^^^^^
                         git-new-workdir
Sorry,


        Stefan

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v3 4/6] worktree: new config file hierarchy
  2016-01-28 18:45           ` Junio C Hamano
@ 2016-02-01  5:09             ` Duy Nguyen
  0 siblings, 0 replies; 53+ messages in thread
From: Duy Nguyen @ 2016-02-01  5:09 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Git Mailing List, Max A.K., Michael J Gruber, Jens Lehmann

On Fri, Jan 29, 2016 at 1:45 AM, Junio C Hamano <gitster@pobox.com> wrote:
> Would it make it simpler to invent a specific value for 'xxx' that
> denotes the main worktree (hence $C/worktrees/xxx/config will always
> be read by worktrees including the primary one), not to add
> $C/common/ anything, and use $C/config as the common one instead?
>
> Then the repository format version can live in $C/config that would
> be noticed by existing versions of Git.

I can read this in two ways. In the first way, we still have $C as a
.git _directory_ that contains no worktree stuff because those files
are in $C/worktrees/main. When we detect .git directory we need to
decide if it this is worktree v1 and redirect $GIT_DIR to
$C/worktrees/main, otherwise keep $GIT_DIR as $C. This messes up setup
code a lot (I tried).

The other way, probably a bit deviated from your intention, is, we
only support two modes: either all worktrees are in $C/worktrees
(multiple worktree mode), or there's only one worktree at .git (single
worktree mode). In other words, there's no mixing main and linked
worktrees. The user will be forced to convert the main worktree to
linked worktree when they want to add a another tree. The backward
compatibility issue with worktree v0 is gone.

The transition between two modes can be done via "git worktree move".
This command can move any worktree, including the main one. Main
worktree is converted when it's moved (.git directory remains where it
is). "worktree move" can also move repository directory, which also
automatically convert main worktree to $C/worktrees/something. If the
user deletes all worktrees except one, they can move the repo back to
worktree's root, which converts it back to the single worktree mode.

Hmm?
-- 
Duy

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v3 5/6] config: select .git/common/config with --repo
  2016-01-30 22:10       ` Max Kirillov
@ 2016-02-01  5:15         ` Duy Nguyen
  0 siblings, 0 replies; 53+ messages in thread
From: Duy Nguyen @ 2016-02-01  5:15 UTC (permalink / raw)
  To: Max Kirillov
  Cc: Git Mailing List, Junio C Hamano, Michael J Gruber, Jens Lehmann

On Sun, Jan 31, 2016 at 5:10 AM, Max Kirillov <max@max630.net> wrote:
> On Tue, Jan 26, 2016 at 06:44:44PM +0700, Nguyễn Thái Ngọc Duy wrote:
>> This new option allows the user to write to or read from
>> .git/common/config in worktree v1. In worktree v0, --repo is an alias
>> of --local.
>
> Looks like by default a value is always set in a local
> config, which might be dangerous for remote.* or gc.*
> parameters, for example. I think that even if reading is
> done uniformly setting could depend on the actual variable
> being set if no location specified.

I grepped "git config" in scripts to see if we need to change any to
use --repo, but I forgot about builtin commands. git-remote needs to
store remote.* in the shared config file instead.

gc.* and others are set manually by the user, so they decide. We can
have a user-controlled filter that catches certain variables and
suggests they are stored in shared config instead, but this is
optional.
-- 
Duy

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v3 1/6] worktree: new repo extension to manage worktree behaviors
  2016-02-01  2:41             ` Stefan Monnier
  2016-02-01  2:47               ` Stefan Monnier
@ 2016-02-01  5:23               ` Duy Nguyen
  2016-02-01 18:19                 ` Junio C Hamano
  2016-02-04 18:12                 ` git worktree (was: [PATCH v3 1/6] worktree: new repo extension to manage worktree behaviors) Stefan Monnier
  1 sibling, 2 replies; 53+ messages in thread
From: Duy Nguyen @ 2016-02-01  5:23 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Git Mailing List

On Mon, Feb 1, 2016 at 9:41 AM, Stefan Monnier <monnier@iro.umontreal.ca> wrote:
>> One lessor key phrase above is "so far", I think, and another one
>> you forgot to use is s/which requires/that we know &/, which to me
>> is a more serious one.  IOW, I do think it is premature for us to
>> say that that config split issue is the only thing, or to say that
>> the issue is best solved by changing the layout in the way being
>> discussed; the multiple-worktree feature needs more lab experience
>> for us to gain confidence.
>
> As a heavy user of the git-new-worktree "hack / script", is there
> something I can do to help "get more experience"?

You can try out "git worktree" command (in "lab" environment) and see
what's missing, what use cases of yours it does not support.
-- 
Duy

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v3 6/6] worktree add: switch to worktree version 1
  2016-01-26 11:44     ` [PATCH v3 6/6] worktree add: switch to worktree version 1 Nguyễn Thái Ngọc Duy
@ 2016-02-01  5:33       ` Max Kirillov
  2016-02-01  6:05         ` Duy Nguyen
  0 siblings, 1 reply; 53+ messages in thread
From: Max Kirillov @ 2016-02-01  5:33 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy
  Cc: git, Junio C Hamano, max, git, Jens.Lehmann

On Tue, Jan 26, 2016 at 06:44:45PM +0700, Nguyễn Thái Ngọc Duy wrote:
> +		for (key_p = per_wortree_keys; *key_p; key_p++) {
> +			const char *key = *key_p;
> +			char *value = get_key(sb.buf, key);
> +
> +			if (value) {
> +				if (git_config_set(key, value))
> +					die(_("failed to keep %s in main worktree's config file"), key);
> +				if (git_config_set_in_file(sb.buf, key, NULL))
> +					die(_("failed to delete %s in shared config file"), key);
> +				free(value);
> +			}
> +		}

1. For submodules (which must be left per-worktree) this
approach is not going to work, because you don't know all
variables in advance. You could scan the config file and
match those actual keys which are there with patterns.

2. This migrates variables to the default (or current?)
worktree, what about others existing?

-- 
Max

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v3 6/6] worktree add: switch to worktree version 1
  2016-02-01  5:33       ` Max Kirillov
@ 2016-02-01  6:05         ` Duy Nguyen
  2016-02-02  5:35           ` Max Kirillov
  0 siblings, 1 reply; 53+ messages in thread
From: Duy Nguyen @ 2016-02-01  6:05 UTC (permalink / raw)
  To: Max Kirillov
  Cc: Git Mailing List, Junio C Hamano, Michael J Gruber, Jens Lehmann

On Mon, Feb 1, 2016 at 12:33 PM, Max Kirillov <max@max630.net> wrote:
> On Tue, Jan 26, 2016 at 06:44:45PM +0700, Nguyễn Thái Ngọc Duy wrote:
>> +             for (key_p = per_wortree_keys; *key_p; key_p++) {
>> +                     const char *key = *key_p;
>> +                     char *value = get_key(sb.buf, key);
>> +
>> +                     if (value) {
>> +                             if (git_config_set(key, value))
>> +                                     die(_("failed to keep %s in main worktree's config file"), key);
>> +                             if (git_config_set_in_file(sb.buf, key, NULL))
>> +                                     die(_("failed to delete %s in shared config file"), key);
>> +                             free(value);
>> +                     }
>> +             }
>
> 1. For submodules (which must be left per-worktree) this
> approach is not going to work, because you don't know all
> variables in advance. You could scan the config file and
> match those actual keys which are there with patterns.

Hmm.. we could keep existing submodule.* per-worktree. New variables
are per-worktree by default, unless you do "git config --repo" in
git-submodule.sh. Am I missing something?

> 2. This migrates variables to the default (or current?)
> worktree, what about others existing?

In v0, $C/config contains all shared variables, once we move these
shared vars to $C/common/config, they will be visible to all other
worktrees. Or do you replicate per-worktree vars in $C/config to all
worktrees ?
-- 
Duy

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v3 1/6] worktree: new repo extension to manage worktree behaviors
  2016-02-01  5:23               ` Duy Nguyen
@ 2016-02-01 18:19                 ` Junio C Hamano
  2016-02-04 18:12                 ` git worktree (was: [PATCH v3 1/6] worktree: new repo extension to manage worktree behaviors) Stefan Monnier
  1 sibling, 0 replies; 53+ messages in thread
From: Junio C Hamano @ 2016-02-01 18:19 UTC (permalink / raw)
  To: Duy Nguyen; +Cc: Stefan Monnier, Git Mailing List

Duy Nguyen <pclouds@gmail.com> writes:

> On Mon, Feb 1, 2016 at 9:41 AM, Stefan Monnier <monnier@iro.umontreal.ca> wrote:
>>> One lessor key phrase above is "so far", I think, and another one
>>> you forgot to use is s/which requires/that we know &/, which to me
>>> is a more serious one.  IOW, I do think it is premature for us to
>>> say that that config split issue is the only thing, or to say that
>>> the issue is best solved by changing the layout in the way being
>>> discussed; the multiple-worktree feature needs more lab experience
>>> for us to gain confidence.
>>
>> As a heavy user of the git-new-worktree "hack / script", is there
>> something I can do to help "get more experience"?
>
> You can try out "git worktree" command (in "lab" environment) and see
> what's missing, what use cases of yours it does not support.

Yup, that would be very helpful.

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v3 1/6] worktree: new repo extension to manage worktree behaviors
  2016-01-27 22:12       ` Junio C Hamano
  2016-01-28 12:11         ` Duy Nguyen
  2016-01-30 14:20         ` Max Kirillov
@ 2016-02-01 18:39         ` Dennis Kaarsemaker
  2 siblings, 0 replies; 53+ messages in thread
From: Dennis Kaarsemaker @ 2016-02-01 18:39 UTC (permalink / raw)
  To: Junio C Hamano, Nguyễn Thái Ngọc Duy
  Cc: git, max, git, Jens.Lehmann

On wo, 2016-01-27 at 14:12 -0800, Junio C Hamano wrote:

> More seriously, are we confident that the overall worktree support
> is mature enough by now that once we add an experimental feature X
> at version 1, we can promise to keep maintaining it forever at
> version N for any positive integer N?  I hate to sound overly
> negative, but I am getting an impression that we are not quite
> there, and it is still not ready for production use.
> 
> It would be beneficial both for us and our users if we can keep our
> hand untied for at least several more releases to allow us try
> various random experimental features, fully intending to drop any of
> them if the ideas do not pan out.

So far I have two use cases for separate worktrees and am a happy user:

- A CI setup that tries to avoid cloning a repository too often. It
  does N independent tasks in parallel in separate worktrees. This
  checks out the same commit multiple times in multiple worktrees.

- Quickly checking out another branch/commit without first having to
  stash all uncommitted work.

Neither of those require much specialness, so I'm more than happy to
see things change for the better as we find out more of the edge cases.
One thing that may benefit especially the former is a 'git worktree rm'
which removes the worktree (iff there are no local changes) and prunes
it, but nothing in the current implementation or proposed changes will
stop the addition of that.

-- 
Dennis Kaarsemaker
www.kaarsemaker.net

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v3 6/6] worktree add: switch to worktree version 1
  2016-02-01  6:05         ` Duy Nguyen
@ 2016-02-02  5:35           ` Max Kirillov
  0 siblings, 0 replies; 53+ messages in thread
From: Max Kirillov @ 2016-02-02  5:35 UTC (permalink / raw)
  To: Duy Nguyen
  Cc: Max Kirillov, Git Mailing List, Junio C Hamano, Michael J Gruber,
	Jens Lehmann

On Mon, Feb 01, 2016 at 01:05:05PM +0700, Duy Nguyen wrote:
> On Mon, Feb 1, 2016 at 12:33 PM, Max Kirillov <max@max630.net> wrote:
>> 1. For submodules (which must be left per-worktree) this
>> approach is not going to work, because you don't know all
>> variables in advance. You could scan the config file and
>> match those actual keys which are there with patterns.

> Hmm.. we could keep existing submodule.* per-worktree. New variables
> are per-worktree by default, unless you do "git config --repo" in
> git-submodule.sh. Am I missing something?

Submodules in new worktree should be not initialized, and as
far as I understand this means that submodule variables
should be removed from common config.

I used test from
http://article.gmane.org/gmane.comp.version-control.git/266621
to verify expectations for submodules.

>> 2. This migrates variables to the default (or current?)
>> worktree, what about others existing?
> 
> In v0, $C/config contains all shared variables, once we move these
> shared vars to $C/common/config, they will be visible to all other
> worktrees. Or do you replicate per-worktree vars in $C/config to all
> worktrees ?

If would make sense for some variables definitely. For
example, the submodule related variables.

-- 
Max

^ permalink raw reply	[flat|nested] 53+ messages in thread

* git worktree (was: [PATCH v3 1/6] worktree: new repo extension to manage worktree behaviors)
  2016-02-01  5:23               ` Duy Nguyen
  2016-02-01 18:19                 ` Junio C Hamano
@ 2016-02-04 18:12                 ` Stefan Monnier
  1 sibling, 0 replies; 53+ messages in thread
From: Stefan Monnier @ 2016-02-04 18:12 UTC (permalink / raw)
  To: git

>> As a heavy user of the git-new-worktree "hack / script", is there
>> something I can do to help "get more experience"?
> You can try out "git worktree" command (in "lab" environment) and see
> what's missing, what use cases of yours it does not support.

Cool, didn't know about it, and it's even already in Debian testing!
Using it right now.  So far so good,


        Stefan

^ permalink raw reply	[flat|nested] 53+ messages in thread

end of thread, other threads:[~2016-02-04 18:12 UTC | newest]

Thread overview: 53+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-12-02 19:13 [PATCH 0/5] Split .git/config in multiple worktree setup Nguyễn Thái Ngọc Duy
2015-12-02 19:13 ` [PATCH 1/5] dir.c: clean the entire struct in clear_exclude_list() Nguyễn Thái Ngọc Duy
2015-12-02 19:13 ` [PATCH 2/5] config.c: move worktree-specific variables to .git/worktrees/ Nguyễn Thái Ngọc Duy
2015-12-06  7:47   ` Eric Sunshine
2015-12-06 10:22     ` Duy Nguyen
2015-12-02 19:13 ` [PATCH 3/5] setup.c: remove special case of core.worktree and core.bare Nguyễn Thái Ngọc Duy
2015-12-02 19:13 ` [PATCH 4/5] worktree: make core.sparseCheckout and core.ignoreStat per-worktree Nguyễn Thái Ngọc Duy
2015-12-02 19:13 ` [PATCH 5/5] git-worktree.txt: mention about the config file split Nguyễn Thái Ngọc Duy
2015-12-06  8:02   ` Eric Sunshine
2015-12-03  6:15 ` [PATCH 0/5] Split .git/config in multiple worktree setup Max Kirillov
2015-12-03  8:07   ` Duy Nguyen
2015-12-03 19:52     ` Junio C Hamano
2015-12-03 21:00       ` Max Kirillov
2015-12-03 20:53     ` Max Kirillov
2015-12-04 15:57       ` Duy Nguyen
2015-12-27  3:14 ` [PATCH v2 0/6] " Nguyễn Thái Ngọc Duy
2015-12-27  3:14   ` [PATCH v2 1/6] Define new repo extension to manage multiple worktree behaviors Nguyễn Thái Ngọc Duy
2015-12-27  3:14   ` [PATCH v2 2/6] config.c: move worktree-specific variables to .git/worktrees/ Nguyễn Thái Ngọc Duy
2015-12-27  3:14   ` [PATCH v2 3/6] setup.c: remove special case of core.worktree and core.bare Nguyễn Thái Ngọc Duy
2015-12-27  3:14   ` [PATCH v2 4/6] worktree: make core.sparseCheckout and core.ignoreStat per-worktree Nguyễn Thái Ngọc Duy
2015-12-27  3:14   ` [PATCH v2 5/6] config.c: allow to un-share certain config in multi-worktree setup Nguyễn Thái Ngọc Duy
2015-12-27  3:14   ` [PATCH v2 6/6] worktree: bump worktree version to 1 on "worktree add" Nguyễn Thái Ngọc Duy
2016-01-11 22:43   ` [PATCH v2 0/6] Split .git/config in multiple worktree setup Max Kirillov
2016-01-26 11:44   ` [PATCH v3 " Nguyễn Thái Ngọc Duy
2016-01-26 11:44     ` [PATCH v3 1/6] worktree: new repo extension to manage worktree behaviors Nguyễn Thái Ngọc Duy
2016-01-27 22:12       ` Junio C Hamano
2016-01-28 12:11         ` Duy Nguyen
2016-01-30 14:20         ` Max Kirillov
2016-01-31 16:42           ` Junio C Hamano
2016-02-01  2:41             ` Stefan Monnier
2016-02-01  2:47               ` Stefan Monnier
2016-02-01  5:23               ` Duy Nguyen
2016-02-01 18:19                 ` Junio C Hamano
2016-02-04 18:12                 ` git worktree (was: [PATCH v3 1/6] worktree: new repo extension to manage worktree behaviors) Stefan Monnier
2016-02-01 18:39         ` [PATCH v3 1/6] worktree: new repo extension to manage worktree behaviors Dennis Kaarsemaker
2016-01-30 13:59       ` Max Kirillov
2016-01-26 11:44     ` [PATCH v3 2/6] path.c: new (identical) list for worktree v1 Nguyễn Thái Ngọc Duy
2016-01-27 22:18       ` Junio C Hamano
2016-01-30 14:45       ` Max Kirillov
2016-01-26 11:44     ` [PATCH v3 3/6] worktree: share .git/common in v1 Nguyễn Thái Ngọc Duy
2016-01-26 11:44     ` [PATCH v3 4/6] worktree: new config file hierarchy Nguyễn Thái Ngọc Duy
2016-01-27 22:22       ` Junio C Hamano
2016-01-28 12:03         ` Duy Nguyen
2016-01-28 18:45           ` Junio C Hamano
2016-02-01  5:09             ` Duy Nguyen
2016-01-26 11:44     ` [PATCH v3 5/6] config: select .git/common/config with --repo Nguyễn Thái Ngọc Duy
2016-01-30 22:10       ` Max Kirillov
2016-02-01  5:15         ` Duy Nguyen
2016-01-26 11:44     ` [PATCH v3 6/6] worktree add: switch to worktree version 1 Nguyễn Thái Ngọc Duy
2016-02-01  5:33       ` Max Kirillov
2016-02-01  6:05         ` Duy Nguyen
2016-02-02  5:35           ` Max Kirillov
2016-01-27 22:23     ` [PATCH v3 0/6] Split .git/config in multiple worktree setup Junio C Hamano

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.