{"thread":{"id":"40920","subject":"[PATCH 1/5] dir.c: clean the entire struct in clear_exclude_list()","startedAt":"2015-12-02T19:13:41Z","lastAt":"2016-02-04T18:12:11Z","messageCount":53,"participants":["Nguyễn Thái Ngọc Duy","Max Kirillov","Duy Nguyen","Junio C Hamano","Eric Sunshine","Stefan Monnier","Dennis Kaarsemaker"],"isPatch":true,"patchVersion":1,"patchTotal":5},"messages":[{"id":"273927","messageId":"1449083626-20075-1-git-send-email-pclouds@gmail.com","threadId":"40920","inReplyTo":null,"subject":"[PATCH 0/5] Split .git/config in multiple worktree setup","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2015-12-02T19:13:41Z","receivedAt":"2015-12-02T19:13:41Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Let's restart this. From the last discussion [1], we need to make\ncore.worktree per-worktree for submodules to work. We also need\ncore.sparseCheckout per-worktree.\n\nThis series adds a pattern list, with .gitignore syntax mostly, that\nsplit config var set into two sets, the per-worktree set will be\nstored in .git/worktrees/*/config.worktree instead. The pattern list\nconsists of default patterns, built in git binary, and user ones in\n.git/info/config.worktree.\n\nI have marked a few obvious config vars as per-worktree. There may be\nmore to mark, Max did go over them last time so I'll let him to add\nmore if submodule needs it.\n\n[1] http://article.gmane.org/gmane.comp.version-control.git/266520\n\nNguyễn Thái Ngọc Duy (5):\n  dir.c: clean the entire struct in clear_exclude_list()\n  config.c: move worktree-specific variables to .git/worktrees/...\n  setup.c: remove special case of core.worktree and core.bare\n  worktree: make core.sparseCheckout and core.ignoreStat per-worktree\n  git-worktree.txt: mention about the config file split\n\n Documentation/config.txt               |  13 ++-\n Documentation/git-worktree.txt         |  13 +++\n Documentation/gitrepository-layout.txt |  12 +++\n builtin/config.c                       |   9 ++\n cache.h                                |   2 +-\n config.c                               | 153 +++++++++++++++++++++++++++++++--\n dir.c                                  |   6 +-\n dir.h                                  |   1 +\n setup.c                                |  62 ++++++-------\n t/t2025-worktree-add.sh                |  26 ++++++\n 10 files changed, 250 insertions(+), 47 deletions(-)\n\n-- \n2.2.0.513.g477eb31\n"},{"id":"273922","messageId":"1449083626-20075-2-git-send-email-pclouds@gmail.com","threadId":"40920","inReplyTo":"1449083626-20075-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 1/5] dir.c: clean the entire struct in clear_exclude_list()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2015-12-02T19:13:42Z","receivedAt":"2015-12-02T19:13:42Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Make sure \"el\" can be reuseable again. The problem was el->alloc is\nnot cleared and may cause segfaults next time because add_exclude()\nthinks el->excludes (being NULL) has enough space. Just clear the\nentire struct to be safe.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n dir.c | 4 +---\n 1 file changed, 1 insertion(+), 3 deletions(-)\n\ndiff --git a/dir.c b/dir.c\nindex d2a8f06..b8b4576 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -564,9 +564,7 @@ void clear_exclude_list(struct exclude_list *el)\n \tfree(el->excludes);\n \tfree(el->filebuf);\n \n-\tel->nr = 0;\n-\tel->excludes = NULL;\n-\tel->filebuf = NULL;\n+\tmemset(el, 0, sizeof(*el));\n }\n \n static void trim_trailing_spaces(char *buf)\n-- \n2.2.0.513.g477eb31\n"},{"id":"273925","messageId":"1449083626-20075-3-git-send-email-pclouds@gmail.com","threadId":"40920","inReplyTo":"1449083626-20075-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 2/5] config.c: move worktree-specific variables to .git/worktrees/...","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2015-12-02T19:13:43Z","receivedAt":"2015-12-02T19:13:43Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":".git/info/config.worktree is a pattern list that splits .git/config in\nto sets: the worktree set matches the patterns, the commmon set does\nnot.\n\nIn normal worktrees, both sets are stored in .git/config. The\nconfig.worktree has no effect. Nothing is changed.\n\nIn linked worktrees, the common and worktree sets are read from and\nsaved to .git/config and .git/config.worktree respectively. Config\nkeys in .git/config that belong to the worktree set is ignored. Those\nare for the main worktree only. Similarly, keys not matching the\npatterns come from .git/config, duplicate keys from\n.git/config.worktree are ignored.\n\nThe effect is similar to the $GIT_DIR/$GIT_COMMON_DIR split, we can\ndefine that some vars can be shared and some cannot. And as a result\nof the $GIT_DIR/$GIT_COMMON_DIR split, config.worktree is actually\nfound at .git/worktrees/<id>/config.worktree.\n\nThrowing the exclude mechanism into this means reading config files\nwill be slower. But unless somebody reads thousands of keys, it should\nnot be noticable. The nice thing is we don't have to introduce yet\nanother pattern syntax.\n\nIn future, we might want to have a shared config file to contain\ncommon worktree-specific settings, so that we have some good defaults,\nbut still allow customization. Or we could twist the above logic a\nbit: for linked worktrees, read _all_ variables in config.worktree\nregardless of the patterns. But let's wait and see..\n\nHelped-by: Max Kirillov <max@max630.net>\nHelped-by: Jens Lehmann <Jens.Lehmann@web.de>\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/config.txt               |   4 +\n Documentation/gitrepository-layout.txt |  12 +++\n builtin/config.c                       |   9 +++\n cache.h                                |   2 +-\n config.c                               | 143 +++++++++++++++++++++++++++++++--\n dir.c                                  |   2 +-\n dir.h                                  |   1 +\n setup.c                                |   2 +-\n t/t2025-worktree-add.sh                |  26 ++++++\n 9 files changed, 191 insertions(+), 10 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 391a0c3..5c6cd4b 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -8,6 +8,10 @@ is used to store the configuration for that repository, and\n fallback values for the `.git/config` file. The file `/etc/gitconfig`\n can be used to store a system-wide default configuration.\n \n+Linked worktrees (see linkgit:git-worktree[1]) also have a\n+worktree-specific file \"config.worktree\". See\n+linkgit:gitrepository-layout[5] for more information.\n+\n The configuration variables are used by both the Git plumbing\n and the porcelains. The variables are divided into sections, wherein\n the fully qualified variable name of the variable itself is the last\ndiff --git a/Documentation/gitrepository-layout.txt b/Documentation/gitrepository-layout.txt\nindex 577ee84..62f7e33 100644\n--- a/Documentation/gitrepository-layout.txt\n+++ b/Documentation/gitrepository-layout.txt\n@@ -212,6 +212,12 @@ info/sparse-checkout::\n \tThis file stores sparse checkout patterns.\n \tSee also: linkgit:git-read-tree[1].\n \n+info/config.worktree:\n+\tThis file stores the configuration variable pattern list where\n+\t$GIT_DIR/config.worktree is used as storage instead of\n+\t$GIT_DIR/config. The syntax is the same as .gitignore except\n+\tthat '.' is considered the separator instead of '/'.\n+\n remotes::\n \tStores shorthands for URL and default refnames for use\n \twhen interacting with remote repositories via 'git fetch',\n@@ -276,6 +282,12 @@ worktrees/<id>/link::\n \tfile. It is used to detect if the linked repository is\n \tmanually removed.\n \n+worktrees/<id>/config.worktree::\n+\tThis file contains worktree-specific configuration\n+\tvariables. The list of variables is controlled by\n+\t$GIT_COMMON_DIR/info/config.worktree. The same variables in\n+\t$GIT_COMMON_DIR/config are ignored.\n+\n SEE ALSO\n --------\n linkgit:git-init[1],\ndiff --git a/builtin/config.c b/builtin/config.c\nindex adc7727..2b4d56e 100644\n--- a/builtin/config.c\n+++ b/builtin/config.c\n@@ -533,6 +533,15 @@ int cmd_config(int argc, const char **argv, const char *prefix)\n \t\tdefault:\n \t\t\tusage_with_options(builtin_config_usage, builtin_config_options);\n \t\t}\n+\n+\t/*\n+\t * For set operations, --local could be either config or\n+\t * config.worktree. Let config.c determine the path based on\n+\t * config keys.\n+\t */\n+\tif (use_local_config && actions != ACTION_LIST)\n+\t\tgiven_config_source.file = NULL;\n+\n \tif (omit_values &&\n \t    !(actions == ACTION_LIST || actions == ACTION_GET_REGEXP)) {\n \t\terror(\"--name-only is only applicable to --list or --get-regexp\");\ndiff --git a/cache.h b/cache.h\nindex 3ba0b8f..27bc3bc 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1468,7 +1468,7 @@ extern void git_config(config_fn_t fn, void *);\n extern int git_config_with_options(config_fn_t fn, void *,\n \t\t\t\t   struct git_config_source *config_source,\n \t\t\t\t   int respect_includes);\n-extern int git_config_early(config_fn_t fn, void *, const char *repo_config);\n+extern int git_config_early(config_fn_t fn, void *, const char *repo_config, const char *worktree_config);\n extern int git_parse_ulong(const char *, unsigned long *);\n extern int git_parse_maybe_bool(const char *);\n extern int git_config_int(const char *, const char *);\ndiff --git a/config.c b/config.c\nindex 248a21a..75c45e1 100644\n--- a/config.c\n+++ b/config.c\n@@ -13,6 +13,7 @@\n #include \"hashmap.h\"\n #include \"string-list.h\"\n #include \"utf8.h\"\n+#include \"dir.h\"\n \n struct config_source {\n \tstruct config_source *prev;\n@@ -38,6 +39,7 @@ struct config_source {\n };\n \n static struct config_source *cf;\n+static struct exclude_list config_local;\n \n static int zlib_compression_seen;\n \n@@ -89,6 +91,73 @@ static long config_buf_ftell(struct config_source *conf)\n \treturn conf->u.buf.pos;\n }\n \n+static void load_info_config_worktree(void)\n+{\n+\tstruct exclude_list *el = &config_local;\n+\tstruct strbuf sb = STRBUF_INIT;\n+\tint i, lineno = 1;\n+\tchar *buf, *entry;\n+\tsize_t size;\n+\n+\tclear_exclude_list(el);\n+\n+\tif (strbuf_read_file(&sb,\n+\t\t\t     git_path(\"info/config.worktree\"),\n+\t\t\t     128) <= 0) {\n+\t\tstrbuf_release(&sb);\n+\t\treturn;\n+\t}\n+\tstrbuf_addch(&sb, '\\n');\n+\tel->filebuf = buf = strbuf_detach(&sb, &size);\n+\n+\tfor (i = 0; i < size; i++)\n+\t\tif (buf[i] == '.')\n+\t\t\tbuf[i] = '/';\n+\t\telse\n+\t\t\tbuf[i] = tolower(buf[i]);\n+\n+\tentry = buf;\n+\tfor (i = 0; i < size; i++) {\n+\t\tif (buf[i] == '\\n') {\n+\t\t\tif (entry != buf + i && entry[0] != '#') {\n+\t\t\t\tbuf[i - (i && buf[i-1] == '\\r')] = 0;\n+\t\t\t\ttrim_trailing_spaces(entry);\n+\t\t\t\tadd_exclude(entry, \"\", 0, el, lineno);\n+\t\t\t}\n+\t\t\tlineno++;\n+\t\t\tentry = buf + i + 1;\n+\t\t}\n+\t}\n+\n+\t/*\n+\t * avoid base name matching because it may confusion in\n+\t * non-directory context.\n+\t */\n+\tfor (i = 0; i < el->nr; i++)\n+\t\tel->excludes[i]->flags &= ~EXC_FLAG_NODIR;\n+}\n+\n+static int is_config_local(const char *key_)\n+{\n+\tstatic struct strbuf key = STRBUF_INIT;\n+\tint i, dtype;\n+\n+\tif (!config_local.nr)\n+\t\treturn 0;\n+\n+\tstrbuf_reset(&key);\n+\tstrbuf_addstr(&key, key_);\n+\tfor (i = 0; i < key.len; i++) {\n+\t\tif (key.buf[i] == '.')\n+\t\t\tkey.buf[i] = '/';\n+\t\telse\n+\t\t\tkey.buf[i] = tolower(key.buf[i]);\n+\t}\n+\tdtype = DT_REG;\n+\treturn is_excluded_from_list(key.buf, key.len, \"\", &dtype,\n+\t\t\t\t     &config_local) > 0;\n+}\n+\n #define MAX_INCLUDE_DEPTH 10\n static const char include_depth_advice[] =\n \"exceeded maximum include depth (%d) while including\\n\"\n@@ -1184,7 +1253,29 @@ int git_config_system(void)\n \treturn !git_env_bool(\"GIT_CONFIG_NOSYSTEM\", 0);\n }\n \n-int git_config_early(config_fn_t fn, void *data, const char *repo_config)\n+static int config_worktree_filter_in(const char *var,\n+\t\t\t\t     const char *value, void *data)\n+{\n+\tstruct config_include_data *inc = data;\n+\n+\tif (!is_config_local(var))\n+\t\treturn error(\"%s in config.worktree is ignored\", var);\n+\treturn inc->fn(var, value, inc->data);\n+}\n+\n+static int config_worktree_filter_out(const char *var,\n+\t\t\t\t      const char *value, void *data)\n+{\n+\tstruct config_include_data *inc = data;\n+\n+\tif (is_config_local(var))\n+\t\treturn 0;\t/* these are for main worktree only */\n+\n+\treturn inc->fn(var, value, inc->data);\n+}\n+\n+int git_config_early(config_fn_t fn, void *data, const char *repo_config,\n+\t\t     const char *worktree_config)\n {\n \tint ret = 0, found = 0;\n \tchar *xdg_config = xdg_config_home(\"config\");\n@@ -1206,7 +1297,25 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)\n \t\tfound += 1;\n \t}\n \n-\tif (repo_config && !access_or_die(repo_config, R_OK, 0)) {\n+\tif (worktree_config) {\n+\t\tstruct config_include_data inc = CONFIG_INCLUDE_INIT;\n+\n+\t\tload_info_config_worktree();\n+\n+\t\tinc.fn = fn;\n+\t\tinc.data = data;\n+\t\tif (!access_or_die(worktree_config, R_OK, 0)) {\n+\t\t\tret += git_config_from_file(config_worktree_filter_in,\n+\t\t\t\t\t\t    worktree_config, &inc);\n+\t\t\tfound += 1;\n+\t\t}\n+\n+\t\tif (repo_config && !access_or_die(repo_config, R_OK, 0)) {\n+\t\t\tret += git_config_from_file(config_worktree_filter_out,\n+\t\t\t\t\t\t    repo_config, &inc);\n+\t\t\tfound += 1;\n+\t\t}\n+\t} else if (repo_config && !access_or_die(repo_config, R_OK, 0)) {\n \t\tret += git_config_from_file(fn, repo_config, data);\n \t\tfound += 1;\n \t}\n@@ -1232,6 +1341,7 @@ int git_config_with_options(config_fn_t fn, void *data,\n \t\t\t    int respect_includes)\n {\n \tchar *repo_config = NULL;\n+\tchar *worktree_config = NULL;\n \tint ret;\n \tstruct config_include_data inc = CONFIG_INCLUDE_INIT;\n \n@@ -1254,9 +1364,11 @@ int git_config_with_options(config_fn_t fn, void *data,\n \t\treturn git_config_from_blob_ref(fn, config_source->blob, data);\n \n \trepo_config = git_pathdup(\"config\");\n-\tret = git_config_early(fn, data, repo_config);\n-\tif (repo_config)\n-\t\tfree(repo_config);\n+\tif (git_common_dir_env)\n+\t\tworktree_config = git_pathdup(\"config.worktree\");\n+\tret = git_config_early(fn, data, repo_config, worktree_config);\n+\tfree(repo_config);\n+\tfree(worktree_config);\n \treturn ret;\n }\n \n@@ -1925,6 +2037,24 @@ int git_config_key_is_valid(const char *key)\n \treturn !git_config_parse_key_1(key, NULL, NULL, 1);\n }\n \n+static const char *get_config_filename(const char *config_filename,\n+\t\t\t\t       const char *key,\n+\t\t\t\t       char **filename_buf)\n+{\n+\tif (config_filename)\n+\t\treturn config_filename;\n+\tif (!git_common_dir_env) {\n+\t\tconfig_filename = *filename_buf = git_pathdup(\"config\");\n+\t\treturn config_filename;\n+\t}\n+\tload_info_config_worktree();\n+\tif (!is_config_local(key))\n+\t\tconfig_filename = *filename_buf = git_pathdup(\"config\");\n+\telse\n+\t\tconfig_filename = *filename_buf = git_pathdup(\"config.worktree\");\n+\treturn config_filename;\n+}\n+\n /*\n  * If value==NULL, unset in (remove from) config,\n  * if value_regex!=NULL, disregard key/value pairs where value does not match.\n@@ -1968,8 +2098,7 @@ int git_config_set_multivar_in_file(const char *config_filename,\n \n \tstore.multi_replace = multi_replace;\n \n-\tif (!config_filename)\n-\t\tconfig_filename = filename_buf = git_pathdup(\"config\");\n+\tconfig_filename = get_config_filename(config_filename, key, &filename_buf);\n \n \t/*\n \t * The lock serves a purpose in addition to locking: the new\ndiff --git a/dir.c b/dir.c\nindex b8b4576..9522b89 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -567,7 +567,7 @@ void clear_exclude_list(struct exclude_list *el)\n \tmemset(el, 0, sizeof(*el));\n }\n \n-static void trim_trailing_spaces(char *buf)\n+void trim_trailing_spaces(char *buf)\n {\n \tchar *p, *last_space = NULL;\n \ndiff --git a/dir.h b/dir.h\nindex 7b5855d..52ded83 100644\n--- a/dir.h\n+++ b/dir.h\n@@ -248,6 +248,7 @@ extern void clear_exclude_list(struct exclude_list *el);\n extern void clear_directory(struct dir_struct *dir);\n extern int file_exists(const char *);\n \n+extern void trim_trailing_spaces(char *buf);\n extern int is_inside_dir(const char *dir);\n extern int dir_inside_of(const char *subdir, const char *dir);\n \ndiff --git a/setup.c b/setup.c\nindex d343725..0047d40 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -404,7 +404,7 @@ static int check_repository_format_gently(const char *gitdir, int *nongit_ok)\n \t * Use a gentler version of git_config() to check if this repo\n \t * is a good one.\n \t */\n-\tgit_config_early(fn, NULL, repo_config);\n+\tgit_config_early(fn, NULL, repo_config, NULL);\n \tif (GIT_REPO_VERSION_READ < repository_format_version) {\n \t\tif (!nongit_ok)\n \t\t\tdie (\"Expected git repo version <= %d, found %d\",\ndiff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh\nindex 3694174..e8d8da4 100755\n--- a/t/t2025-worktree-add.sh\n+++ b/t/t2025-worktree-add.sh\n@@ -198,4 +198,30 @@ test_expect_success 'local clone from linked checkout' '\n \t( cd here-clone && git fsck )\n '\n \n+test_expect_success 'setting worktree.foo goes to config.worktree' '\n+\techo worKtree.Foo >> .git/info/config.worktree &&\n+\tgit worktree add wt.foo HEAD &&\n+\tgit config woRKtree.FOO barrrr &&\n+\tgit --git-dir=wt.foo/.git config woRKtree.FOO bar &&\n+\tcat >expect <<\\EOF &&\n+[woRKtree]\n+\tFOO = bar\n+EOF\n+\ttest_cmp expect .git/worktrees/wt.foo/config.worktree &&\n+\tgit --git-dir=wt.foo/.git config woRktree.foo >actual2 &&\n+\techo bar >expect2 &&\n+\ttest_cmp expect2 actual2 &&\n+\ttest_path_is_missing .git/config.worktree &&\n+\tgit config WORKTREE.FOO >actual3 &&\n+\techo barrrr >expect3 &&\n+\ttest_cmp expect3 actual3\n+'\n+\n+test_expect_success 'shared config still goes to config' '\n+\tgit config random.key randomValue &&\n+\tgit --git-dir=wt.foo/.git config random.key >actual &&\n+\techo randomValue >expect &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\n-- \n2.2.0.513.g477eb31\n"},{"id":"273923","messageId":"1449083626-20075-4-git-send-email-pclouds@gmail.com","threadId":"40920","inReplyTo":"1449083626-20075-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 3/5] setup.c: remove special case of core.worktree and core.bare","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2015-12-02T19:13:44Z","receivedAt":"2015-12-02T19:13:44Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"core.worktree and core.bare, which are treated specially in 31e26eb [1],\nare now moved to info/core.worktree and the special treatment\nreverted. The test \"$GIT_DIR/common overrides core.worktree\" in t1501\nfrom 31e26eb verifies that the behavior is still correct after this\nchange.\n\nA note about core.bare. On the surface it does not make sense for\ncore.bare to be worktree specific. It's made so in order to \"grow\" new\nworktrees from a bare repo. In these new linked worktrees, core.bare\nwill be hidden away and worktree-related commands won't complain about\nbare repository.\n\n[1] 31e26eb (setup.c: support multi-checkout repo setup - 2014-11-30)\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/config.txt |  4 ++++\n config.c                 |  8 +++++++\n setup.c                  | 62 ++++++++++++++++++++++--------------------------\n 3 files changed, 40 insertions(+), 34 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 5c6cd4b..09a8b57 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -454,6 +454,8 @@ linkgit:git-init[1] when the repository was created.  By default a\n repository that ends in \"/.git\" is assumed to be not bare (bare =\n false), while all other repositories are assumed to be bare (bare\n = true).\n++\n+This variable is per-worktree in multiple working tree setup.\n \n core.worktree::\n \tSet the path to the root of the working tree.\n@@ -478,6 +480,8 @@ still use \"/different/path\" as the root of the work tree and can cause\n confusion unless you know what you are doing (e.g. you are creating a\n read-only snapshot of the same index to a location different from the\n repository's usual working tree).\n++\n+This variable is per-worktree in multiple working tree setup.\n \n core.logAllRefUpdates::\n \tEnable the reflog. Updates to a ref <ref> is logged to the file\ndiff --git a/config.c b/config.c\nindex 75c45e1..54a6219 100644\n--- a/config.c\n+++ b/config.c\n@@ -91,6 +91,11 @@ static long config_buf_ftell(struct config_source *conf)\n \treturn conf->u.buf.pos;\n }\n \n+static const char* default_config_worktree[] = {\n+\t\"core/bare\",\n+\t\"core/worktree\"\n+};\n+\n static void load_info_config_worktree(void)\n {\n \tstruct exclude_list *el = &config_local;\n@@ -101,6 +106,9 @@ static void load_info_config_worktree(void)\n \n \tclear_exclude_list(el);\n \n+\tfor (i = 0; i < ARRAY_SIZE(default_config_worktree); i++)\n+\t\tadd_exclude(default_config_worktree[i], \"\", 0, el, 0);\n+\n \tif (strbuf_read_file(&sb,\n \t\t\t     git_path(\"info/config.worktree\"),\n \t\t\t     128) <= 0) {\ndiff --git a/setup.c b/setup.c\nindex 0047d40..c088d45 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -355,43 +355,20 @@ void setup_work_tree(void)\n \tinitialized = 1;\n }\n \n-static int check_repo_format(const char *var, const char *value, void *cb)\n-{\n-\tconst char *ext;\n-\n-\tif (strcmp(var, \"core.repositoryformatversion\") == 0)\n-\t\trepository_format_version = git_config_int(var, value);\n-\telse if (strcmp(var, \"core.sharedrepository\") == 0)\n-\t\tshared_repository = git_config_perm(var, value);\n-\telse if (skip_prefix(var, \"extensions.\", &ext)) {\n-\t\t/*\n-\t\t * record any known extensions here; otherwise,\n-\t\t * we fall through to recording it as unknown, and\n-\t\t * check_repository_format will complain\n-\t\t */\n-\t\tif (!strcmp(ext, \"noop\"))\n-\t\t\t;\n-\t\telse if (!strcmp(ext, \"preciousobjects\"))\n-\t\t\trepository_format_precious_objects = git_config_bool(var, value);\n-\t\telse\n-\t\t\tstring_list_append(&unknown_extensions, ext);\n-\t}\n-\treturn 0;\n-}\n-\n static int check_repository_format_gently(const char *gitdir, int *nongit_ok)\n {\n \tstruct strbuf sb = STRBUF_INIT;\n+\tstruct strbuf sb2 = STRBUF_INIT;\n \tconst char *repo_config;\n-\tconfig_fn_t fn;\n+\tconst char *worktree_config = NULL;\n \tint ret = 0;\n \n \tstring_list_clear(&unknown_extensions, 0);\n \n-\tif (get_common_dir(&sb, gitdir))\n-\t\tfn = check_repo_format;\n-\telse\n-\t\tfn = check_repository_format_version;\n+\tif (get_common_dir(&sb, gitdir)) {\n+\t\tstrbuf_addf(&sb2, \"%s/config.worktree\", gitdir);\n+\t\tworktree_config = sb2.buf;\n+\t}\n \tstrbuf_addstr(&sb, \"/config\");\n \trepo_config = sb.buf;\n \n@@ -404,7 +381,8 @@ static int check_repository_format_gently(const char *gitdir, int *nongit_ok)\n \t * Use a gentler version of git_config() to check if this repo\n \t * is a good one.\n \t */\n-\tgit_config_early(fn, NULL, repo_config, NULL);\n+\tgit_config_early(check_repository_format_version, NULL,\n+\t\t\t repo_config, worktree_config);\n \tif (GIT_REPO_VERSION_READ < repository_format_version) {\n \t\tif (!nongit_ok)\n \t\t\tdie (\"Expected git repo version <= %d, found %d\",\n@@ -431,6 +409,7 @@ static int check_repository_format_gently(const char *gitdir, int *nongit_ok)\n \t}\n \n \tstrbuf_release(&sb);\n+\tstrbuf_release(&sb2);\n \treturn ret;\n }\n \n@@ -963,10 +942,25 @@ int git_config_perm(const char *var, const char *value)\n \n int check_repository_format_version(const char *var, const char *value, void *cb)\n {\n-\tint ret = check_repo_format(var, value, cb);\n-\tif (ret)\n-\t\treturn ret;\n-\tif (strcmp(var, \"core.bare\") == 0) {\n+\tconst char *ext;\n+\n+\tif (strcmp(var, \"core.repositoryformatversion\") == 0)\n+\t\trepository_format_version = git_config_int(var, value);\n+\telse if (strcmp(var, \"core.sharedrepository\") == 0)\n+\t\tshared_repository = git_config_perm(var, value);\n+\telse if (skip_prefix(var, \"extensions.\", &ext)) {\n+\t\t/*\n+\t\t * record any known extensions here; otherwise,\n+\t\t * we fall through to recording it as unknown, and\n+\t\t * check_repository_format will complain\n+\t\t */\n+\t\tif (!strcmp(ext, \"noop\"))\n+\t\t\t;\n+\t\telse if (!strcmp(ext, \"preciousobjects\"))\n+\t\t\trepository_format_precious_objects = git_config_bool(var, value);\n+\t\telse\n+\t\t\tstring_list_append(&unknown_extensions, ext);\n+\t} else if (strcmp(var, \"core.bare\") == 0) {\n \t\tis_bare_repository_cfg = git_config_bool(var, value);\n \t\tif (is_bare_repository_cfg == 1)\n \t\t\tinside_work_tree = -1;\n-- \n2.2.0.513.g477eb31\n"},{"id":"273926","messageId":"1449083626-20075-5-git-send-email-pclouds@gmail.com","threadId":"40920","inReplyTo":"1449083626-20075-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 4/5] worktree: make core.sparseCheckout and core.ignoreStat per-worktree","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2015-12-02T19:13:45Z","receivedAt":"2015-12-02T19:13:45Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"The first one must be per-worktree because info/sparse-checkout\nalready is. The second one shares the same nature and should also be\nper-worktree.\n\nNote, because info/config.worktree uses .gitignore syntax, you can\nnegate a default pattern and revert it back to per-repo..\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/config.txt | 5 ++++-\n config.c                 | 2 ++\n 2 files changed, 6 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 09a8b57..aff1431 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -435,7 +435,8 @@ Git will not normally detect changes to those files.\n This is useful on systems where lstat() calls are very slow, such as\n CIFS/Microsoft Windows.\n +\n-False by default.\n+False by default. This variable is per-worktree in multiple working\n+tree setup.\n \n core.preferSymlinkRefs::\n \tInstead of the default \"symref\" format for HEAD\n@@ -736,6 +737,8 @@ the 'GIT_NOTES_REF' environment variable.  See linkgit:git-notes[1].\n core.sparseCheckout::\n \tEnable \"sparse checkout\" feature. See section \"Sparse checkout\" in\n \tlinkgit:git-read-tree[1] for more information.\n++\n+This variable is per-worktree in multiple working tree setup.\n \n core.abbrev::\n \tSet the length object names are abbreviated to.  If unspecified,\ndiff --git a/config.c b/config.c\nindex 54a6219..fdf38da 100644\n--- a/config.c\n+++ b/config.c\n@@ -93,6 +93,8 @@ static long config_buf_ftell(struct config_source *conf)\n \n static const char* default_config_worktree[] = {\n \t\"core/bare\",\n+\t\"core/ignorestat\",\n+\t\"core/sparsecheckout\",\n \t\"core/worktree\"\n };\n \n-- \n2.2.0.513.g477eb31\n"},{"id":"273924","messageId":"1449083626-20075-6-git-send-email-pclouds@gmail.com","threadId":"40920","inReplyTo":"1449083626-20075-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 5/5] git-worktree.txt: mention about the config file split","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2015-12-02T19:13:46Z","receivedAt":"2015-12-02T19:13:46Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/git-worktree.txt | 13 +++++++++++++\n 1 file changed, 13 insertions(+)\n\ndiff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt\nindex 5b9ad04..299e4f2 100644\n--- a/Documentation/git-worktree.txt\n+++ b/Documentation/git-worktree.txt\n@@ -147,6 +147,19 @@ to `/path/main/.git/worktrees/test-next` then a file named\n `test-next` entry from being pruned.  See\n linkgit:gitrepository-layout[5] for details.\n \n+Similar to the file system split in \".git\", the repository config file\n+is also split. Certain variables, for example core.worktree, are\n+per-worktree while the majority of variables are still shared (see\n+linkgit:git-config[1] for details). Shared variables and per-working\n+tree ones that belong to the main working tree are in .git/config.\n+Per-working tree variables for working tree X are in\n+$GIT_COMMON_DIR/worktrees/X/config.worktree. Even though per-working\n+tree variables for the main working tree are in the default config\n+place, they are invisible from all linked working trees.  You can make\n+more config variables per-working tree by adding them in\n+.git/info/config.worktree (see linkgit:gitrepository-layout[5] for\n+details).\n+\n LIST OUTPUT FORMAT\n ------------------\n The worktree list command has two output formats.  The default format shows the\n-- \n2.2.0.513.g477eb31\n"},{"id":"273966","messageId":"20151203061505.GA4314@wheezy.local","threadId":"40920","inReplyTo":"1449083626-20075-1-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH 0/5] Split .git/config in multiple worktree setup","fromName":"Max Kirillov","fromEmail":"max@max630.net","sentAt":"2015-12-03T06:15:05Z","receivedAt":"2015-12-03T06:15:05Z","isPatch":true,"sender":{"key":"max@max630.net","avatar":"https://avatars.githubusercontent.com/u/381560?v=4"},"body":"On Wed, Dec 02, 2015 at 08:13:41PM +0100, Nguyễn Thái Ngọc Duy wrote:\n> Let's restart this. From the last discussion [1], we need to make\n> core.worktree per-worktree for submodules to work. We also need\n> core.sparseCheckout per-worktree.\n\nThank you. It would be nice to have it, so that features\nlike submodules work fully.\n\nNow there are extensions support, would it make sense to\nmark repositories which use per-worktree config with an\nextension? It could clearly separate 2.5-style\nmulti-worktree repositories (which might exist already\naround) from the new format. The extension could be set by\n'worktree add' while creating first worktree, for example.\n\n> This series adds a pattern list, with .gitignore syntax mostly, that\n> split config var set into two sets, the per-worktree set will be\n> stored in .git/worktrees/*/config.worktree instead. The pattern list\n> consists of default patterns, built in git binary, and user ones in\n> .git/info/config.worktree.\n\nUsing builtin defaults might be confusing for users -\nediting the info/config.worktree they must keep in mind the\nlist of defaults (which they seem to don't know). Also, if\nanybody wants to extend the default list (like myself, for\nsubmodules), should they edit the info/config.worktree in\nprovided template of extend the builtin list? What was wrong\nwith the default in template?\n\n-- \nMax\n"},{"id":"273968","messageId":"CACsJy8AOeFEKhhmH-TCK6gWZQAJX0kbTS0-=iyCji9eXwBr9QA@mail.gmail.com","threadId":"40920","inReplyTo":"20151203061505.GA4314@wheezy.local","subject":"Re: [PATCH 0/5] Split .git/config in multiple worktree setup","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2015-12-03T08:07:07Z","receivedAt":"2015-12-03T08:07:07Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Thu, Dec 3, 2015 at 7:15 AM, Max Kirillov <max@max630.net> wrote:\n> On Wed, Dec 02, 2015 at 08:13:41PM +0100, Nguyễn Thái Ngọc Duy wrote:\n>> Let's restart this. From the last discussion [1], we need to make\n>> core.worktree per-worktree for submodules to work. We also need\n>> core.sparseCheckout per-worktree.\n>\n> Thank you. It would be nice to have it, so that features\n> like submodules work fully.\n>\n> Now there are extensions support, would it make sense to\n> mark repositories which use per-worktree config with an\n> extension? It could clearly separate 2.5-style\n> multi-worktree repositories (which might exist already\n> around) from the new format. The extension could be set by\n> 'worktree add' while creating first worktree, for example.\n\nHmm.. I didn't think of this. If we add this as a repo extension, then\nwe could use git/config for shared vars only, main worktree specific\nvars can stay in .git/config.worktree while linked worktree's in\n.git/worktrees/*/config.worktree. Neat.\n\n>> This series adds a pattern list, with .gitignore syntax mostly, that\n>> split config var set into two sets, the per-worktree set will be\n>> stored in .git/worktrees/*/config.worktree instead. The pattern list\n>> consists of default patterns, built in git binary, and user ones in\n>> .git/info/config.worktree.\n>\n> Using builtin defaults might be confusing for users -\n> editing the info/config.worktree they must keep in mind the\n> list of defaults (which they seem to don't know).\n\nAll per-worktree variables are marked so in config.txt\n\n> Also, if\n> anybody wants to extend the default list (like myself, for\n> submodules), should they edit the info/config.worktree in\n> provided template of extend the builtin list? What was wrong\n> with the default in template?\n\nIf a variable _must_ be per-worktree or something will break, then it\nshould belong to the builtin list (so the user is less likely to mess\nwith it). If it may or may not be per-worktree, depending on one's\npreference, then we can keep this in info/config.worktree. I made the\nbuiltin list for that reason (user not breaking stuff accidentally)\nand another one, which is upgrade issue. Suppose you introduce a new\nper-worktree variable in the new git version. If it's in the builtin\nlist, we don't have to update every repo's info/config,worktree.\n-- \nDuy\n"},{"id":"273985","messageId":"xmqqpoyntilw.fsf@gitster.mtv.corp.google.com","threadId":"40920","inReplyTo":"CACsJy8AOeFEKhhmH-TCK6gWZQAJX0kbTS0-=iyCji9eXwBr9QA@mail.gmail.com","subject":"Re: [PATCH 0/5] Split .git/config in multiple worktree setup","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-12-03T19:52:43Z","receivedAt":"2015-12-03T19:52:43Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Duy Nguyen <pclouds@gmail.com> writes:\n\n> If a variable _must_ be per-worktree or something will break, then it\n> should belong to the builtin list (so the user is less likely to mess\n> with it). If it may or may not be per-worktree, depending on one's\n> preference, then we can keep this in info/config.worktree. I made the\n> builtin list for that reason (user not breaking stuff accidentally)\n> and another one, which is upgrade issue. Suppose you introduce a new\n> per-worktree variable in the new git version. If it's in the builtin\n> list, we don't have to update every repo's info/config,worktree.\n\nI agree with your reasoning to have built-in set of files that are\nper-worktree. I actually prefer *not* to have any configurability\nto avoid confusion between users.\n"},{"id":"273992","messageId":"20151203205318.GA10006@wheezy.local","threadId":"40920","inReplyTo":"CACsJy8AOeFEKhhmH-TCK6gWZQAJX0kbTS0-=iyCji9eXwBr9QA@mail.gmail.com","subject":"Re: [PATCH 0/5] Split .git/config in multiple worktree setup","fromName":"Max Kirillov","fromEmail":"max@max630.net","sentAt":"2015-12-03T20:53:18Z","receivedAt":"2015-12-03T20:53:18Z","isPatch":true,"sender":{"key":"max@max630.net","avatar":"https://avatars.githubusercontent.com/u/381560?v=4"},"body":"On Thu, Dec 03, 2015 at 09:07:07AM +0100, Duy Nguyen wrote:\n> On Thu, Dec 3, 2015 at 7:15 AM, Max Kirillov <max@max630.net> wrote:\n>> Using builtin defaults might be confusing for users -\n>> editing the info/config.worktree they must keep in mind the\n>> list of defaults (which they seem to don't know).\n> \n> All per-worktree variables are marked so in config.txt\n\nIf I were user I would like the list to be more explicit.\n\n>> Also, if\n>> anybody wants to extend the default list (like myself, for\n>> submodules), should they edit the info/config.worktree in\n>> provided template of extend the builtin list? What was wrong\n>> with the default in template?\n> \n> Suppose you introduce a new\n> per-worktree variable in the new git version. If it's in the builtin\n> list, we don't have to update every repo's info/config,worktree.\n\nBut how do you see it? Let's, for example, git-N consider\nsome variable as per-repository, and user does have it their\n.git/config. Then git-N+1 considers it as per-worktree. How\ndoes it find the variable while opening some existing\nworktree? Then, if user sets the variable in some worktree\nusing git-N+1, git-N will no longer be able to see the\ncorrect variable value. Does this mean that any change in\nbuiltin list should cause repository incompatibility?\n\nWith defaults written in the info/config.worktree file the\nissue do not exist at all: you can open repository created\nwith a git version with some default list of per-worktree\nveriables with a version with other default list. It all\nwould work.\n\nIf user decides to change the actual list of default\nper-worktree variable it is always can be done explcitly,\nwith some provided convenience command for example.\n\n-- \nMax\n"},{"id":"273993","messageId":"20151203210049.GB10006@wheezy.local","threadId":"40920","inReplyTo":"xmqqpoyntilw.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 0/5] Split .git/config in multiple worktree setup","fromName":"Max Kirillov","fromEmail":"max@max630.net","sentAt":"2015-12-03T21:00:49Z","receivedAt":"2015-12-03T21:00:49Z","isPatch":true,"sender":{"key":"max@max630.net","avatar":"https://avatars.githubusercontent.com/u/381560?v=4"},"body":"On Thu, Dec 03, 2015 at 11:52:43AM -0800, Junio C Hamano wrote:\n> I actually prefer *not* to have any configurability\n> to avoid confusion between users.\n\nThis could be an approach. But because of upgrade issues\nwhich I described in the other response it looks like this\ndecision is not easy to change in a later version. So the\nlist should be decided here and now for each existing\nvariable, and later for any new one, and preferable never\nchanged after that.\n\n-- \nMax\n"},{"id":"274006","messageId":"CACsJy8B6hZGn_KW5PeB33bjU6Y5n3Zbuh1YO0McZZg5DRemB0g@mail.gmail.com","threadId":"40920","inReplyTo":"20151203205318.GA10006@wheezy.local","subject":"Re: [PATCH 0/5] Split .git/config in multiple worktree setup","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2015-12-04T15:57:14Z","receivedAt":"2015-12-04T15:57:14Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Thu, Dec 3, 2015 at 9:53 PM, Max Kirillov <max@max630.net> wrote:\n> On Thu, Dec 03, 2015 at 09:07:07AM +0100, Duy Nguyen wrote:\n>> On Thu, Dec 3, 2015 at 7:15 AM, Max Kirillov <max@max630.net> wrote:\n>>> Using builtin defaults might be confusing for users -\n>>> editing the info/config.worktree they must keep in mind the\n>>> list of defaults (which they seem to don't know).\n>>\n>> All per-worktree variables are marked so in config.txt\n>\n> If I were user I would like the list to be more explicit.\n\nI wouldn't. I mean, I have more than a dozen of git repos lying\naround, some I don't even remember where. Should I check git release\nnotes at every upgrade then fix up _all_ of my repos? That's something\nI rather not do.\n\n>>> Also, if\n>>> anybody wants to extend the default list (like myself, for\n>>> submodules), should they edit the info/config.worktree in\n>>> provided template of extend the builtin list? What was wrong\n>>> with the default in template?\n>>\n>> Suppose you introduce a new\n>> per-worktree variable in the new git version. If it's in the builtin\n>> list, we don't have to update every repo's info/config,worktree.\n>\n> But how do you see it? Let's, for example, git-N consider\n> some variable as per-repository, and user does have it their\n> .git/config. Then git-N+1 considers it as per-worktree. How\n> does it find the variable while opening some existing\n> worktree? Then, if user sets the variable in some worktree\n> using git-N+1, git-N will no longer be able to see the\n> correct variable value. Does this mean that any change in\n> builtin list should cause repository incompatibility?\n\nBehavior differences between git versions have been alway will always\nbe the problem. Yes providing some forward compatibility (by storing\nsome logic outside the binary in this case) helps, but I don't think\nit eliminates it. If incompatibilities may lead to a big problem, then\nwe can always make the new behavior an \"repo extension\" to stop older\nbinaries from accessing the touched repos.\n\nMost of the time there's only one git version being used. So it should\nnot be a big problem. But yes, if a repo is shared over network, then\nmultiple git versions accessing the same repo can happen.\n\nOn Thu, Dec 3, 2015 at 8:52 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> I agree with your reasoning to have built-in set of files that are\n> per-worktree. I actually prefer *not* to have any configurability\n> to avoid confusion between users.\n\nThere are a set of variables where whether they are shared or\nper-worktree is pretty much preference. For example, core.ignoreCase.\nWhat if I put one worktree on that case-insensitive file system? This\ngives the user some flexibility in managing those variables. _But_\nthey can also manage another way with include.path (or a new variant\nthat is worktree-aware), with a bit of work.\n\nSo killing info/core.worktree is not a bad idea. Even better, we can\navoid pulling exclude machinery in. But yeah, need to sort out the\nupgrade issue Max mentioned first.\n-- \nDuy\n"},{"id":"274063","messageId":"CAPig+cST=UGG8VAG94qb9M8vcOXfmWAhLoP65yWJGywR9R84LA@mail.gmail.com","threadId":"40920","inReplyTo":"1449083626-20075-3-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH 2/5] config.c: move worktree-specific variables to .git/worktrees/...","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2015-12-06T07:47:27Z","receivedAt":"2015-12-06T07:47:27Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Wed, Dec 2, 2015 at 2:13 PM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:\n> .git/info/config.worktree is a pattern list that splits .git/config in\n> to sets: the worktree set matches the patterns, the commmon set does\n> not.\n>\n> In normal worktrees, both sets are stored in .git/config. The\n> config.worktree has no effect. Nothing is changed.\n>\n> In linked worktrees, the common and worktree sets are read from and\n> saved to .git/config and .git/config.worktree respectively. Config\n> keys in .git/config that belong to the worktree set is ignored. Those\n> are for the main worktree only. Similarly, keys not matching the\n> patterns come from .git/config, duplicate keys from\n> .git/config.worktree are ignored.\n>\n> The effect is similar to the $GIT_DIR/$GIT_COMMON_DIR split, we can\n> define that some vars can be shared and some cannot. And as a result\n> of the $GIT_DIR/$GIT_COMMON_DIR split, config.worktree is actually\n> found at .git/worktrees/<id>/config.worktree.\n\nWhy does this worktree-specific file need/have a .worktree suffix?\n\n> Throwing the exclude mechanism into this means reading config files\n> will be slower. But unless somebody reads thousands of keys, it should\n> not be noticable. The nice thing is we don't have to introduce yet\n> another pattern syntax.\n>\n> In future, we might want to have a shared config file to contain\n> common worktree-specific settings, so that we have some good defaults,\n> but still allow customization. Or we could twist the above logic a\n> bit: for linked worktrees, read _all_ variables in config.worktree\n> regardless of the patterns. But let's wait and see..\n>\n> Helped-by: Max Kirillov <max@max630.net>\n> Helped-by: Jens Lehmann <Jens.Lehmann@web.de>\n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> ---\n> diff --git a/config.c b/config.c\n> @@ -89,6 +91,73 @@ static long config_buf_ftell(struct config_source *conf)\n> +static void load_info_config_worktree(void)\n> +{\n> +       struct exclude_list *el = &config_local;\n> +       struct strbuf sb = STRBUF_INIT;\n> +       int i, lineno = 1;\n> +       char *buf, *entry;\n> +       size_t size;\n> +\n> +       clear_exclude_list(el);\n> +\n> +       if (strbuf_read_file(&sb,\n> +                            git_path(\"info/config.worktree\"),\n> +                            128) <= 0) {\n> +               strbuf_release(&sb);\n> +               return;\n> +       }\n> +       strbuf_addch(&sb, '\\n');\n> +       el->filebuf = buf = strbuf_detach(&sb, &size);\n> +\n> +       for (i = 0; i < size; i++)\n> +               if (buf[i] == '.')\n> +                       buf[i] = '/';\n> +               else\n> +                       buf[i] = tolower(buf[i]);\n> +\n> +       entry = buf;\n> +       for (i = 0; i < size; i++) {\n> +               if (buf[i] == '\\n') {\n> +                       if (entry != buf + i && entry[0] != '#') {\n> +                               buf[i - (i && buf[i-1] == '\\r')] = 0;\n> +                               trim_trailing_spaces(entry);\n> +                               add_exclude(entry, \"\", 0, el, lineno);\n> +                       }\n> +                       lineno++;\n> +                       entry = buf + i + 1;\n> +               }\n> +       }\n> +\n> +       /*\n> +        * avoid base name matching because it may confusion in\n\ns/may/may cause/\n\n> +        * non-directory context.\n> +        */\n> +       for (i = 0; i < el->nr; i++)\n> +               el->excludes[i]->flags &= ~EXC_FLAG_NODIR;\n> +}\n> +\n> +static int is_config_local(const char *key_)\n> +{\n> +       static struct strbuf key = STRBUF_INIT;\n> +       int i, dtype;\n> +\n> +       if (!config_local.nr)\n> +               return 0;\n> +\n> +       strbuf_reset(&key);\n> +       strbuf_addstr(&key, key_);\n\nWhy does 'key' need to be static considering that it is overwritten on\neach call and its value is never accessed after the function returns?\n\n> +       for (i = 0; i < key.len; i++) {\n> +               if (key.buf[i] == '.')\n> +                       key.buf[i] = '/';\n> +               else\n> +                       key.buf[i] = tolower(key.buf[i]);\n> +       }\n> +       dtype = DT_REG;\n> +       return is_excluded_from_list(key.buf, key.len, \"\", &dtype,\n> +                                    &config_local) > 0;\n> +}\n> diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh\n> @@ -198,4 +198,30 @@ test_expect_success 'local clone from linked checkout' '\n> +test_expect_success 'setting worktree.foo goes to config.worktree' '\n> +       echo worKtree.Foo >> .git/info/config.worktree &&\n\nPerhaps? s/>> />/\n\n> +       git worktree add wt.foo HEAD &&\n> +       git config woRKtree.FOO barrrr &&\n> +       git --git-dir=wt.foo/.git config woRKtree.FOO bar &&\n> +       cat >expect <<\\EOF &&\n> +[woRKtree]\n> +       FOO = bar\n> +EOF\n> +       test_cmp expect .git/worktrees/wt.foo/config.worktree &&\n> +       git --git-dir=wt.foo/.git config woRktree.foo >actual2 &&\n> +       echo bar >expect2 &&\n> +       test_cmp expect2 actual2 &&\n> +       test_path_is_missing .git/config.worktree &&\n> +       git config WORKTREE.FOO >actual3 &&\n> +       echo barrrr >expect3 &&\n> +       test_cmp expect3 actual3\n> +'\n> +\n> +test_expect_success 'shared config still goes to config' '\n> +       git config random.key randomValue &&\n> +       git --git-dir=wt.foo/.git config random.key >actual &&\n\nWhat about also testing the opposite scenario?\n\n    git --git-dir=wt.foo/.git  config random.key randomValue &&\n    git config random.key >actual &&\n\n> +       echo randomValue >expect &&\n> +       test_cmp expect actual\n> +'\n> +\n>  test_done\n> --\n> 2.2.0.513.g477eb31\n"},{"id":"274064","messageId":"CAPig+cT3NrF+0uDi4krd9WoqqJvZUqxCfhVxekoKWaPZ7C_dKw@mail.gmail.com","threadId":"40920","inReplyTo":"1449083626-20075-6-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH 5/5] git-worktree.txt: mention about the config file split","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2015-12-06T08:02:27Z","receivedAt":"2015-12-06T08:02:27Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Wed, Dec 2, 2015 at 2:13 PM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:\n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> ---\n> diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt\n> @@ -147,6 +147,19 @@ to `/path/main/.git/worktrees/test-next` then a file named\n>  `test-next` entry from being pruned.  See\n>  linkgit:gitrepository-layout[5] for details.\n>\n> +Similar to the file system split in \".git\", the repository config file\n> +is also split. Certain variables, for example core.worktree, are\n> +per-worktree while the majority of variables are still shared (see\n> +linkgit:git-config[1] for details). Shared variables and per-working\n> +tree ones that belong to the main working tree are in .git/config.\n> +Per-working tree variables for working tree X are in\n> +$GIT_COMMON_DIR/worktrees/X/config.worktree. Even though per-working\n\nExisting examples in the DETAILS section call this \"test-next\" rather\nthan \"X\", so perhaps s/X/test-next/g ?\n\n> +tree variables for the main working tree are in the default config\n> +place, they are invisible from all linked working trees.  You can make\n> +more config variables per-working tree by adding them in\n> +.git/info/config.worktree (see linkgit:gitrepository-layout[5] for\n> +details).\n> +\n>  LIST OUTPUT FORMAT\n>  ------------------\n>  The worktree list command has two output formats.  The default format shows the\n> --\n> 2.2.0.513.g477eb31\n"},{"id":"274065","messageId":"CACsJy8BDCGxkLuFTwoyNYZqThe9mZYh1OpL8R1R4-BFvB_1coA@mail.gmail.com","threadId":"40920","inReplyTo":"CAPig+cST=UGG8VAG94qb9M8vcOXfmWAhLoP65yWJGywR9R84LA@mail.gmail.com","subject":"Re: [PATCH 2/5] config.c: move worktree-specific variables to .git/worktrees/...","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2015-12-06T10:22:16Z","receivedAt":"2015-12-06T10:22:16Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Sun, Dec 6, 2015 at 8:47 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n> On Wed, Dec 2, 2015 at 2:13 PM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:\n>> .git/info/config.worktree is a pattern list that splits .git/config in\n>> to sets: the worktree set matches the patterns, the commmon set does\n>> not.\n>>\n>> In normal worktrees, both sets are stored in .git/config. The\n>> config.worktree has no effect. Nothing is changed.\n>>\n>> In linked worktrees, the common and worktree sets are read from and\n>> saved to .git/config and .git/config.worktree respectively. Config\n>> keys in .git/config that belong to the worktree set is ignored. Those\n>> are for the main worktree only. Similarly, keys not matching the\n>> patterns come from .git/config, duplicate keys from\n>> .git/config.worktree are ignored.\n>>\n>> The effect is similar to the $GIT_DIR/$GIT_COMMON_DIR split, we can\n>> define that some vars can be shared and some cannot. And as a result\n>> of the $GIT_DIR/$GIT_COMMON_DIR split, config.worktree is actually\n>> found at .git/worktrees/<id>/config.worktree.\n>\n> Why does this worktree-specific file need/have a .worktree suffix?\n\nI think in the beginning it was supposed to support git-new-workdir as\nwell. With a separate name, you can symlink .git/config back to\noriginal repo and create a new .git/config.worktree. The actual code\nin this patch does not support this though. I guess as 'git worktree'\nis maturing, we probably don't have to worry about git-new-workdir and\ncould drop .worktree suffix.\n\n>> +static int is_config_local(const char *key_)\n>> +{\n>> +       static struct strbuf key = STRBUF_INIT;\n>> +       int i, dtype;\n>> +\n>> +       if (!config_local.nr)\n>> +               return 0;\n>> +\n>> +       strbuf_reset(&key);\n>> +       strbuf_addstr(&key, key_);\n>\n> Why does 'key' need to be static considering that it is overwritten on\n> each call and its value is never accessed after the function returns?\n\nMostly to avoid re-allocation because this function will be called for\nevery configuration variable. But this may be premature optimization.\nOn top of that, if we go with builtin per-worktree list only as being\ndiscussed, then we can drop exclude machinery, we don't have to\npreprocess \"key\" and we can finally kill this \"strbuf key\".\n\n>> @@ -198,4 +198,30 @@ test_expect_success 'local clone from linked checkout' '\n>> +test_expect_success 'setting worktree.foo goes to config.worktree' '\n>> +       echo worKtree.Foo >> .git/info/config.worktree &&\n>\n> Perhaps? s/>> />/\n\nYeah. In the previous iteration, config.worktree would contain the\ndefault list (core.worktree and stuff) so > may force following tests\nto re-initialize config.worktree again. But that's now gone and >\nmakes more sense.\n\n>> +test_expect_success 'shared config still goes to config' '\n>> +       git config random.key randomValue &&\n>> +       git --git-dir=wt.foo/.git config random.key >actual &&\n>\n> What about also testing the opposite scenario?\n>\n>     git --git-dir=wt.foo/.git  config random.key randomValue &&\n>     git config random.key >actual &&\n\nYep. Will do.\n-- \nDuy\n"},{"id":"275022","messageId":"1451186079-6119-1-git-send-email-pclouds@gmail.com","threadId":"40920","inReplyTo":"1449083626-20075-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v2 0/6] Split .git/config in multiple worktree setup","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2015-12-27T03:14:33Z","receivedAt":"2015-12-27T03:14:33Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"New design. We now define multiworktree behavior with config var\nextensions.worktree. Latest git must support all older behavior\nversions. If config file says \"version 1\", even if latest version is\n3, git must behave like version 1. This covers all aspects of\nmulti-worktree, not just config files.\n\nWith that foundation, we can now build version 1 (version 0 is what\nis already released). Version 1 stores per-worktree config in\n$GIT_DIR/worktrees/.../config. The list of config vars is hard coded.\nNew list requires new worktree version.\n\nThe hard coded list actually supports precise variable name matching,\nor prefix matching (e.g. submodule.*). I don't suppose we need full\nfnmatch to support submodules.\n\ninclude.path is now extended a bit to give the user an opportunity to\nchange the config split. The user can turn a shared config into\nper-worktree (but not the other way around). It's done by allowing env\nexpansion in include.path. So if you specify\n\n    include.path = $GIT_DIR/abc\n\n\"abc\" will always be per-worktree.\n\nUpgrade support is manual (for now). When a new worktree is added, we\ncan bump from version 0 (i.e. extensions.worktree is missing) to 1.\nBut that's it. We can't safely bump 1 to 2 automatically.\n\nThe code in this series is not meant to be run (I didn't even test\nit). It's just in case my C expresses my ideas better than my English.\n\nNguyễn Thái Ngọc Duy (6):\n  Define new repo extension to manage multiple worktree behaviors\n  config.c: move worktree-specific variables to .git/worktrees/...\n  setup.c: remove special case of core.worktree and core.bare\n  worktree: make core.sparseCheckout and core.ignoreStat per-worktree\n  config.c: allow to un-share certain config in multi-worktree setup\n  worktree: bump worktree version to 1 on \"worktree add\"\n\n Documentation/config.txt                       |   4 +\n Documentation/git-worktree.txt                 |  12 ++\n Documentation/gitrepository-layout.txt         |   5 +\n Documentation/technical/repository-version.txt |   9 ++\n builtin/config.c                               |   9 ++\n builtin/worktree.c                             |  33 ++++++\n cache.h                                        |   4 +-\n config.c                                       | 151 +++++++++++++++++++++++--\n environment.c                                  |  14 +++\n setup.c                                        |  65 +++++------\n 10 files changed, 264 insertions(+), 42 deletions(-)\n\n-- \n2.3.0.rc1.137.g477eb31\n"},{"id":"275023","messageId":"1451186079-6119-2-git-send-email-pclouds@gmail.com","threadId":"40920","inReplyTo":"1451186079-6119-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v2 1/6] Define new repo extension to manage multiple worktree behaviors","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2015-12-27T03:14:34Z","receivedAt":"2015-12-27T03:14:34Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Multiple worktree setup is still evolving and its behavior may be\nchanged in future. But we do not want to break existing worktree\nsetups. A new set of extensions, worktree=X, is recognized to tell Git\nwhat multiple worktree \"version\" is being used so that Git can\nbehavior accordingly.\n\nThis extension has no use yet. The first one will be config split.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/technical/repository-version.txt | 6 ++++++\n cache.h                                        | 1 +\n environment.c                                  | 1 +\n setup.c                                        | 3 +++\n 4 files changed, 11 insertions(+)\n\ndiff --git a/Documentation/technical/repository-version.txt b/Documentation/technical/repository-version.txt\nindex 00ad379..c680528 100644\n--- a/Documentation/technical/repository-version.txt\n+++ b/Documentation/technical/repository-version.txt\n@@ -86,3 +86,9 @@ for testing format-1 compatibility.\n When the config key `extensions.preciousObjects` is set to `true`,\n objects in the repository MUST NOT be deleted (e.g., by `git-prune` or\n `git repack -d`).\n+\n+`worktree`\n+~~~~~~~~~~~~~~\n+\n+Define behavior in multiple worktree setup. The value specifies the\n+version. Default version is zero.\ndiff --git a/cache.h b/cache.h\nindex c63fcc1..fa0a64b 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -725,6 +725,7 @@ extern int grafts_replace_parents;\n #define GIT_REPO_VERSION_READ 1\n extern int repository_format_version;\n extern int repository_format_precious_objects;\n+extern int repository_format_worktree_version;\n extern int check_repository_format(void);\n \n #define MTIME_CHANGED\t0x0001\ndiff --git a/environment.c b/environment.c\nindex 2da7fe2..a3f17ed 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -27,6 +27,7 @@ int warn_on_object_refname_ambiguity = 1;\n int ref_paranoia = -1;\n int repository_format_version;\n int repository_format_precious_objects;\n+int repository_format_worktree_version;\n const char *git_commit_encoding;\n const char *git_log_output_encoding;\n int shared_repository = PERM_UMASK;\ndiff --git a/setup.c b/setup.c\nindex d343725..2f41648 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -373,6 +373,9 @@ static int check_repo_format(const char *var, const char *value, void *cb)\n \t\t\t;\n \t\telse if (!strcmp(ext, \"preciousobjects\"))\n \t\t\trepository_format_precious_objects = git_config_bool(var, value);\n+\t\telse if (!strcmp(ext, \"worktree\"))\n+\t\t\trepository_format_worktree_version =\n+\t\t\t\tgit_config_ulong(var, value);\n \t\telse\n \t\t\tstring_list_append(&unknown_extensions, ext);\n \t}\n-- \n2.3.0.rc1.137.g477eb31\n"},{"id":"275017","messageId":"1451186079-6119-3-git-send-email-pclouds@gmail.com","threadId":"40920","inReplyTo":"1451186079-6119-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v2 2/6] config.c: move worktree-specific variables to .git/worktrees/...","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2015-12-27T03:14:35Z","receivedAt":"2015-12-27T03:14:35Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"In multiple worktree setup, a set of variables will be read from\n$GIT_DIR/worktrees/<id>/config instead of $GIT_DIR/config, when the\nconfig variables are accessed from a linked worktree. When accessed\nfrom the main worktree, the same set is still read from $GIT_DIR/config.\n\nThis mechanism is needed because we do have worktree-specific config\nvariables such as core.worktree. But for now, no config variable is\nmarked per-worktree (so can't test yet).\n\nThis is the new behavior when repo extension worktree=1 is defined.\n\nHelped-by: Max Kirillov <max@max630.net>\nHelped-by: Jens Lehmann <Jens.Lehmann@web.de>\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/config.txt               |   4 ++\n Documentation/git-worktree.txt         |  11 +++\n Documentation/gitrepository-layout.txt |   5 ++\n builtin/config.c                       |   9 +++\n cache.h                                |   2 +-\n config.c                               | 121 +++++++++++++++++++++++++++++++--\n setup.c                                |   2 +-\n 7 files changed, 145 insertions(+), 9 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex f617886..d507b8a 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -8,6 +8,10 @@ is used to store the configuration for that repository, and\n fallback values for the `.git/config` file. The file `/etc/gitconfig`\n can be used to store a system-wide default configuration.\n \n+Linked worktrees (see linkgit:git-worktree[1]) also have a\n+worktree-specific file config. See linkgit:gitrepository-layout[5] for\n+more information.\n+\n The configuration variables are used by both the Git plumbing\n and the porcelains. The variables are divided into sections, wherein\n the fully qualified variable name of the variable itself is the last\ndiff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt\nindex 5b9ad04..bc0734c 100644\n--- a/Documentation/git-worktree.txt\n+++ b/Documentation/git-worktree.txt\n@@ -147,6 +147,17 @@ to `/path/main/.git/worktrees/test-next` then a file named\n `test-next` entry from being pruned.  See\n linkgit:gitrepository-layout[5] for details.\n \n+Similar to the file system split in \".git\", the repository config file\n+is also split. Certain variables, for example core.worktree, are\n+per-worktree while the majority of variables are still shared (see\n+linkgit:git-config[1] for details). Shared variables and per-working\n+tree ones that belong to the main working tree are in .git/config.\n+Per-working tree variables for working tree X are in\n+$GIT_COMMON_DIR/worktrees/X/config. Even though per-working tree\n+variables for the main working tree are in the default config place,\n+they are invisible from all linked working trees. The following\n+configuration variables are per working directory:\n+\n LIST OUTPUT FORMAT\n ------------------\n The worktree list command has two output formats.  The default format shows the\ndiff --git a/Documentation/gitrepository-layout.txt b/Documentation/gitrepository-layout.txt\nindex 577ee84..cf724e6 100644\n--- a/Documentation/gitrepository-layout.txt\n+++ b/Documentation/gitrepository-layout.txt\n@@ -276,6 +276,11 @@ worktrees/<id>/link::\n \tfile. It is used to detect if the linked repository is\n \tmanually removed.\n \n+worktrees/<id>/config::\n+\tThis file contains worktree-specific configuration\n+\tvariables. See the list of variables in linkgit:git-worktree[1].\n+\tThe same variables in $GIT_COMMON_DIR/config are ignored.\n+\n SEE ALSO\n --------\n linkgit:git-init[1],\ndiff --git a/builtin/config.c b/builtin/config.c\nindex adc7727..2b4d56e 100644\n--- a/builtin/config.c\n+++ b/builtin/config.c\n@@ -533,6 +533,15 @@ int cmd_config(int argc, const char **argv, const char *prefix)\n \t\tdefault:\n \t\t\tusage_with_options(builtin_config_usage, builtin_config_options);\n \t\t}\n+\n+\t/*\n+\t * For set operations, --local could be either config or\n+\t * config.worktree. Let config.c determine the path based on\n+\t * config keys.\n+\t */\n+\tif (use_local_config && actions != ACTION_LIST)\n+\t\tgiven_config_source.file = NULL;\n+\n \tif (omit_values &&\n \t    !(actions == ACTION_LIST || actions == ACTION_GET_REGEXP)) {\n \t\terror(\"--name-only is only applicable to --list or --get-regexp\");\ndiff --git a/cache.h b/cache.h\nindex fa0a64b..10f4ff8 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1494,7 +1494,7 @@ extern void git_config(config_fn_t fn, void *);\n extern int git_config_with_options(config_fn_t fn, void *,\n \t\t\t\t   struct git_config_source *config_source,\n \t\t\t\t   int respect_includes);\n-extern int git_config_early(config_fn_t fn, void *, const char *repo_config);\n+extern int git_config_early(config_fn_t fn, void *, const char *repo_config, const char *worktree_config);\n extern int git_parse_ulong(const char *, unsigned long *);\n extern int git_parse_maybe_bool(const char *);\n extern int git_config_int(const char *, const char *);\ndiff --git a/config.c b/config.c\nindex 86a5eb2..7d94f21 100644\n--- a/config.c\n+++ b/config.c\n@@ -37,10 +37,25 @@ struct config_source {\n \tlong (*do_ftell)(struct config_source *c);\n };\n \n+struct config_pattern {\n+\tunsigned int prefix;\n+\tunsigned int len;\n+\tconst char *pattern;\n+};\n+\n static struct config_source *cf;\n \n static int zlib_compression_seen;\n \n+static struct config_pattern worktree_v1[] = {\n+\t{ 0, 0, NULL }\n+};\n+\n+static struct config_pattern *worktree_patterns[] = {\n+\tNULL,\n+\tworktree_v1\n+};\n+\n /*\n  * Default config_set that contains key-value pairs from the usual set of config\n  * config files (i.e repo specific .git/config, user wide ~/.gitconfig, XDG\n@@ -89,6 +104,34 @@ static long config_buf_ftell(struct config_source *conf)\n \treturn conf->u.buf.pos;\n }\n \n+static int is_config_local(const char *key_)\n+{\n+\tint len;\n+\tstruct config_pattern *cp;\n+\n+\tif (repository_format_worktree_version < 0 ||\n+\t    repository_format_worktree_version >= ARRAY_SIZE(worktree_patterns))\n+\t\tdie(\"unknown config version %d\", repository_format_worktree_version);\n+\n+\tcp = worktree_patterns[repository_format_worktree_version];\n+\tif (!cp)\n+\t\treturn 0;\n+\tlen = strlen(key_);\n+\tfor (; ; cp++) {\n+\t\tif (!cp->pattern)\n+\t\t\treturn 0;\n+\t\tif (!cp->len)\n+\t\t\tcp->len = strlen(cp->pattern);\n+\t\tif (len < cp->len)\n+\t\t\tcontinue;\n+\t\tif (strncmp(key_, cp->pattern, len))\n+\t\t\tcontinue;\n+\t\tif (!cp->prefix && len > cp->len)\n+\t\t\tcontinue;\n+\t\treturn 1;\n+\t}\n+}\n+\n #define MAX_INCLUDE_DEPTH 10\n static const char include_depth_advice[] =\n \"exceeded maximum include depth (%d) while including\\n\"\n@@ -1184,7 +1227,36 @@ int git_config_system(void)\n \treturn !git_env_bool(\"GIT_CONFIG_NOSYSTEM\", 0);\n }\n \n-int git_config_early(config_fn_t fn, void *data, const char *repo_config)\n+static char *worktree_config_path(void)\n+{\n+\tstruct strbuf sb = STRBUF_INIT;\n+\tstrbuf_addf(&sb, \"%s/config\", get_git_dir());\n+\treturn strbuf_detach(&sb, NULL);\n+}\n+\n+static int config_worktree_filter_in(const char *var,\n+\t\t\t\t     const char *value, void *data)\n+{\n+\tstruct config_include_data *inc = data;\n+\n+\tif (!is_config_local(var))\n+\t\treturn error(\"%s in per-worktree config file is ignored\", var);\n+\treturn inc->fn(var, value, inc->data);\n+}\n+\n+static int config_worktree_filter_out(const char *var,\n+\t\t\t\t      const char *value, void *data)\n+{\n+\tstruct config_include_data *inc = data;\n+\n+\tif (is_config_local(var))\n+\t\treturn 0;\t/* these are for main worktree only */\n+\n+\treturn inc->fn(var, value, inc->data);\n+}\n+\n+int git_config_early(config_fn_t fn, void *data, const char *repo_config,\n+\t\t     const char *worktree_config)\n {\n \tint ret = 0, found = 0;\n \tchar *xdg_config = xdg_config_home(\"config\");\n@@ -1206,7 +1278,23 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)\n \t\tfound += 1;\n \t}\n \n-\tif (repo_config && !access_or_die(repo_config, R_OK, 0)) {\n+\tif (worktree_config) {\n+\t\tstruct config_include_data inc = CONFIG_INCLUDE_INIT;\n+\n+\t\tinc.fn = fn;\n+\t\tinc.data = data;\n+\t\tif (!access_or_die(worktree_config, R_OK, 0)) {\n+\t\t\tret += git_config_from_file(config_worktree_filter_in,\n+\t\t\t\t\t\t    worktree_config, &inc);\n+\t\t\tfound += 1;\n+\t\t}\n+\n+\t\tif (repo_config && !access_or_die(repo_config, R_OK, 0)) {\n+\t\t\tret += git_config_from_file(config_worktree_filter_out,\n+\t\t\t\t\t\t    repo_config, &inc);\n+\t\t\tfound += 1;\n+\t\t}\n+\t} else if (repo_config && !access_or_die(repo_config, R_OK, 0)) {\n \t\tret += git_config_from_file(fn, repo_config, data);\n \t\tfound += 1;\n \t}\n@@ -1232,6 +1320,7 @@ int git_config_with_options(config_fn_t fn, void *data,\n \t\t\t    int respect_includes)\n {\n \tchar *repo_config = NULL;\n+\tchar *worktree_config = NULL;\n \tint ret;\n \tstruct config_include_data inc = CONFIG_INCLUDE_INIT;\n \n@@ -1254,9 +1343,11 @@ int git_config_with_options(config_fn_t fn, void *data,\n \t\treturn git_config_from_blob_ref(fn, config_source->blob, data);\n \n \trepo_config = git_pathdup(\"config\");\n-\tret = git_config_early(fn, data, repo_config);\n-\tif (repo_config)\n-\t\tfree(repo_config);\n+\tif (git_common_dir_env)\n+\t\tworktree_config = worktree_config_path();\n+\tret = git_config_early(fn, data, repo_config, worktree_config);\n+\tfree(repo_config);\n+\tfree(worktree_config);\n \treturn ret;\n }\n \n@@ -1925,6 +2016,23 @@ int git_config_key_is_valid(const char *key)\n \treturn !git_config_parse_key_1(key, NULL, NULL, 1);\n }\n \n+static const char *get_config_filename(const char *config_filename,\n+\t\t\t\t       const char *key,\n+\t\t\t\t       char **filename_buf)\n+{\n+\tif (config_filename)\n+\t\treturn config_filename;\n+\tif (!git_common_dir_env) {\n+\t\tconfig_filename = *filename_buf = git_pathdup(\"config\");\n+\t\treturn config_filename;\n+\t}\n+\tif (!is_config_local(key))\n+\t\tconfig_filename = *filename_buf = git_pathdup(\"config\");\n+\telse\n+\t\tconfig_filename = *filename_buf = worktree_config_path();\n+\treturn config_filename;\n+}\n+\n /*\n  * If value==NULL, unset in (remove from) config,\n  * if value_regex!=NULL, disregard key/value pairs where value does not match.\n@@ -1968,8 +2076,7 @@ int git_config_set_multivar_in_file(const char *config_filename,\n \n \tstore.multi_replace = multi_replace;\n \n-\tif (!config_filename)\n-\t\tconfig_filename = filename_buf = git_pathdup(\"config\");\n+\tconfig_filename = get_config_filename(config_filename, key, &filename_buf);\n \n \t/*\n \t * The lock serves a purpose in addition to locking: the new\ndiff --git a/setup.c b/setup.c\nindex 2f41648..9196945 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -407,7 +407,7 @@ static int check_repository_format_gently(const char *gitdir, int *nongit_ok)\n \t * Use a gentler version of git_config() to check if this repo\n \t * is a good one.\n \t */\n-\tgit_config_early(fn, NULL, repo_config);\n+\tgit_config_early(fn, NULL, repo_config, NULL);\n \tif (GIT_REPO_VERSION_READ < repository_format_version) {\n \t\tif (!nongit_ok)\n \t\t\tdie (\"Expected git repo version <= %d, found %d\",\n-- \n2.3.0.rc1.137.g477eb31\n"},{"id":"275018","messageId":"1451186079-6119-4-git-send-email-pclouds@gmail.com","threadId":"40920","inReplyTo":"1451186079-6119-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v2 3/6] setup.c: remove special case of core.worktree and core.bare","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2015-12-27T03:14:36Z","receivedAt":"2015-12-27T03:14:36Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"core.worktree and core.bare, which are treated specially in 31e26eb [1],\nare now defined per-worktree with repo extension worktree=1 and the\nspecial treatment reverted. The test \"$GIT_DIR/common overrides\ncore.worktree\" in t1501 from 31e26eb verifies that the behavior is\nstill correct after this change.\n\nA note about core.bare. On the surface it does not make sense for\ncore.bare to be worktree specific. It's made so in order to \"grow\" new\nworktrees from a bare repo. In these new linked worktrees, core.bare\nwill be hidden away and worktree-related commands won't complain about\nbare repository.\n\n[1] 31e26eb (setup.c: support multi-checkout repo setup - 2014-11-30)\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/git-worktree.txt                 |  1 +\n Documentation/technical/repository-version.txt |  3 ++\n config.c                                       |  2 +\n setup.c                                        | 68 ++++++++++++--------------\n 4 files changed, 37 insertions(+), 37 deletions(-)\n\ndiff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt\nindex bc0734c..087b35e 100644\n--- a/Documentation/git-worktree.txt\n+++ b/Documentation/git-worktree.txt\n@@ -157,6 +157,7 @@ $GIT_COMMON_DIR/worktrees/X/config. Even though per-working tree\n variables for the main working tree are in the default config place,\n they are invisible from all linked working trees. The following\n configuration variables are per working directory:\n+core.bare, core.worktree.\n \n LIST OUTPUT FORMAT\n ------------------\ndiff --git a/Documentation/technical/repository-version.txt b/Documentation/technical/repository-version.txt\nindex c680528..fc2cdb9 100644\n--- a/Documentation/technical/repository-version.txt\n+++ b/Documentation/technical/repository-version.txt\n@@ -92,3 +92,6 @@ objects in the repository MUST NOT be deleted (e.g., by `git-prune` or\n \n Define behavior in multiple worktree setup. The value specifies the\n version. Default version is zero.\n+\n+In version 1, the following config variables are per-worktree:\n+core.bare, core.worktree.\ndiff --git a/config.c b/config.c\nindex 7d94f21..c2ea91b 100644\n--- a/config.c\n+++ b/config.c\n@@ -48,6 +48,8 @@ static struct config_source *cf;\n static int zlib_compression_seen;\n \n static struct config_pattern worktree_v1[] = {\n+\t{ 0, 0, \"core.bare\" },\n+\t{ 0, 0, \"core.worktree\" },\n \t{ 0, 0, NULL }\n };\n \ndiff --git a/setup.c b/setup.c\nindex 9196945..b49d61e 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -355,46 +355,20 @@ void setup_work_tree(void)\n \tinitialized = 1;\n }\n \n-static int check_repo_format(const char *var, const char *value, void *cb)\n-{\n-\tconst char *ext;\n-\n-\tif (strcmp(var, \"core.repositoryformatversion\") == 0)\n-\t\trepository_format_version = git_config_int(var, value);\n-\telse if (strcmp(var, \"core.sharedrepository\") == 0)\n-\t\tshared_repository = git_config_perm(var, value);\n-\telse if (skip_prefix(var, \"extensions.\", &ext)) {\n-\t\t/*\n-\t\t * record any known extensions here; otherwise,\n-\t\t * we fall through to recording it as unknown, and\n-\t\t * check_repository_format will complain\n-\t\t */\n-\t\tif (!strcmp(ext, \"noop\"))\n-\t\t\t;\n-\t\telse if (!strcmp(ext, \"preciousobjects\"))\n-\t\t\trepository_format_precious_objects = git_config_bool(var, value);\n-\t\telse if (!strcmp(ext, \"worktree\"))\n-\t\t\trepository_format_worktree_version =\n-\t\t\t\tgit_config_ulong(var, value);\n-\t\telse\n-\t\t\tstring_list_append(&unknown_extensions, ext);\n-\t}\n-\treturn 0;\n-}\n-\n static int check_repository_format_gently(const char *gitdir, int *nongit_ok)\n {\n \tstruct strbuf sb = STRBUF_INIT;\n+\tstruct strbuf sb2 = STRBUF_INIT;\n \tconst char *repo_config;\n-\tconfig_fn_t fn;\n+\tconst char *worktree_config = NULL;\n \tint ret = 0;\n \n \tstring_list_clear(&unknown_extensions, 0);\n \n-\tif (get_common_dir(&sb, gitdir))\n-\t\tfn = check_repo_format;\n-\telse\n-\t\tfn = check_repository_format_version;\n+\tif (get_common_dir(&sb, gitdir)) {\n+\t\tstrbuf_addf(&sb2, \"%s/config.worktree\", gitdir);\n+\t\tworktree_config = sb2.buf;\n+\t}\n \tstrbuf_addstr(&sb, \"/config\");\n \trepo_config = sb.buf;\n \n@@ -407,7 +381,8 @@ static int check_repository_format_gently(const char *gitdir, int *nongit_ok)\n \t * Use a gentler version of git_config() to check if this repo\n \t * is a good one.\n \t */\n-\tgit_config_early(fn, NULL, repo_config, NULL);\n+\tgit_config_early(check_repository_format_version, NULL,\n+\t\t\t repo_config, worktree_config);\n \tif (GIT_REPO_VERSION_READ < repository_format_version) {\n \t\tif (!nongit_ok)\n \t\t\tdie (\"Expected git repo version <= %d, found %d\",\n@@ -434,6 +409,7 @@ static int check_repository_format_gently(const char *gitdir, int *nongit_ok)\n \t}\n \n \tstrbuf_release(&sb);\n+\tstrbuf_release(&sb2);\n \treturn ret;\n }\n \n@@ -966,10 +942,28 @@ int git_config_perm(const char *var, const char *value)\n \n int check_repository_format_version(const char *var, const char *value, void *cb)\n {\n-\tint ret = check_repo_format(var, value, cb);\n-\tif (ret)\n-\t\treturn ret;\n-\tif (strcmp(var, \"core.bare\") == 0) {\n+\tconst char *ext;\n+\n+\tif (strcmp(var, \"core.repositoryformatversion\") == 0)\n+\t\trepository_format_version = git_config_int(var, value);\n+\telse if (strcmp(var, \"core.sharedrepository\") == 0)\n+\t\tshared_repository = git_config_perm(var, value);\n+\telse if (skip_prefix(var, \"extensions.\", &ext)) {\n+\t\t/*\n+\t\t * record any known extensions here; otherwise,\n+\t\t * we fall through to recording it as unknown, and\n+\t\t * check_repository_format will complain\n+\t\t */\n+\t\tif (!strcmp(ext, \"noop\"))\n+\t\t\t;\n+\t\telse if (!strcmp(ext, \"preciousobjects\"))\n+\t\t\trepository_format_precious_objects = git_config_bool(var, value);\n+\t\telse if (!strcmp(ext, \"worktree\"))\n+\t\t\trepository_format_worktree_version =\n+\t\t\t\tgit_config_ulong(var, value);\n+\t\telse\n+\t\t\tstring_list_append(&unknown_extensions, ext);\n+\t} else if (strcmp(var, \"core.bare\") == 0) {\n \t\tis_bare_repository_cfg = git_config_bool(var, value);\n \t\tif (is_bare_repository_cfg == 1)\n \t\t\tinside_work_tree = -1;\n-- \n2.3.0.rc1.137.g477eb31\n"},{"id":"275019","messageId":"1451186079-6119-5-git-send-email-pclouds@gmail.com","threadId":"40920","inReplyTo":"1451186079-6119-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v2 4/6] worktree: make core.sparseCheckout and core.ignoreStat per-worktree","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2015-12-27T03:14:37Z","receivedAt":"2015-12-27T03:14:37Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"The first one must be per-worktree because info/sparse-checkout\nalready is. The second one shares the same nature and should also be\nper-worktree.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/git-worktree.txt                 | 2 +-\n Documentation/technical/repository-version.txt | 2 +-\n config.c                                       | 2 ++\n 3 files changed, 4 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt\nindex 087b35e..bc6a26e 100644\n--- a/Documentation/git-worktree.txt\n+++ b/Documentation/git-worktree.txt\n@@ -157,7 +157,7 @@ $GIT_COMMON_DIR/worktrees/X/config. Even though per-working tree\n variables for the main working tree are in the default config place,\n they are invisible from all linked working trees. The following\n configuration variables are per working directory:\n-core.bare, core.worktree.\n+core.bare, core.ignorestat, core.sparsecheckout, core.worktree.\n \n LIST OUTPUT FORMAT\n ------------------\ndiff --git a/Documentation/technical/repository-version.txt b/Documentation/technical/repository-version.txt\nindex fc2cdb9..4fc113b 100644\n--- a/Documentation/technical/repository-version.txt\n+++ b/Documentation/technical/repository-version.txt\n@@ -94,4 +94,4 @@ Define behavior in multiple worktree setup. The value specifies the\n version. Default version is zero.\n \n In version 1, the following config variables are per-worktree:\n-core.bare, core.worktree.\n+core.bare, core.ignorestat, core.sparsecheckout, core.worktree.\ndiff --git a/config.c b/config.c\nindex c2ea91b..5aa1379 100644\n--- a/config.c\n+++ b/config.c\n@@ -49,6 +49,8 @@ static int zlib_compression_seen;\n \n static struct config_pattern worktree_v1[] = {\n \t{ 0, 0, \"core.bare\" },\n+\t{ 0, 0, \"core.ignorestat\" },\n+\t{ 0, 0, \"core.sparsecheckout\" },\n \t{ 0, 0, \"core.worktree\" },\n \t{ 0, 0, NULL }\n };\n-- \n2.3.0.rc1.137.g477eb31\n"},{"id":"275020","messageId":"1451186079-6119-6-git-send-email-pclouds@gmail.com","threadId":"40920","inReplyTo":"1451186079-6119-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v2 5/6] config.c: allow to un-share certain config in multi-worktree setup","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2015-12-27T03:14:38Z","receivedAt":"2015-12-27T03:14:38Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Repo ext worktree=1 provides a set of config vars that _must_ be\nper-worktree. However, the user may want to make some more config vars\nper-worktree, depending on their workflow.\n\ninclude.path is extended to make this possible. If the given path is\nin the form \"$GIT_xyz/abc\" then \"$GIT_xyz\" will be expanded using the\ncorresponding environment variable. To unshare, the user can save\nconfig in, for example, $GIT_DIR/worktrees/<id>/config.worktree and\nspecify this in $GIT_DIR/config\n\n    include.path = $GIT_DIR/config.worktree\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n cache.h       |  1 +\n config.c      | 26 ++++++++++++++++++++++++++\n environment.c | 13 +++++++++++++\n 3 files changed, 40 insertions(+)\n\ndiff --git a/cache.h b/cache.h\nindex 10f4ff8..cc00ca1 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -454,6 +454,7 @@ extern int is_bare_repository(void);\n extern int is_inside_git_dir(void);\n extern char *git_work_tree_cfg;\n extern int is_inside_work_tree(void);\n+extern const char *get_git_env(const char *name);\n extern const char *get_git_dir(void);\n extern const char *get_git_common_dir(void);\n extern int is_git_directory(const char *path);\ndiff --git a/config.c b/config.c\nindex 5aa1379..eb951f5 100644\n--- a/config.c\n+++ b/config.c\n@@ -155,6 +155,32 @@ static int handle_path_include(const char *path, struct config_include_data *inc\n \texpanded = expand_user_path(path);\n \tif (!expanded)\n \t\treturn error(\"Could not expand include path '%s'\", path);\n+\n+\tif (starts_with(expanded, \"$GIT_\")) {\n+\t\tchar *slash = expanded;\n+\t\tconst char *base = NULL;\n+\t\tstruct strbuf sb = STRBUF_INIT;\n+\n+\t\twhile (*slash && !is_dir_sep(*slash))\n+\t\t\tslash++;\n+\n+\t\tif (*slash) {\n+\t\t\tchar saved_slash = *slash;\n+\t\t\t*slash = '\\0';\n+\t\t\tbase = get_git_env(expanded + 1);\n+\t\t\t*slash = saved_slash;\n+\t\t}\n+\n+\t\tif (!base) {\n+\t\t\tfree(expanded);\n+\t\t\treturn error(\"Could not expand include path '%s'\", path);\n+\t\t}\n+\n+\t\tstrbuf_addstr(&sb, real_path(base));\n+\t\tstrbuf_addstr(&sb, slash);\n+\t\tfree(expanded);\n+\t\texpanded = strbuf_detach(&sb, NULL);\n+\t}\n \tpath = expanded;\n \n \t/*\ndiff --git a/environment.c b/environment.c\nindex a3f17ed..7a1d62e 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -321,3 +321,16 @@ const char *get_commit_output_encoding(void)\n {\n \treturn git_commit_encoding ? git_commit_encoding : \"UTF-8\";\n }\n+\n+const char *get_git_env(const char *name)\n+{\n+\tif (!strcmp(name, GIT_DIR_ENVIRONMENT))\n+\t\treturn get_git_dir();\n+\telse if (!strcmp(name, GIT_WORK_TREE_ENVIRONMENT))\n+\t\treturn get_git_work_tree();\n+\telse if (!strcmp(name, GIT_COMMON_DIR_ENVIRONMENT))\n+\t\treturn get_git_common_dir();\n+\t// else if ... check environment.c\n+\telse\n+\t\treturn getenv(name);\n+}\n-- \n2.3.0.rc1.137.g477eb31\n"},{"id":"275021","messageId":"1451186079-6119-7-git-send-email-pclouds@gmail.com","threadId":"40920","inReplyTo":"1451186079-6119-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v2 6/6] worktree: bump worktree version to 1 on \"worktree add\"","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2015-12-27T03:14:39Z","receivedAt":"2015-12-27T03:14:39Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/worktree.c | 33 +++++++++++++++++++++++++++++++++\n 1 file changed, 33 insertions(+)\n\ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex 475b958..2ec9c36 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -184,6 +184,37 @@ static const char *worktree_basename(const char *path, int *olen)\n \treturn name;\n }\n \n+static int git_config_set_int(const char *key, int value)\n+{\n+\tstruct strbuf sb = STRBUF_INIT;\n+\tint ret;\n+\n+\tstrbuf_addf(&sb, \"%d\", value);\n+\tret = git_config_set(key, sb.buf);\n+\tstrbuf_release(&sb);\n+\treturn ret;\n+}\n+\n+static void upgrade_worktree_version(void)\n+{\n+\tif (repository_format_worktree_version != 0)\n+\t\t/*\n+\t\t * XXX: anything else to do when upgrading from\n+\t\t * version X to Y? Also, the user may want to stick to\n+\t\t * a particular version if multiple git versions\n+\t\t * operate on this repo. In that case, do not\n+\t\t * automatically bump version up.\n+\t\t */\n+\t\treturn;\n+\trepository_format_worktree_version = 1;\n+\tif (repository_format_version < 2)\n+\t\trepository_format_version = 2;\n+\tgit_config_set_int(\"core.repositoryformatversion\",\n+\t\t\t   repository_format_version);\n+\tgit_config_set_int(\"extensions.worktree\",\n+\t\t\t   repository_format_worktree_version);\n+}\n+\n static int add_worktree(const char *path, const char *refname,\n \t\t\tconst struct add_opts *opts)\n {\n@@ -268,6 +299,8 @@ static int add_worktree(const char *path, const char *refname,\n \tstrbuf_addf(&sb, \"%s/commondir\", sb_repo.buf);\n \twrite_file(sb.buf, \"../..\");\n \n+\tupgrade_worktree_version();\n+\n \tfprintf_ln(stderr, _(\"Preparing %s (identifier %s)\"), path, name);\n \n \targv_array_pushf(&child_env, \"%s=%s\", GIT_DIR_ENVIRONMENT, sb_git.buf);\n-- \n2.3.0.rc1.137.g477eb31\n"},{"id":"275721","messageId":"20160111224350.GA10955@wheezy.local","threadId":"40920","inReplyTo":"1451186079-6119-1-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH v2 0/6] Split .git/config in multiple worktree setup","fromName":"Max Kirillov","fromEmail":"max@max630.net","sentAt":"2016-01-11T22:43:50Z","receivedAt":"2016-01-11T22:43:50Z","isPatch":true,"sender":{"key":"max@max630.net","avatar":"https://avatars.githubusercontent.com/u/381560?v=4"},"body":"Hi.\n\nOn Sun, Dec 27, 2015 at 10:14:33AM +0700, Nguyễn Thái Ngọc Duy wrote:\n> Upgrade support is manual (for now). When a new worktree is added, we\n> can bump from version 0 (i.e. extensions.worktree is missing) to 1.\n> But that's it. We can't safely bump 1 to 2 automatically.\n\nMaybe, bumping should happen only if there is no worktree so\nfar. If there is already, then worktree left to be 0 or\nwhatever it is. Then it can be bumped directly to the last\nsupported version.\n\nOtherwise sounds ok. I have checked how it works and did not\nread the code carefully, since you it's not ready yet.\n\n-- \nMax\n"},{"id":"276782","messageId":"1453808685-21235-1-git-send-email-pclouds@gmail.com","threadId":"40920","inReplyTo":"1451186079-6119-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v3 0/6] Split .git/config in multiple worktree setup","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-01-26T11:44:39Z","receivedAt":"2016-01-26T11:44:39Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"I've changed my mind. So v3 is not a polished v2. It's quite different.\nAnd I hope it's good different.\n\nIn v2, .git/config contains both shared part and the per-worktree part\n(for main worktree). It's ugly, slow and hard to work with. v3 adds a\ncompletly new config file for sharing. \".git/config\" will not be shared\nany more.\n\nFor any worktree, the new file .git/common/config is read first, then\neither .git/config or .git/worktrees/xxx/config is read after. There's\nno special per-worktree var list any more. Which is great. You want to\nadd per-worktree config vars, use \"git config --local\". You want to\nadd per-repo config vars, use (new) \"git config --repo\". You put a\nvariable in a wrong file, you're punished for it (and it's the same\ntoday, say if you put core.worktree to /etc/gitconfig).\n\nThe only ugly part I see is how to deal with released git binaries,\nhow to make it reject the new config split (because otherwise it would\nread incorrectly).\n\nA lot more explanation is in patch 04/06. The series is also\navailable at https://github.com/pclouds/git/tree/worktree-config\n\nNguyễn Thái Ngọc Duy (6):\n  worktree: new repo extension to manage worktree behaviors\n  path.c: new (identical) list for worktree v1\n  worktree: share .git/common in v1\n  worktree: new config file hierarchy\n  config: select .git/common/config with --repo\n  worktree add: switch to worktree version 1\n\n Documentation/config.txt                       |   5 +-\n Documentation/git-config.txt                   |  14 +++-\n Documentation/git-worktree.txt                 |  31 +++++++-\n Documentation/gitrepository-layout.txt         |  12 +++\n Documentation/technical/repository-version.txt |   6 ++\n builtin/config.c                               |  19 +++--\n builtin/worktree.c                             |  95 ++++++++++++++++++++++\n cache.h                                        |   5 +-\n config.c                                       |  14 +++-\n environment.c                                  |   1 +\n path.c                                         |  40 +++++++++-\n setup.c                                        |  40 ++++++++--\n t/t2028-worktree-config.sh (new +x)            | 104 +++++++++++++++++++++++++\n 13 files changed, 364 insertions(+), 22 deletions(-)\n create mode 100755 t/t2028-worktree-config.sh\n\n-- \n2.7.0.288.g1d8ad15\n"},{"id":"276783","messageId":"1453808685-21235-2-git-send-email-pclouds@gmail.com","threadId":"40920","inReplyTo":"1453808685-21235-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v3 1/6] worktree: new repo extension to manage worktree behaviors","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-01-26T11:44:40Z","receivedAt":"2016-01-26T11:44:40Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Multiple worktree setup is still evolving and its behavior may be\nchanged in future. But we do not want to break existing worktree\nsetups. A new set of extensions, worktree=X, is recognized to tell Git\nwhat multiple worktree \"version\" is being used so that Git can\nbehavior accordingly.\n\nThis extension has no use yet. The first one will be config split.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/git-worktree.txt                 | 12 ++++++++++++\n Documentation/technical/repository-version.txt |  6 ++++++\n cache.h                                        |  1 +\n environment.c                                  |  1 +\n setup.c                                        |  3 +++\n 5 files changed, 23 insertions(+)\n\ndiff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt\nindex 5b9ad04..048d7d6 100644\n--- a/Documentation/git-worktree.txt\n+++ b/Documentation/git-worktree.txt\n@@ -106,6 +106,18 @@ OPTIONS\n --expire <time>::\n \tWith `prune`, only expire unused working trees older than <time>.\n \n+WORKTREE VERSIONS AND MIGRATION\n+-------------------------------\n+Multiple worktree is still an experimental feature and evolving. Every\n+time the behavior is changed, the \"worktree version\" is stepped\n+up. Worktree version is stored as a configuration variable\n+extensions.worktree.\n+\n+Version 0\n+~~~~~~~~~\n+This is the first release. Version 0 is implied if extensions.worktree\n+does not exist.\n+\n DETAILS\n -------\n Each linked working tree has a private sub-directory in the repository's\ndiff --git a/Documentation/technical/repository-version.txt b/Documentation/technical/repository-version.txt\nindex 00ad379..e4583c5 100644\n--- a/Documentation/technical/repository-version.txt\n+++ b/Documentation/technical/repository-version.txt\n@@ -86,3 +86,9 @@ for testing format-1 compatibility.\n When the config key `extensions.preciousObjects` is set to `true`,\n objects in the repository MUST NOT be deleted (e.g., by `git-prune` or\n `git repack -d`).\n+\n+`worktree`\n+~~~~~~~~~~\n+\n+Define behavior in multiple worktree setup. The value specifies the\n+version. Default version is zero.\ndiff --git a/cache.h b/cache.h\nindex dfc459c..e742c46 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -727,6 +727,7 @@ extern int grafts_replace_parents;\n #define GIT_REPO_VERSION_READ 1\n extern int repository_format_version;\n extern int repository_format_precious_objects;\n+extern int repository_format_worktree_version;\n extern int check_repository_format(void);\n \n #define MTIME_CHANGED\t0x0001\ndiff --git a/environment.c b/environment.c\nindex 1cc4aab..1bd4a56 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -27,6 +27,7 @@ int warn_on_object_refname_ambiguity = 1;\n int ref_paranoia = -1;\n int repository_format_version;\n int repository_format_precious_objects;\n+int repository_format_worktree_version;\n const char *git_commit_encoding;\n const char *git_log_output_encoding;\n int shared_repository = PERM_UMASK;\ndiff --git a/setup.c b/setup.c\nindex d343725..2f41648 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -373,6 +373,9 @@ static int check_repo_format(const char *var, const char *value, void *cb)\n \t\t\t;\n \t\telse if (!strcmp(ext, \"preciousobjects\"))\n \t\t\trepository_format_precious_objects = git_config_bool(var, value);\n+\t\telse if (!strcmp(ext, \"worktree\"))\n+\t\t\trepository_format_worktree_version =\n+\t\t\t\tgit_config_ulong(var, value);\n \t\telse\n \t\t\tstring_list_append(&unknown_extensions, ext);\n \t}\n-- \n2.7.0.288.g1d8ad15\n"},{"id":"276785","messageId":"1453808685-21235-3-git-send-email-pclouds@gmail.com","threadId":"40920","inReplyTo":"1453808685-21235-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v3 2/6] path.c: new (identical) list for worktree v1","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-01-26T11:44:41Z","receivedAt":"2016-01-26T11:44:41Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Worktree v1 may have different .git file split than v0. Add support\ncode to change common file list based on extensions.worktree. The list\nfor now is identical to v0.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n path.c | 40 +++++++++++++++++++++++++++++++++++++---\n 1 file changed, 37 insertions(+), 3 deletions(-)\n\ndiff --git a/path.c b/path.c\nindex 3cd155e..14adf5d 100644\n--- a/path.c\n+++ b/path.c\n@@ -100,7 +100,7 @@ struct common_dir {\n \tconst char *dirname;\n };\n \n-static struct common_dir common_list[] = {\n+static struct common_dir common_list_v0[] = {\n \t{ 0, 1, 0, \"branches\" },\n \t{ 0, 1, 0, \"hooks\" },\n \t{ 0, 1, 0, \"info\" },\n@@ -123,6 +123,40 @@ static struct common_dir common_list[] = {\n \t{ 0, 0, 0, NULL }\n };\n \n+static struct common_dir common_list_v1[] = {\n+\t{ 0, 1, 0, \"branches\" },\n+\t{ 0, 1, 0, \"hooks\" },\n+\t{ 0, 1, 0, \"info\" },\n+\t{ 0, 0, 1, \"info/sparse-checkout\" },\n+\t{ 1, 1, 0, \"logs\" },\n+\t{ 1, 1, 1, \"logs/HEAD\" },\n+\t{ 0, 1, 1, \"logs/refs/bisect\" },\n+\t{ 0, 1, 0, \"lost-found\" },\n+\t{ 0, 1, 0, \"objects\" },\n+\t{ 0, 1, 0, \"refs\" },\n+\t{ 0, 1, 1, \"refs/bisect\" },\n+\t{ 0, 1, 0, \"remotes\" },\n+\t{ 0, 1, 0, \"worktrees\" },\n+\t{ 0, 1, 0, \"rr-cache\" },\n+\t{ 0, 1, 0, \"svn\" },\n+\t{ 0, 0, 0, \"config\" },\n+\t{ 1, 0, 0, \"gc.pid\" },\n+\t{ 0, 0, 0, \"packed-refs\" },\n+\t{ 0, 0, 0, \"shallow\" },\n+\t{ 0, 0, 0, NULL }\n+};\n+\n+static struct common_dir *get_common_list(void)\n+{\n+\tswitch (repository_format_worktree_version) {\n+\tcase 0: return common_list_v0;\n+\tcase 1: return common_list_v1;\n+\tdefault:\n+\t\tdie(_(\"unsupported worktree format version %d\"),\n+\t\t    repository_format_worktree_version);\n+\t}\n+}\n+\n /*\n  * A compressed trie.  A trie node consists of zero or more characters that\n  * are common to all elements with this prefix, optionally followed by some\n@@ -309,7 +343,7 @@ static void init_common_trie(void)\n \tif (common_trie_done_setup)\n \t\treturn;\n \n-\tfor (p = common_list; p->dirname; p++)\n+\tfor (p = get_common_list(); p->dirname; p++)\n \t\tadd_to_trie(&common_trie, p->dirname, p);\n \n \tcommon_trie_done_setup = 1;\n@@ -356,7 +390,7 @@ void report_linked_checkout_garbage(void)\n \t\treturn;\n \tstrbuf_addf(&sb, \"%s/\", get_git_dir());\n \tlen = sb.len;\n-\tfor (p = common_list; p->dirname; p++) {\n+\tfor (p = get_common_list(); p->dirname; p++) {\n \t\tconst char *path = p->dirname;\n \t\tif (p->ignore_garbage)\n \t\t\tcontinue;\n-- \n2.7.0.288.g1d8ad15\n"},{"id":"276784","messageId":"1453808685-21235-4-git-send-email-pclouds@gmail.com","threadId":"40920","inReplyTo":"1453808685-21235-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v3 3/6] worktree: share .git/common in v1","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-01-26T11:44:42Z","receivedAt":"2016-01-26T11:44:42Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/gitrepository-layout.txt | 4 ++++\n path.c                                 | 1 +\n 2 files changed, 5 insertions(+)\n\ndiff --git a/Documentation/gitrepository-layout.txt b/Documentation/gitrepository-layout.txt\nindex 577ee84..771e362 100644\n--- a/Documentation/gitrepository-layout.txt\n+++ b/Documentation/gitrepository-layout.txt\n@@ -250,6 +250,10 @@ commondir::\n modules::\n \tContains the git-repositories of the submodules.\n \n+common::\n+\tThis directory is seen from all working directories. It is\n+\tmeant to share files that all working directories can see.\n+\n worktrees::\n \tContains administrative data for linked\n \tworking trees. Each subdirectory contains the working tree-related\ndiff --git a/path.c b/path.c\nindex 14adf5d..3b85968 100644\n--- a/path.c\n+++ b/path.c\n@@ -124,6 +124,7 @@ static struct common_dir common_list_v0[] = {\n };\n \n static struct common_dir common_list_v1[] = {\n+\t{ 0, 1, 0, \"common\" },\n \t{ 0, 1, 0, \"branches\" },\n \t{ 0, 1, 0, \"hooks\" },\n \t{ 0, 1, 0, \"info\" },\n-- \n2.7.0.288.g1d8ad15\n"},{"id":"276786","messageId":"1453808685-21235-5-git-send-email-pclouds@gmail.com","threadId":"40920","inReplyTo":"1453808685-21235-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v3 4/6] worktree: new config file hierarchy","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-01-26T11:44:43Z","receivedAt":"2016-01-26T11:44:43Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"($C stands for $GIT_COMMON_DIR for the rest of the message)\n\nIn main worktree, we read these config files in this order:\n\n1) system config\n2) XDG config\n3) user config\n4) $GIT_DIR/config\n\nCurrently linked worktrees share the same config file at step 4 with\nmain worktree. The problem is, not all config variables can be\nshared. We need per-repo vars and per-worktree ones.\n\nWith this patch, since worktree v1, the repo config file (or worktree\nconfig file in multi worktree context) is no longer shared. Main\nworktree reads $C/config.  Linked worktrees read $C/worktrees/xxx/config\nand a new file, $C/worktrees/config. Sharing is done via this new\nfile. The read hierarchy for a worktree becomes\n\n1) system config\n2) XDG config\n3) user config\n4) $C/common/config\n5) $C/worktrees/xxx/config (or $C/config for main worktree)\n\nCompare to an alternative scheme where $C/config contains both shared\nvariables and main-worktree-only ones, this is a cleaner design.\n\n* We do not have to check every single variable name to see if it's\n  shared or per-worktree when reading config files.\n\n* We do not enforce any particular variable split. If a variable\n  is in $C/worktrees/config, it is shared. Putting core.worktree in\n  $C/worktrees/config is punished the same way the variable is put in\n  $HOME/.gitconfig, for example.\n\n* We will provide a new \"git config --repo\" to access this new config\n  file. In single-worktree context, or worktree v0, --repo is an alias\n  of --local.\n\nThere is one problem though. We store worktree version in config file\nand expect that all worktrees must share the same version (i.e. read\nthe same config file). But the share-ness of per-repo config files is\nchanged based on worktree version. Where do we put extensions.worktree\nthen?\n\nWorktree version detection is tweaked a bit in this case. The presence\nof $C/worktrees/config implies worktree version 1+. The lack of it\nimplies wortree version 0.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/config.txt               |  5 +++--\n Documentation/git-worktree.txt         |  8 ++++++-\n Documentation/gitrepository-layout.txt |  8 +++++++\n cache.h                                |  4 +++-\n config.c                               | 14 ++++++++++--\n path.c                                 |  1 -\n setup.c                                | 37 +++++++++++++++++++++++++------\n t/t2028-worktree-config.sh (new +x)    | 40 ++++++++++++++++++++++++++++++++++\n 8 files changed, 103 insertions(+), 14 deletions(-)\n create mode 100755 t/t2028-worktree-config.sh\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 07f7a3b..5009d98 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -2,8 +2,9 @@ CONFIGURATION FILE\n ------------------\n \n The Git configuration file contains a number of variables that affect\n-the Git commands' behavior. The `.git/config` file in each repository\n-is used to store the configuration for that repository, and\n+the Git commands' behavior. The files `.git/config` and\n+`.git/common/config` (see linkgit:git-worktree.txt[1]) are each\n+repository is used to store the configuration for that repository, and\n `$HOME/.gitconfig` is used to store a per-user configuration as\n fallback values for the `.git/config` file. The file `/etc/gitconfig`\n can be used to store a system-wide default configuration.\ndiff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt\nindex 048d7d6..0846f2a 100644\n--- a/Documentation/git-worktree.txt\n+++ b/Documentation/git-worktree.txt\n@@ -111,7 +111,13 @@ WORKTREE VERSIONS AND MIGRATION\n Multiple worktree is still an experimental feature and evolving. Every\n time the behavior is changed, the \"worktree version\" is stepped\n up. Worktree version is stored as a configuration variable\n-extensions.worktree.\n+extensions.worktree. Latest version is one.\n+\n+Version 1\n+~~~~~~~~~\n+In this version, the repository config file `.git/config` is not\n+shared anymore. A new file, `.git/common/config`, read for all\n+worktrees. Shared configuration should be stored here.\n \n Version 0\n ~~~~~~~~~\ndiff --git a/Documentation/gitrepository-layout.txt b/Documentation/gitrepository-layout.txt\nindex 771e362..d65345d 100644\n--- a/Documentation/gitrepository-layout.txt\n+++ b/Documentation/gitrepository-layout.txt\n@@ -261,6 +261,11 @@ worktrees::\n \t$GIT_COMMON_DIR is set, in which case\n \t\"$GIT_COMMON_DIR/worktrees\" will be used instead.\n \n+common/config::\n+\tRepository specific configuration file. Note that if this file\n+\tis present, it must contain the variable extensions.worktree\n+\twhose value must be one or above.\n+\n worktrees/<id>/gitdir::\n \tA text file containing the absolute path back to the .git file\n \tthat points to here. This is used to check if the linked\n@@ -280,6 +285,9 @@ worktrees/<id>/link::\n \tfile. It is used to detect if the linked repository is\n \tmanually removed.\n \n+worktrees/<id>/config::\n+\tWorking tree specific configuration file.\n+\n SEE ALSO\n --------\n linkgit:git-init[1],\ndiff --git a/cache.h b/cache.h\nindex e742c46..fa5e451 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1497,7 +1497,9 @@ extern void git_config(config_fn_t fn, void *);\n extern int git_config_with_options(config_fn_t fn, void *,\n \t\t\t\t   struct git_config_source *config_source,\n \t\t\t\t   int respect_includes);\n-extern int git_config_early(config_fn_t fn, void *, const char *repo_config);\n+extern int git_config_early(config_fn_t fn, void *,\n+\t\t\t    const char *repo_common_config,\n+\t\t\t    const char *repo_config);\n extern int git_parse_ulong(const char *, unsigned long *);\n extern int git_parse_maybe_bool(const char *);\n extern int git_config_int(const char *, const char *);\ndiff --git a/config.c b/config.c\nindex 86a5eb2..a75926e 100644\n--- a/config.c\n+++ b/config.c\n@@ -1184,7 +1184,9 @@ int git_config_system(void)\n \treturn !git_env_bool(\"GIT_CONFIG_NOSYSTEM\", 0);\n }\n \n-int git_config_early(config_fn_t fn, void *data, const char *repo_config)\n+int git_config_early(config_fn_t fn, void *data,\n+\t\t     const char *repo_common_config,\n+\t\t     const char *repo_config)\n {\n \tint ret = 0, found = 0;\n \tchar *xdg_config = xdg_config_home(\"config\");\n@@ -1206,6 +1208,11 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)\n \t\tfound += 1;\n \t}\n \n+\tif (repo_common_config && !access_or_die(repo_common_config, R_OK, 0)) {\n+\t\tret += git_config_from_file(fn, repo_common_config, data);\n+\t\tfound += 1;\n+\t}\n+\n \tif (repo_config && !access_or_die(repo_config, R_OK, 0)) {\n \t\tret += git_config_from_file(fn, repo_config, data);\n \t\tfound += 1;\n@@ -1231,6 +1238,7 @@ int git_config_with_options(config_fn_t fn, void *data,\n \t\t\t    struct git_config_source *config_source,\n \t\t\t    int respect_includes)\n {\n+\tstruct strbuf repo_common_config = STRBUF_INIT;\n \tchar *repo_config = NULL;\n \tint ret;\n \tstruct config_include_data inc = CONFIG_INCLUDE_INIT;\n@@ -1253,10 +1261,12 @@ int git_config_with_options(config_fn_t fn, void *data,\n \telse if (config_source && config_source->blob)\n \t\treturn git_config_from_blob_ref(fn, config_source->blob, data);\n \n+\tstrbuf_addf(&repo_common_config, \"%s/common/config\", get_git_common_dir());\n \trepo_config = git_pathdup(\"config\");\n-\tret = git_config_early(fn, data, repo_config);\n+\tret = git_config_early(fn, data, repo_common_config.buf, repo_config);\n \tif (repo_config)\n \t\tfree(repo_config);\n+\tstrbuf_release(&repo_common_config);\n \treturn ret;\n }\n \ndiff --git a/path.c b/path.c\nindex 3b85968..aee9f59 100644\n--- a/path.c\n+++ b/path.c\n@@ -140,7 +140,6 @@ static struct common_dir common_list_v1[] = {\n \t{ 0, 1, 0, \"worktrees\" },\n \t{ 0, 1, 0, \"rr-cache\" },\n \t{ 0, 1, 0, \"svn\" },\n-\t{ 0, 0, 0, \"config\" },\n \t{ 1, 0, 0, \"gc.pid\" },\n \t{ 0, 0, 0, \"packed-refs\" },\n \t{ 0, 0, 0, \"shallow\" },\ndiff --git a/setup.c b/setup.c\nindex 2f41648..7ca8ebe 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -385,18 +385,32 @@ static int check_repo_format(const char *var, const char *value, void *cb)\n static int check_repository_format_gently(const char *gitdir, int *nongit_ok)\n {\n \tstruct strbuf sb = STRBUF_INIT;\n+\tstruct strbuf sb2 = STRBUF_INIT;\n+\tstruct strbuf sb3 = STRBUF_INIT;\n \tconst char *repo_config;\n+\tconst char *repo_common_config;\n \tconfig_fn_t fn;\n-\tint ret = 0;\n+\tint ret = 0, has_common_dir;\n \n \tstring_list_clear(&unknown_extensions, 0);\n \n-\tif (get_common_dir(&sb, gitdir))\n-\t\tfn = check_repo_format;\n-\telse\n+\thas_common_dir = get_common_dir(&sb, gitdir);\n+\tstrbuf_addf(&sb2, \"%s/common/config\", sb.buf);\n+\n+\tif (access(sb2.buf, F_OK) == -1) { /* worktree v0 */\n+\t\tif (has_common_dir)\n+\t\t\tfn = check_repo_format;\n+\t\telse\n+\t\t\tfn = check_repository_format_version;\n+\t\tstrbuf_addf(&sb3, \"%s/config\", sb.buf);\n+\t\trepo_common_config = NULL;\n+\t\trepo_config = sb3.buf;\n+\t} else {\n \t\tfn = check_repository_format_version;\n-\tstrbuf_addstr(&sb, \"/config\");\n-\trepo_config = sb.buf;\n+\t\tstrbuf_addf(&sb3, \"%s/config\", gitdir);\n+\t\trepo_common_config = sb2.buf;\n+\t\trepo_config = sb3.buf;\n+\t}\n \n \t/*\n \t * git_config() can't be used here because it calls git_pathdup()\n@@ -407,7 +421,7 @@ static int check_repository_format_gently(const char *gitdir, int *nongit_ok)\n \t * Use a gentler version of git_config() to check if this repo\n \t * is a good one.\n \t */\n-\tgit_config_early(fn, NULL, repo_config);\n+\tgit_config_early(fn, NULL, repo_common_config, repo_config);\n \tif (GIT_REPO_VERSION_READ < repository_format_version) {\n \t\tif (!nongit_ok)\n \t\t\tdie (\"Expected git repo version <= %d, found %d\",\n@@ -433,7 +447,16 @@ static int check_repository_format_gently(const char *gitdir, int *nongit_ok)\n \t\tret = -1;\n \t}\n \n+\tif (repo_common_config && repository_format_worktree_version < 1)\n+\t\tdie(_(\"worktree version must be one minimum in the presence of %s\"),\n+\t\t    repo_common_config);\n+\tif (!repo_common_config && repository_format_worktree_version > 0)\n+\t\tdie(_(\"worktree version must be zero if %s/common/config does not exist\"),\n+\t\t    gitdir);\n+\n \tstrbuf_release(&sb);\n+\tstrbuf_release(&sb2);\n+\tstrbuf_release(&sb3);\n \treturn ret;\n }\n \ndiff --git a/t/t2028-worktree-config.sh b/t/t2028-worktree-config.sh\nnew file mode 100755\nindex 0000000..5561788\n--- /dev/null\n+++ b/t/t2028-worktree-config.sh\n@@ -0,0 +1,40 @@\n+#!/bin/sh\n+\n+test_description=\"config file in multi worktree\"\n+\n+. ./test-lib.sh\n+\n+test_expect_success 'setup' '\n+\ttest_commit start &&\n+\tgit worktree add wt1 &&\n+\tgit worktree add wt2\n+'\n+\n+test_expect_success 'main config is shared in version 0' '\n+\tgit config -f .git/config wt.name main &&\n+\tgit config wt.name >actual &&\n+\techo main >expected &&\n+\ttest_cmp expected actual &&\n+\tgit -C wt1 config wt.name >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'main config is for main worktree only (v1)' '\n+\tmkdir .git/common &&\n+\tgit config -f .git/common/config extensions.worktree 1 &&\n+\tgit config wt.name >actual &&\n+\techo main >expected &&\n+\ttest_cmp expected actual &&\n+\ttest_must_fail git -C wt1 config wt.name\n+'\n+\n+test_expect_success 'worktrees/config is shared (v1)' '\n+\tgit config -f .git/common/config some.thing is-shared &&\n+\techo is-shared >expected &&\n+\tgit config some.thing >actual &&\n+\ttest_cmp expected actual &&\n+\tgit -C wt1 config some.thing >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_done\n-- \n2.7.0.288.g1d8ad15\n"},{"id":"276788","messageId":"1453808685-21235-6-git-send-email-pclouds@gmail.com","threadId":"40920","inReplyTo":"1453808685-21235-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v3 5/6] config: select .git/common/config with --repo","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-01-26T11:44:44Z","receivedAt":"2016-01-26T11:44:44Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This new option allows the user to write to or read from\n.git/common/config in worktree v1. In worktree v0, --repo is an alias\nof --local.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/git-config.txt           | 14 +++++++++++++-\n Documentation/git-worktree.txt         |  4 ++++\n Documentation/gitrepository-layout.txt | 10 +++++-----\n builtin/config.c                       | 19 ++++++++++++++-----\n t/t2028-worktree-config.sh             | 23 ++++++++++++++++++++++-\n 5 files changed, 58 insertions(+), 12 deletions(-)\n\ndiff --git a/Documentation/git-config.txt b/Documentation/git-config.txt\nindex 2608ca7..79fd453 100644\n--- a/Documentation/git-config.txt\n+++ b/Documentation/git-config.txt\n@@ -47,7 +47,7 @@ checks or transformations are performed on the value.\n \n When reading, the values are read from the system, global and\n repository local configuration files by default, and options\n-'--system', '--global', '--local' and '--file <filename>' can be\n+'--system', '--global', '--repo', '--local' and '--file <filename>' can be\n used to tell the command to read from only that location (see <<FILES>>).\n \n When writing, the new value is written to the repository local\n@@ -125,6 +125,18 @@ rather than from all available files.\n +\n See also <<FILES>>.\n \n+--repo::\n+\n+\tFor writing options: write to the repository file\n+\t`.git/config` if the configuration variable extensions.worktree\n+\tis not specified or has the value zero, `.git/worktrees/config`\n+\totherwise.\n++\n+For reading options: read only from the same file rather than from all\n+available files.\n++\n+See also <<FILES>>.\n+\n --local::\n \tFor writing options: write to the repository `.git/config` file.\n \tThis is\tthe default behavior.\ndiff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt\nindex 0846f2a..6082d4d 100644\n--- a/Documentation/git-worktree.txt\n+++ b/Documentation/git-worktree.txt\n@@ -119,6 +119,10 @@ In this version, the repository config file `.git/config` is not\n shared anymore. A new file, `.git/common/config`, read for all\n worktrees. Shared configuration should be stored here.\n \n+Use \"git config --repo\" to store shared configuration variables. Use\n+\"git config --local\" to store per-worktree ones. This works even in\n+single-worktree mode.\n+\n Version 0\n ~~~~~~~~~\n This is the first release. Version 0 is implied if extensions.worktree\ndiff --git a/Documentation/gitrepository-layout.txt b/Documentation/gitrepository-layout.txt\nindex d65345d..56175f0 100644\n--- a/Documentation/gitrepository-layout.txt\n+++ b/Documentation/gitrepository-layout.txt\n@@ -254,6 +254,11 @@ common::\n \tThis directory is seen from all working directories. It is\n \tmeant to share files that all working directories can see.\n \n+common/config::\n+\tRepository specific configuration file. Note that if this file\n+\tis present, it must contain the variable extensions.worktree\n+\twhose value must be one or above.\n+\n worktrees::\n \tContains administrative data for linked\n \tworking trees. Each subdirectory contains the working tree-related\n@@ -261,11 +266,6 @@ worktrees::\n \t$GIT_COMMON_DIR is set, in which case\n \t\"$GIT_COMMON_DIR/worktrees\" will be used instead.\n \n-common/config::\n-\tRepository specific configuration file. Note that if this file\n-\tis present, it must contain the variable extensions.worktree\n-\twhose value must be one or above.\n-\n worktrees/<id>/gitdir::\n \tA text file containing the absolute path back to the .git file\n \tthat points to here. This is used to check if the linked\ndiff --git a/builtin/config.c b/builtin/config.c\nindex adc7727..6aecd13 100644\n--- a/builtin/config.c\n+++ b/builtin/config.c\n@@ -21,7 +21,7 @@ static char delim = '=';\n static char key_delim = ' ';\n static char term = '\\n';\n \n-static int use_global_config, use_system_config, use_local_config;\n+static int use_global_config, use_system_config, use_local_config, use_repo_config;\n static struct git_config_source given_config_source;\n static int actions, types;\n static const char *get_color_slot, *get_colorbool_slot;\n@@ -54,7 +54,8 @@ static struct option builtin_config_options[] = {\n \tOPT_GROUP(N_(\"Config file location\")),\n \tOPT_BOOL(0, \"global\", &use_global_config, N_(\"use global config file\")),\n \tOPT_BOOL(0, \"system\", &use_system_config, N_(\"use system config file\")),\n-\tOPT_BOOL(0, \"local\", &use_local_config, N_(\"use repository config file\")),\n+\tOPT_BOOL(0, \"repo\", &use_repo_config, N_(\"use per-repository config file\")),\n+\tOPT_BOOL(0, \"local\", &use_local_config, N_(\"use per-worktree config file\")),\n \tOPT_STRING('f', \"file\", &given_config_source.file, N_(\"file\"), N_(\"use given config file\")),\n \tOPT_STRING(0, \"blob\", &given_config_source.blob, N_(\"blob-id\"), N_(\"read config from given blob object\")),\n \tOPT_GROUP(N_(\"Action\")),\n@@ -460,7 +461,8 @@ int cmd_config(int argc, const char **argv, const char *prefix)\n \t\t\t     PARSE_OPT_STOP_AT_NON_OPTION);\n \n \tif (use_global_config + use_system_config + use_local_config +\n-\t    !!given_config_source.file + !!given_config_source.blob > 1) {\n+\t    !!given_config_source.file + !!given_config_source.blob > 1 +\n+\t    use_repo_config) {\n \t\terror(\"only one config file at a time.\");\n \t\tusage_with_options(builtin_config_usage, builtin_config_options);\n \t}\n@@ -492,9 +494,16 @@ int cmd_config(int argc, const char **argv, const char *prefix)\n \t}\n \telse if (use_system_config)\n \t\tgiven_config_source.file = git_etc_gitconfig();\n-\telse if (use_local_config)\n+\telse if (use_local_config ||\n+\t\t (use_repo_config &&\n+\t\t  repository_format_worktree_version == 0))\n \t\tgiven_config_source.file = git_pathdup(\"config\");\n-\telse if (given_config_source.file) {\n+\telse if (use_repo_config) {\n+\t\tstruct strbuf sb = STRBUF_INIT;\n+\n+\t\tstrbuf_addf(&sb, \"%s/common/config\", get_git_common_dir());\n+\t\tgiven_config_source.file = strbuf_detach(&sb, NULL);\n+\t} else if (given_config_source.file) {\n \t\tif (!is_absolute_path(given_config_source.file) && prefix)\n \t\t\tgiven_config_source.file =\n \t\t\t\txstrdup(prefix_filename(prefix,\ndiff --git a/t/t2028-worktree-config.sh b/t/t2028-worktree-config.sh\nindex 5561788..d11b2ce 100755\n--- a/t/t2028-worktree-config.sh\n+++ b/t/t2028-worktree-config.sh\n@@ -19,6 +19,15 @@ test_expect_success 'main config is shared in version 0' '\n \ttest_cmp expected actual\n '\n \n+test_expect_success 'config --repo on v0' '\n+\tgit config --global new.var old-value &&\n+\tgit config --repo new.var new-value &&\n+\ttest_path_is_missing .git/common/config &&\n+\tgit config --repo new.var >actual &&\n+\techo new-value >expected &&\n+\ttest_cmp expected actual\n+'\n+\n test_expect_success 'main config is for main worktree only (v1)' '\n \tmkdir .git/common &&\n \tgit config -f .git/common/config extensions.worktree 1 &&\n@@ -28,7 +37,7 @@ test_expect_success 'main config is for main worktree only (v1)' '\n \ttest_must_fail git -C wt1 config wt.name\n '\n \n-test_expect_success 'worktrees/config is shared (v1)' '\n+test_expect_success 'common/config is shared (v1)' '\n \tgit config -f .git/common/config some.thing is-shared &&\n \techo is-shared >expected &&\n \tgit config some.thing >actual &&\n@@ -37,4 +46,16 @@ test_expect_success 'worktrees/config is shared (v1)' '\n \ttest_cmp expected actual\n '\n \n+test_expect_success 'config --repo on v1' '\n+\tgit config --global new.var1 old-value &&\n+\tgit config --repo new.var1 new-value &&\n+\tgrep var1 .git/common/config >/dev/null &&\n+\tgit config --repo new.var1 >actual &&\n+\techo new-value >expected &&\n+\ttest_cmp expected actual &&\n+\tgit -C wt2 config --repo new.var1 >actual &&\n+\techo new-value >expected &&\n+\ttest_cmp expected actual\n+'\n+\n test_done\n-- \n2.7.0.288.g1d8ad15\n"},{"id":"276787","messageId":"1453808685-21235-7-git-send-email-pclouds@gmail.com","threadId":"40920","inReplyTo":"1453808685-21235-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v3 6/6] worktree add: switch to worktree version 1","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-01-26T11:44:45Z","receivedAt":"2016-01-26T11:44:45Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"The most obvious use case is, \"git worktree add\" creates the first\nlinked worktree. In this case, we should be able to move to latest\nworktree version. The following happens:\n\n - common/config is created with extensions.worktree 1 and\n   core.repositoryformatversion 1\n\n - all config keys except a few per-worktree are moved to\n   common/config\n\n - per-worktree keys stay with the main worktree's config file\n\n - the main worktree config file also has worktree version explicitly\n   set to 1. This is to prevent older Git binaries from reading it.\n\nWhat if the repo already has another linked worktree and the user\nwants to stay at version 0, maybe because multiple git binaries can\naccess this repo? \"worktree add --version=0\" can be used, but it's\nreally not recommended to stay at lower (and buggy) version.\n\nA note about core.bare staying per-worktree. On the surface it does\nnot make sense for core.bare to be worktree specific. It's made so in\norder to \"grow\" new worktrees from a bare repo. In these new linked\nworktrees, core.bare will be hidden away and worktree-related commands\nwon't complain about bare repository.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/git-worktree.txt |  9 +++-\n builtin/worktree.c             | 95 ++++++++++++++++++++++++++++++++++++++++++\n t/t2028-worktree-config.sh     | 47 ++++++++++++++++++++-\n 3 files changed, 148 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt\nindex 6082d4d..0d7d523 100644\n--- a/Documentation/git-worktree.txt\n+++ b/Documentation/git-worktree.txt\n@@ -9,7 +9,7 @@ git-worktree - Manage multiple working trees\n SYNOPSIS\n --------\n [verse]\n-'git worktree add' [-f] [--detach] [-b <new-branch>] <path> [<branch>]\n+'git worktree add' [-f] [--detach] [-b <new-branch>] [--version=<N>] <path> [<branch>]\n 'git worktree prune' [-n] [-v] [--expire <expire>]\n 'git worktree list' [--porcelain]\n \n@@ -89,6 +89,13 @@ OPTIONS\n \tWith `add`, detach HEAD in the new working tree. See \"DETACHED HEAD\"\n \tin linkgit:git-checkout[1].\n \n+--version=<N>::\n+\tBy default when a new working directory is added, worktree\n+\tlayout is automatically migrated to latest version. This\n+\toption can be used to specify only migrate to the specified\n+\tversion, or no migrate at all if it's already current worktree\n+\tversion.\n+\n -n::\n --dry-run::\n \tWith `prune`, do not remove anything; just report what it would\ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex 475b958..551fe37 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -140,6 +140,7 @@ static char *junk_work_tree;\n static char *junk_git_dir;\n static int is_junk;\n static pid_t junk_pid;\n+static int target_version = 1;\n \n static void remove_junk(void)\n {\n@@ -184,6 +185,93 @@ static const char *worktree_basename(const char *path, int *olen)\n \treturn name;\n }\n \n+struct key_data {\n+\tconst char *key;\n+\tchar *value;\n+};\n+\n+static int get_one_key(const char *key, const char *value, void *cb)\n+{\n+\tstruct key_data *kd = cb;\n+\n+\tif (!strcmp(key, kd->key))\n+\t\tkd->value = xstrdup(value);\n+\n+\treturn 0;\n+}\n+\n+static char *get_key(const char *file, const char *key)\n+{\n+\tstruct key_data kd;\n+\n+\tkd.key = key;\n+\tkd.value = NULL;\n+\tif (git_config_from_file(get_one_key, file, &kd))\n+\t\treturn NULL;\n+\treturn kd.value;\n+}\n+\n+static void migrate_worktree_layout(void)\n+{\n+\tconst char *per_wortree_keys[] = {\n+\t\t\"core.bare\",\n+\t\t\"core.ignorestat\",\n+\t\t\"core.sparsecheckout\",\n+\t\t\"core.worktree\",\n+\t\tNULL\n+\t};\n+\tstruct strbuf sb = STRBUF_INIT;\n+\tconst char **key_p;\n+\n+\tswitch (repository_format_worktree_version) {\n+\tcase 0:\n+\t\tstrbuf_addf(&sb, \"%s/common\", get_git_common_dir());\n+\t\tif (mkdir_in_gitdir(sb.buf))\n+\t\t\tdie_errno(_(\"failed to create directory %s\"), sb.buf);\n+\t\tif (repository_format_version < 1 &&\n+\t\t    git_config_set(\"core.repositoryformatversion\", \"1\"))\n+\t\t\tdie(_(\"failed to set core.repositoryformatversion to one\"));\n+\t\tif (git_config_set(\"extensions.worktree\", \"1\"))\n+\t\t\tdie(_(\"failed to set extensions.worktree to one\"));\n+\t\tstrbuf_addstr(&sb, \"/config\");\n+\t\tif (rename(git_path(\"config\"), sb.buf))\n+\t\t\tdie_errno(_(\"failed to set move config file to %s\"),\n+\t\t\t\t  sb.buf);\n+\t\tfor (key_p = per_wortree_keys; *key_p; key_p++) {\n+\t\t\tconst char *key = *key_p;\n+\t\t\tchar *value = get_key(sb.buf, key);\n+\n+\t\t\tif (value) {\n+\t\t\t\tif (git_config_set(key, value))\n+\t\t\t\t\tdie(_(\"failed to keep %s in main worktree's config file\"), key);\n+\t\t\t\tif (git_config_set_in_file(sb.buf, key, NULL))\n+\t\t\t\t\tdie(_(\"failed to delete %s in shared config file\"), key);\n+\t\t\t\tfree(value);\n+\t\t\t}\n+\t\t}\n+\n+\t\t/*\n+\t\t * we're still in version 0 in this process, this will\n+\t\t * create a new file $GIT_COMMON_DIR/config with only\n+\t\t * one key, extensions.worktree. This will force old\n+\t\t * git binaries that do not understand v1 to bail out.\n+\t\t */\n+\t\tif (repository_format_version < 1 &&\n+\t\t    git_config_set(\"core.repositoryformatversion\", \"1\"))\n+\t\t\tdie(_(\"failed to set core.repositoryformatversion to one\"));\n+\t\tif (git_config_set(\"extensions.worktree\", \"1\"))\n+\t\t\tdie(_(\"failed to set extensions.worktree to one\"));\n+\n+\t\trepository_format_worktree_version = 1;\n+\t\tbreak;\n+\tcase 1:\n+\t\tbreak;\n+\tdefault:\n+\t\tdie(_(\"unsupported worktree format version %d\"),\n+\t\t    repository_format_worktree_version);\n+\t}\n+}\n+\n static int add_worktree(const char *path, const char *refname,\n \t\t\tconst struct add_opts *opts)\n {\n@@ -297,6 +385,9 @@ static int add_worktree(const char *path, const char *refname,\n \t\tfree(junk_git_dir);\n \t\tjunk_work_tree = NULL;\n \t\tjunk_git_dir = NULL;\n+\n+\t\twhile (repository_format_worktree_version < target_version)\n+\t\t\tmigrate_worktree_layout();\n \t}\n done:\n \tstrbuf_reset(&sb);\n@@ -322,6 +413,8 @@ static int add(int ac, const char **av, const char *prefix)\n \t\tOPT_STRING('B', NULL, &new_branch_force, N_(\"branch\"),\n \t\t\t   N_(\"create or reset a branch\")),\n \t\tOPT_BOOL(0, \"detach\", &opts.detach, N_(\"detach HEAD at named commit\")),\n+\t\tOPT_INTEGER(0, \"version\", &target_version,\n+\t\t\t   N_(\"stay at this worktree version\")),\n \t\tOPT_END()\n \t};\n \n@@ -331,6 +424,8 @@ static int add(int ac, const char **av, const char *prefix)\n \t\tdie(_(\"-b, -B, and --detach are mutually exclusive\"));\n \tif (ac < 1 || ac > 2)\n \t\tusage_with_options(worktree_usage, options);\n+\tif (target_version < 0 || target_version > 1)\n+\t\tdie(_(\"invalid worktree version %d\"), target_version);\n \n \tpath = prefix ? prefix_filename(prefix, strlen(prefix), av[0]) : av[0];\n \tbranch = ac < 2 ? \"HEAD\" : av[1];\ndiff --git a/t/t2028-worktree-config.sh b/t/t2028-worktree-config.sh\nindex d11b2ce..0d4cb8e 100755\n--- a/t/t2028-worktree-config.sh\n+++ b/t/t2028-worktree-config.sh\n@@ -6,8 +6,8 @@ test_description=\"config file in multi worktree\"\n \n test_expect_success 'setup' '\n \ttest_commit start &&\n-\tgit worktree add wt1 &&\n-\tgit worktree add wt2\n+\tgit worktree add --version=0 wt1 &&\n+\tgit worktree add --version=0 wt2\n '\n \n test_expect_success 'main config is shared in version 0' '\n@@ -58,4 +58,47 @@ test_expect_success 'config --repo on v1' '\n \ttest_cmp expected actual\n '\n \n+test_expect_success 'prepare worktree v0' '\n+\ttest_create_repo repo-v0 &&\n+\t(\n+\t\tcd repo-v0 &&\n+\t\ttest_commit v0 &&\n+\t\tgit config core.sparsecheckout true &&\n+\t\tgit config core.ignorestat true &&\n+\t\tgit config core.worktree \"$TEST_DIRECTORY\" &&\n+\t\tgit config share.key value\n+\t)\n+'\n+\n+test_expect_success 'migrate v0 to v1' '\n+\tgit -C repo-v0 worktree add --version=1 wt\n+'\n+\n+test_expect_success 'after migration: main wortree has extensions.worktree' '\n+\ttest \"`git -C repo-v0 config core.repositoryformatversion`\" = 1 &&\n+\ttest \"`git -C repo-v0 config extensions.worktree`\" = 1\n+'\n+\n+test_expect_success 'after migration: linked wortree has extensions.worktree' '\n+\ttest \"`git -C repo-v0/wt config core.repositoryformatversion`\" = 1 &&\n+\ttest \"`git -C repo-v0/wt config extensions.worktree`\" = 1\n+'\n+\n+test_expect_success 'after migration: main wortree keeps per-worktree vars' '\n+\ttest \"`git -C repo-v0 config core.sparsecheckout`\" = true &&\n+\ttest \"`git -C repo-v0 config core.ignorestat`\" = true &&\n+\ttest \"`git -C repo-v0 config core.worktree`\" = \"$TEST_DIRECTORY\"\n+'\n+\n+test_expect_success 'after migration: linked wortree has no per-worktree vars' '\n+\ttest_must_fail git -C repo-v0/wt config core.sparsecheckout &&\n+\ttest_must_fail git -C repo-v0/wt config core.ignorestat &&\n+\ttest_must_fail git -C repo-v0/wt config core.worktree\n+'\n+\n+test_expect_success 'after migration: shared vars are shared' '\n+\ttest \"`git -C repo-v0 config share.key`\" = value &&\n+\ttest \"`git -C repo-v0/wt config share.key`\" = value\n+'\n+\n test_done\n-- \n2.7.0.288.g1d8ad15\n"},{"id":"276937","messageId":"xmqqfuxi7jtn.fsf@gitster.mtv.corp.google.com","threadId":"40920","inReplyTo":"1453808685-21235-2-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH v3 1/6] worktree: new repo extension to manage worktree behaviors","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-27T22:12:52Z","receivedAt":"2016-01-27T22:12:52Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n\n> Multiple worktree setup is still evolving and its behavior may be\n> changed in future. But we do not want to break existing worktree\n\ns/be changed/change/\n\n> setups. A new set of extensions, worktree=X, is recognized to tell Git\n> what multiple worktree \"version\" is being used so that Git can\n> behavior accordingly.\n\ns/behavior/behave/\n\n> +WORKTREE VERSIONS AND MIGRATION\n> +-------------------------------\n> +Multiple worktree is still an experimental feature and evolving. Every\n> +time the behavior is changed, the \"worktree version\" is stepped\n> +up. Worktree version is stored as a configuration variable\n> +extensions.worktree.\n\ns/stepped up/incremented/\n\nMore seriously, are we confident that the overall worktree support\nis mature enough by now that once we add an experimental feature X\nat version 1, we can promise to keep maintaining it forever at\nversion N for any positive integer N?  I hate to sound overly\nnegative, but I am getting an impression that we are not quite\nthere, and it is still not ready for production use.\n\nIt would be beneficial both for us and our users if we can keep our\nhand untied for at least several more releases to allow us try\nvarious random experimental features, fully intending to drop any of\nthem if the ideas do not pan out.\n"},{"id":"276938","messageId":"xmqqbn867jl3.fsf@gitster.mtv.corp.google.com","threadId":"40920","inReplyTo":"1453808685-21235-3-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH v3 2/6] path.c: new (identical) list for worktree v1","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-27T22:18:00Z","receivedAt":"2016-01-27T22:18:00Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n\n> +static struct common_dir common_list_v1[] = {\n> +\t...\n> +};\n> +\n> +static struct common_dir *get_common_list(void)\n> +{\n> +\tswitch (repository_format_worktree_version) {\n> +\tcase 0: return common_list_v0;\n> +\tcase 1: return common_list_v1;\n\nWhy not an array whose elements are these common_list_v$N[]\ninstead of \"switch\"?  I.e.\n\nstatic struct common_dir **common_list_version[] = {\n\tcommon_list_v0,\n        common_list_v1,\n};\n\nstatic struct common_dir *get_common_list(void)\n{\n\tint i = repository_format_worktree_version;\n\tif (i < ARRAY_SIZE(common_list_version))\n\t\treturn common_list_version[i];\n\tdie(\"I dunno about version %d\", i);\n}\n"},{"id":"276939","messageId":"xmqq7fiu7je7.fsf@gitster.mtv.corp.google.com","threadId":"40920","inReplyTo":"1453808685-21235-5-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH v3 4/6] worktree: new config file hierarchy","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-27T22:22:08Z","receivedAt":"2016-01-27T22:22:08Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n\n> ($C stands for $GIT_COMMON_DIR for the rest of the message)\n>\n> In main worktree, we read these config files in this order:\n>\n> 1) system config\n> 2) XDG config\n> 3) user config\n> 4) $GIT_DIR/config\n>\n> Currently linked worktrees share the same config file at step 4 with\n> main worktree. The problem is, not all config variables can be\n> shared. We need per-repo vars and per-worktree ones.\n>\n> With this patch, since worktree v1, the repo config file (or worktree\n> config file in multi worktree context) is no longer shared. Main\n> worktree reads $C/config.  Linked worktrees read $C/worktrees/xxx/config\n> and a new file, $C/worktrees/config. Sharing is done via this new\n> file. The read hierarchy for a worktree becomes\n>\n> 1) system config\n> 2) XDG config\n> 3) user config\n> 4) $C/common/config\n> 5) $C/worktrees/xxx/config (or $C/config for main worktree)\n>\n> Compare to an alternative scheme where $C/config contains both shared\n> variables and main-worktree-only ones, this is a cleaner design.\n>\n> * We do not have to check every single variable name to see if it's\n>   shared or per-worktree when reading config files.\n>\n> * We do not enforce any particular variable split. If a variable\n>   is in $C/worktrees/config, it is shared. Putting core.worktree in\n>   $C/worktrees/config is punished the same way the variable is put in\n>   $HOME/.gitconfig, for example.\n>\n> * We will provide a new \"git config --repo\" to access this new config\n>   file. In single-worktree context, or worktree v0, --repo is an alias\n>   of --local.\n>\n> There is one problem though. We store worktree version in config file\n> and expect that all worktrees must share the same version (i.e. read\n> the same config file). But the share-ness of per-repo config files is\n> changed based on worktree version. Where do we put extensions.worktree\n> then?\n\nI cannot see why it cannot live in $C/common/config, which would be\nread as the fourth alternative in your earlier enumeration.  What I\nam missing?\n"},{"id":"276940","messageId":"xmqq37ti7jbt.fsf@gitster.mtv.corp.google.com","threadId":"40920","inReplyTo":"1453808685-21235-1-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH v3 0/6] Split .git/config in multiple worktree setup","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-27T22:23:34Z","receivedAt":"2016-01-27T22:23:34Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n\n> For any worktree, the new file .git/common/config is read first, then\n> either .git/config or .git/worktrees/xxx/config is read after. There's\n> no special per-worktree var list any more. Which is great. You want to\n> add per-worktree config vars, use \"git config --local\". You want to\n> add per-repo config vars, use (new) \"git config --repo\". You put a\n> variable in a wrong file, you're punished for it (and it's the same\n> today, say if you put core.worktree to /etc/gitconfig).\n\nI think this is saner than the one before.\n"},{"id":"276994","messageId":"CACsJy8C3wXL-nE1TfS7V8BFNwaQTjMtkQibCswycpX_teaATpQ@mail.gmail.com","threadId":"40920","inReplyTo":"xmqq7fiu7je7.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v3 4/6] worktree: new config file hierarchy","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2016-01-28T12:03:38Z","receivedAt":"2016-01-28T12:03:38Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Thu, Jan 28, 2016 at 5:22 AM, Junio C Hamano <gitster@pobox.com> wrote:\n>> With this patch, since worktree v1, the repo config file (or worktree\n>> config file in multi worktree context) is no longer shared. Main\n>> worktree reads $C/config.  Linked worktrees read $C/worktrees/xxx/config\n>> and a new file, $C/worktrees/config. Sharing is done via this new\n>> file. The read hierarchy for a worktree becomes\n>>\n>> 1) system config\n>> 2) XDG config\n>> 3) user config\n>> 4) $C/common/config\n>> 5) $C/worktrees/xxx/config (or $C/config for main worktree)\n>>\n>> Compare to an alternative scheme where $C/config contains both shared\n>> variables and main-worktree-only ones, this is a cleaner design.\n>>\n>> * We do not have to check every single variable name to see if it's\n>>   shared or per-worktree when reading config files.\n>>\n>> * We do not enforce any particular variable split. If a variable\n>>   is in $C/worktrees/config, it is shared. Putting core.worktree in\n>>   $C/worktrees/config is punished the same way the variable is put in\n>>   $HOME/.gitconfig, for example.\n>>\n>> * We will provide a new \"git config --repo\" to access this new config\n>>   file. In single-worktree context, or worktree v0, --repo is an alias\n>>   of --local.\n>>\n>> There is one problem though. We store worktree version in config file\n>> and expect that all worktrees must share the same version (i.e. read\n>> the same config file). But the share-ness of per-repo config files is\n>> changed based on worktree version. Where do we put extensions.worktree\n>> then?\n>\n> I cannot see why it cannot live in $C/common/config, which would be\n> read as the fourth alternative in your earlier enumeration.  What I\n> am missing?\n\nI wasn't clear. The last paragraph is about already released git\nbinaries, which does not care about $C/common/config. Suppose you add\na new worktree with new git binary, which will move common stuff out\nof .git/config to common/config, on a shared repo. If the old binary\nreads that repo, it does not see common config, but it does not know\nwhere common config is either.\n-- \nDuy\n"},{"id":"276995","messageId":"CACsJy8ABj+_iohtobRJxeVd3WfRcufFVPC4ZCzGqJDz=wJkjyg@mail.gmail.com","threadId":"40920","inReplyTo":"xmqqfuxi7jtn.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v3 1/6] worktree: new repo extension to manage worktree behaviors","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2016-01-28T12:11:00Z","receivedAt":"2016-01-28T12:11:00Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Thu, Jan 28, 2016 at 5:12 AM, Junio C Hamano <gitster@pobox.com> wrote:\n>> +WORKTREE VERSIONS AND MIGRATION\n>> +-------------------------------\n>> +Multiple worktree is still an experimental feature and evolving. Every\n>> +time the behavior is changed, the \"worktree version\" is stepped\n>> +up. Worktree version is stored as a configuration variable\n>> +extensions.worktree.\n>\n> s/stepped up/incremented/\n>\n> More seriously, are we confident that the overall worktree support\n> is mature enough by now that once we add an experimental feature X\n> at version 1, we can promise to keep maintaining it forever at\n> version N for any positive integer N?  I hate to sound overly\n> negative, but I am getting an impression that we are not quite\n> there, and it is still not ready for production use.\n\nI completely overlooked this config file issue in the first round, so\nthere's a good chance I will fail to realize it's still incomplete\nagain.\n\n> It would be beneficial both for us and our users if we can keep our\n> hand untied for at least several more releases to allow us try\n> various random experimental features, fully intending to drop any of\n> them if the ideas do not pan out.\n\nYes it's best if we can somehow communicate with the users about that.\nIf a line or two in release announcement is good enough, great.\nOtherwise maybe print a line every time the user executes \"git\nworktree\"?\n-- \nDuy\n"},{"id":"276997","messageId":"xmqqsi1hilug.fsf@junio.mtv.corp.google.com","threadId":"40920","inReplyTo":"CACsJy8C3wXL-nE1TfS7V8BFNwaQTjMtkQibCswycpX_teaATpQ@mail.gmail.com","subject":"Re: [PATCH v3 4/6] worktree: new config file hierarchy","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-28T18:45:59Z","receivedAt":"2016-01-28T18:45:59Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Duy Nguyen <pclouds@gmail.com> writes:\n\n>> I cannot see why it cannot live in $C/common/config, which would be\n>> read as the fourth alternative in your earlier enumeration.  What I\n>> am missing?\n>\n> I wasn't clear. The last paragraph is about already released git\n> binaries, which does not care about $C/common/config. Suppose you add\n> a new worktree with new git binary, which will move common stuff out\n> of .git/config to common/config, on a shared repo. If the old binary\n> reads that repo, it does not see common config, but it does not know\n> where common config is either.\n\nAh, OK.\n\nWould it make it simpler to invent a specific value for 'xxx' that\ndenotes the main worktree (hence $C/worktrees/xxx/config will always\nbe read by worktrees including the primary one), not to add\n$C/common/ anything, and use $C/config as the common one instead?\n\nThen the repository format version can live in $C/config that would\nbe noticed by existing versions of Git.\n"},{"id":"277084","messageId":"20160130135944.GA4978@wheezy.local","threadId":"40920","inReplyTo":"1453808685-21235-2-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH v3 1/6] worktree: new repo extension to manage worktree behaviors","fromName":"Max Kirillov","fromEmail":"max@max630.net","sentAt":"2016-01-30T13:59:44Z","receivedAt":"2016-01-30T13:59:44Z","isPatch":true,"sender":{"key":"max@max630.net","avatar":"https://avatars.githubusercontent.com/u/381560?v=4"},"body":"On Tue, Jan 26, 2016 at 06:44:40PM +0700, Nguyễn Thái Ngọc Duy wrote:\n> +WORKTREE VERSIONS AND MIGRATION\n> +-------------------------------\n> +Multiple worktree is still an experimental feature and evolving. Every\n> +time the behavior is changed, the \"worktree version\" is stepped\n> +up. Worktree version is stored as a configuration variable\n> +extensions.worktree.\n> +\n> +Version 0\n> +~~~~~~~~~\n> +This is the first release. Version 0 is implied if extensions.worktree\n> +does not exist.\n> +\n\n...\n\n> +`worktree`\n> +~~~~~~~~~~\n> +\n> +Define behavior in multiple worktree setup. The value specifies the\n> +version. Default version is zero.\n\nThis sounds too pessimistic. There is now a need to\nintroduce incompatible change, because there is no way to\nmake config separation. There would be a need to increase\nthe version regularly in case of previous option which\nsuggested to hardcode per-worktree versions, so that each\nchange of their list would need a version increase. Now\nthere is no need to increase the version beyond 1, so it can\nbe \"version 0 is like in older gits, version 1 is separated\nconfig file, and version 2 will never happen\" :) The\nextension parameter coould even be called like\n\"worktreeConfig\" and be boolean.\n"},{"id":"277085","messageId":"20160130142039.GB4978@wheezy.local","threadId":"40920","inReplyTo":"xmqqfuxi7jtn.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v3 1/6] worktree: new repo extension to manage worktree behaviors","fromName":"Max Kirillov","fromEmail":"max@max630.net","sentAt":"2016-01-30T14:20:39Z","receivedAt":"2016-01-30T14:20:39Z","isPatch":true,"sender":{"key":"max@max630.net","avatar":"https://avatars.githubusercontent.com/u/381560?v=4"},"body":"On Wed, Jan 27, 2016 at 02:12:52PM -0800, Junio C Hamano wrote:\n> More seriously, are we confident that the overall worktree support\n> is mature enough by now that once we add an experimental feature X\n> at version 1, we can promise to keep maintaining it forever at\n> version N for any positive integer N?  I hate to sound overly\n> negative, but I am getting an impression that we are not quite\n> there, and it is still not ready for production use.\n\nThe worktree feature has been used by several people\nalready (me included), and do far the only issue which\nrequires change in repository layout is the config\nseparation. Isn't it enough to be confident?\n\nAs I noted in another email, I would not expect to be N>2\nsoon. At least not more likely than incompatible change\nbecause of some other reason. And the support for an older\nversion can be as little as one-time upgrade to the current\nN (preferably with confirmation from user).\n\n> It would be beneficial both for us and our users if we can keep our\n> hand untied for at least several more releases to allow us try\n> various random experimental features, fully intending to drop any of\n> them if the ideas do not pan out.\n\nUsers definitely would not benefit if there is release\nfeature with note \"anything you do can be lost after you\ninstall next version of git\"\n"},{"id":"277087","messageId":"20160130144517.GC4978@wheezy.local","threadId":"40920","inReplyTo":"1453808685-21235-3-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH v3 2/6] path.c: new (identical) list for worktree v1","fromName":"Max Kirillov","fromEmail":"max@max630.net","sentAt":"2016-01-30T14:45:17Z","receivedAt":"2016-01-30T14:45:17Z","isPatch":true,"sender":{"key":"max@max630.net","avatar":"https://avatars.githubusercontent.com/u/381560?v=4"},"body":"On Tue, Jan 26, 2016 at 06:44:41PM +0700, Nguyễn Thái Ngọc Duy wrote:\n> Worktree v1 may have different .git file split than v0. Add support\n> code to change common file list based on extensions.worktree. The list\n> for now is identical to v0.\n\nIn the end this turned out to be needed only for \"common\"\nwhich is not strictly necessary, as Junio pointed out, and\nanyway could be done for v0 as well because \"common\" is not\nused to be used before. So probably it is not needed at all.\n"},{"id":"277099","messageId":"20160130221010.GD4978@wheezy.local","threadId":"40920","inReplyTo":"1453808685-21235-6-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH v3 5/6] config: select .git/common/config with --repo","fromName":"Max Kirillov","fromEmail":"max@max630.net","sentAt":"2016-01-30T22:10:10Z","receivedAt":"2016-01-30T22:10:10Z","isPatch":true,"sender":{"key":"max@max630.net","avatar":"https://avatars.githubusercontent.com/u/381560?v=4"},"body":"On Tue, Jan 26, 2016 at 06:44:44PM +0700, Nguyễn Thái Ngọc Duy wrote:\n> This new option allows the user to write to or read from\n> .git/common/config in worktree v1. In worktree v0, --repo is an alias\n> of --local.\n\nLooks like by default a value is always set in a local\nconfig, which might be dangerous for remote.* or gc.*\nparameters, for example. I think that even if reading is\ndone uniformly setting could depend on the actual variable\nbeing set if no location specified.\n\n>  \tif (use_global_config + use_system_config + use_local_config +\n> -\t    !!given_config_source.file + !!given_config_source.blob > 1) {\n> +\t    !!given_config_source.file + !!given_config_source.blob > 1 +\n> +\t    use_repo_config) {\n>  \t\terror(\"only one config file at a time.\");\n\nShouldn't \"+ use_repo_config\" do here to the left part of\ncomparison?\n\n-- \nMax\n"},{"id":"277126","messageId":"xmqqh9htya2e.fsf@gitster.mtv.corp.google.com","threadId":"40920","inReplyTo":"20160130142039.GB4978@wheezy.local","subject":"Re: [PATCH v3 1/6] worktree: new repo extension to manage worktree behaviors","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-31T16:42:49Z","receivedAt":"2016-01-31T16:42:49Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Max Kirillov <max@max630.net> writes:\n\n> The worktree feature has been used by several people\n> already (me included), and do far the only issue which\n> requires change in repository layout is the config\n> separation. Isn't it enough to be confident?\n\nOne lessor key phrase above is \"so far\", I think, and another one\nyou forgot to use is s/which requires/that we know &/, which to me\nis a more serious one.  IOW, I do think it is premature for us to\nsay that that config split issue is the only thing, or to say that\nthe issue is best solved by changing the layout in the way being\ndiscussed; the multiple-worktree feature needs more lab experience\nfor us to gain confidence.\n"},{"id":"277150","messageId":"jwvfuxd17bz.fsf-monnier+gmane.comp.version-control.git@gnu.org","threadId":"40920","inReplyTo":"xmqqh9htya2e.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v3 1/6] worktree: new repo extension to manage worktree behaviors","fromName":"Stefan Monnier","fromEmail":"monnier@iro.umontreal.ca","sentAt":"2016-02-01T02:41:31Z","receivedAt":"2016-02-01T02:41:31Z","isPatch":true,"sender":{"key":"monnier@iro.umontreal.ca","avatar":null},"body":"> One lessor key phrase above is \"so far\", I think, and another one\n> you forgot to use is s/which requires/that we know &/, which to me\n> is a more serious one.  IOW, I do think it is premature for us to\n> say that that config split issue is the only thing, or to say that\n> the issue is best solved by changing the layout in the way being\n> discussed; the multiple-worktree feature needs more lab experience\n> for us to gain confidence.\n\nAs a heavy user of the git-new-worktree \"hack / script\", is there\nsomething I can do to help \"get more experience\"?\n\n\n        Stefan\n"},{"id":"277151","messageId":"jwva8nl171f.fsf-monnier+gmane.comp.version-control.git@gnu.org","threadId":"40920","inReplyTo":"jwvfuxd17bz.fsf-monnier+gmane.comp.version-control.git@gnu.org","subject":"Re: [PATCH v3 1/6] worktree: new repo extension to manage worktree behaviors","fromName":"Stefan Monnier","fromEmail":"monnier@iro.umontreal.ca","sentAt":"2016-02-01T02:47:12Z","receivedAt":"2016-02-01T02:47:12Z","isPatch":true,"sender":{"key":"monnier@iro.umontreal.ca","avatar":null},"body":"> As a heavy user of the git-new-worktree \"hack / script\", is there\n                         ^^^^^^^^^^^^^^^^\n                         git-new-workdir\nSorry,\n\n\n        Stefan\n"},{"id":"277154","messageId":"CACsJy8AZYjQJ0rP0nF3xkOuvRzP_sX9Dp6bxS4abUEYQJ8kmnQ@mail.gmail.com","threadId":"40920","inReplyTo":"xmqqsi1hilug.fsf@junio.mtv.corp.google.com","subject":"Re: [PATCH v3 4/6] worktree: new config file hierarchy","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2016-02-01T05:09:54Z","receivedAt":"2016-02-01T05:09:54Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Fri, Jan 29, 2016 at 1:45 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Would it make it simpler to invent a specific value for 'xxx' that\n> denotes the main worktree (hence $C/worktrees/xxx/config will always\n> be read by worktrees including the primary one), not to add\n> $C/common/ anything, and use $C/config as the common one instead?\n>\n> Then the repository format version can live in $C/config that would\n> be noticed by existing versions of Git.\n\nI can read this in two ways. In the first way, we still have $C as a\n.git _directory_ that contains no worktree stuff because those files\nare in $C/worktrees/main. When we detect .git directory we need to\ndecide if it this is worktree v1 and redirect $GIT_DIR to\n$C/worktrees/main, otherwise keep $GIT_DIR as $C. This messes up setup\ncode a lot (I tried).\n\nThe other way, probably a bit deviated from your intention, is, we\nonly support two modes: either all worktrees are in $C/worktrees\n(multiple worktree mode), or there's only one worktree at .git (single\nworktree mode). In other words, there's no mixing main and linked\nworktrees. The user will be forced to convert the main worktree to\nlinked worktree when they want to add a another tree. The backward\ncompatibility issue with worktree v0 is gone.\n\nThe transition between two modes can be done via \"git worktree move\".\nThis command can move any worktree, including the main one. Main\nworktree is converted when it's moved (.git directory remains where it\nis). \"worktree move\" can also move repository directory, which also\nautomatically convert main worktree to $C/worktrees/something. If the\nuser deletes all worktrees except one, they can move the repo back to\nworktree's root, which converts it back to the single worktree mode.\n\nHmm?\n-- \nDuy\n"},{"id":"277155","messageId":"CACsJy8Av6W3S2S+eEi=X_V1TSBYp_t4wdRn_dvrtKiS3aS_=7g@mail.gmail.com","threadId":"40920","inReplyTo":"20160130221010.GD4978@wheezy.local","subject":"Re: [PATCH v3 5/6] config: select .git/common/config with --repo","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2016-02-01T05:15:08Z","receivedAt":"2016-02-01T05:15:08Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Sun, Jan 31, 2016 at 5:10 AM, Max Kirillov <max@max630.net> wrote:\n> On Tue, Jan 26, 2016 at 06:44:44PM +0700, Nguyễn Thái Ngọc Duy wrote:\n>> This new option allows the user to write to or read from\n>> .git/common/config in worktree v1. In worktree v0, --repo is an alias\n>> of --local.\n>\n> Looks like by default a value is always set in a local\n> config, which might be dangerous for remote.* or gc.*\n> parameters, for example. I think that even if reading is\n> done uniformly setting could depend on the actual variable\n> being set if no location specified.\n\nI grepped \"git config\" in scripts to see if we need to change any to\nuse --repo, but I forgot about builtin commands. git-remote needs to\nstore remote.* in the shared config file instead.\n\ngc.* and others are set manually by the user, so they decide. We can\nhave a user-controlled filter that catches certain variables and\nsuggests they are stored in shared config instead, but this is\noptional.\n-- \nDuy\n"},{"id":"277156","messageId":"CACsJy8DGsDFnX57eQ7rN2hkOR3Wuw_eQ9ED4e-9FhAm30sBFEQ@mail.gmail.com","threadId":"40920","inReplyTo":"jwvfuxd17bz.fsf-monnier+gmane.comp.version-control.git@gnu.org","subject":"Re: [PATCH v3 1/6] worktree: new repo extension to manage worktree behaviors","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2016-02-01T05:23:46Z","receivedAt":"2016-02-01T05:23:46Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Mon, Feb 1, 2016 at 9:41 AM, Stefan Monnier <monnier@iro.umontreal.ca> wrote:\n>> One lessor key phrase above is \"so far\", I think, and another one\n>> you forgot to use is s/which requires/that we know &/, which to me\n>> is a more serious one.  IOW, I do think it is premature for us to\n>> say that that config split issue is the only thing, or to say that\n>> the issue is best solved by changing the layout in the way being\n>> discussed; the multiple-worktree feature needs more lab experience\n>> for us to gain confidence.\n>\n> As a heavy user of the git-new-worktree \"hack / script\", is there\n> something I can do to help \"get more experience\"?\n\nYou can try out \"git worktree\" command (in \"lab\" environment) and see\nwhat's missing, what use cases of yours it does not support.\n-- \nDuy\n"},{"id":"277157","messageId":"20160201053333.GE4978@wheezy.local","threadId":"40920","inReplyTo":"1453808685-21235-7-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH v3 6/6] worktree add: switch to worktree version 1","fromName":"Max Kirillov","fromEmail":"max@max630.net","sentAt":"2016-02-01T05:33:33Z","receivedAt":"2016-02-01T05:33:33Z","isPatch":true,"sender":{"key":"max@max630.net","avatar":"https://avatars.githubusercontent.com/u/381560?v=4"},"body":"On Tue, Jan 26, 2016 at 06:44:45PM +0700, Nguyễn Thái Ngọc Duy wrote:\n> +\t\tfor (key_p = per_wortree_keys; *key_p; key_p++) {\n> +\t\t\tconst char *key = *key_p;\n> +\t\t\tchar *value = get_key(sb.buf, key);\n> +\n> +\t\t\tif (value) {\n> +\t\t\t\tif (git_config_set(key, value))\n> +\t\t\t\t\tdie(_(\"failed to keep %s in main worktree's config file\"), key);\n> +\t\t\t\tif (git_config_set_in_file(sb.buf, key, NULL))\n> +\t\t\t\t\tdie(_(\"failed to delete %s in shared config file\"), key);\n> +\t\t\t\tfree(value);\n> +\t\t\t}\n> +\t\t}\n\n1. For submodules (which must be left per-worktree) this\napproach is not going to work, because you don't know all\nvariables in advance. You could scan the config file and\nmatch those actual keys which are there with patterns.\n\n2. This migrates variables to the default (or current?)\nworktree, what about others existing?\n\n-- \nMax\n"},{"id":"277158","messageId":"CACsJy8Am7rQ=pm0C7bw0gQ=aic3opmBos+3+1Awrko8TT2uHrg@mail.gmail.com","threadId":"40920","inReplyTo":"20160201053333.GE4978@wheezy.local","subject":"Re: [PATCH v3 6/6] worktree add: switch to worktree version 1","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2016-02-01T06:05:05Z","receivedAt":"2016-02-01T06:05:05Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Mon, Feb 1, 2016 at 12:33 PM, Max Kirillov <max@max630.net> wrote:\n> On Tue, Jan 26, 2016 at 06:44:45PM +0700, Nguyễn Thái Ngọc Duy wrote:\n>> +             for (key_p = per_wortree_keys; *key_p; key_p++) {\n>> +                     const char *key = *key_p;\n>> +                     char *value = get_key(sb.buf, key);\n>> +\n>> +                     if (value) {\n>> +                             if (git_config_set(key, value))\n>> +                                     die(_(\"failed to keep %s in main worktree's config file\"), key);\n>> +                             if (git_config_set_in_file(sb.buf, key, NULL))\n>> +                                     die(_(\"failed to delete %s in shared config file\"), key);\n>> +                             free(value);\n>> +                     }\n>> +             }\n>\n> 1. For submodules (which must be left per-worktree) this\n> approach is not going to work, because you don't know all\n> variables in advance. You could scan the config file and\n> match those actual keys which are there with patterns.\n\nHmm.. we could keep existing submodule.* per-worktree. New variables\nare per-worktree by default, unless you do \"git config --repo\" in\ngit-submodule.sh. Am I missing something?\n\n> 2. This migrates variables to the default (or current?)\n> worktree, what about others existing?\n\nIn v0, $C/config contains all shared variables, once we move these\nshared vars to $C/common/config, they will be visible to all other\nworktrees. Or do you replicate per-worktree vars in $C/config to all\nworktrees ?\n-- \nDuy\n"},{"id":"277175","messageId":"xmqqh9hswawj.fsf@gitster.mtv.corp.google.com","threadId":"40920","inReplyTo":"CACsJy8DGsDFnX57eQ7rN2hkOR3Wuw_eQ9ED4e-9FhAm30sBFEQ@mail.gmail.com","subject":"Re: [PATCH v3 1/6] worktree: new repo extension to manage worktree behaviors","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-02-01T18:19:56Z","receivedAt":"2016-02-01T18:19:56Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Duy Nguyen <pclouds@gmail.com> writes:\n\n> On Mon, Feb 1, 2016 at 9:41 AM, Stefan Monnier <monnier@iro.umontreal.ca> wrote:\n>>> One lessor key phrase above is \"so far\", I think, and another one\n>>> you forgot to use is s/which requires/that we know &/, which to me\n>>> is a more serious one.  IOW, I do think it is premature for us to\n>>> say that that config split issue is the only thing, or to say that\n>>> the issue is best solved by changing the layout in the way being\n>>> discussed; the multiple-worktree feature needs more lab experience\n>>> for us to gain confidence.\n>>\n>> As a heavy user of the git-new-worktree \"hack / script\", is there\n>> something I can do to help \"get more experience\"?\n>\n> You can try out \"git worktree\" command (in \"lab\" environment) and see\n> what's missing, what use cases of yours it does not support.\n\nYup, that would be very helpful.\n"},{"id":"277176","messageId":"1454351978.13104.6.camel@kaarsemaker.net","threadId":"40920","inReplyTo":"xmqqfuxi7jtn.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v3 1/6] worktree: new repo extension to manage worktree behaviors","fromName":"Dennis Kaarsemaker","fromEmail":"dennis@kaarsemaker.net","sentAt":"2016-02-01T18:39:38Z","receivedAt":"2016-02-01T18:39:38Z","isPatch":true,"sender":{"key":"dennis@kaarsemaker.net","avatar":"https://avatars.githubusercontent.com/u/200649?v=4"},"body":"On wo, 2016-01-27 at 14:12 -0800, Junio C Hamano wrote:\n\n> More seriously, are we confident that the overall worktree support\n> is mature enough by now that once we add an experimental feature X\n> at version 1, we can promise to keep maintaining it forever at\n> version N for any positive integer N?  I hate to sound overly\n> negative, but I am getting an impression that we are not quite\n> there, and it is still not ready for production use.\n> \n> It would be beneficial both for us and our users if we can keep our\n> hand untied for at least several more releases to allow us try\n> various random experimental features, fully intending to drop any of\n> them if the ideas do not pan out.\n\nSo far I have two use cases for separate worktrees and am a happy user:\n\n- A CI setup that tries to avoid cloning a repository too often. It\n  does N independent tasks in parallel in separate worktrees. This\n  checks out the same commit multiple times in multiple worktrees.\n\n- Quickly checking out another branch/commit without first having to\n  stash all uncommitted work.\n\nNeither of those require much specialness, so I'm more than happy to\nsee things change for the better as we find out more of the edge cases.\nOne thing that may benefit especially the former is a 'git worktree rm'\nwhich removes the worktree (iff there are no local changes) and prunes\nit, but nothing in the current implementation or proposed changes will\nstop the addition of that.\n\n-- \nDennis Kaarsemaker\nwww.kaarsemaker.net\n"},{"id":"277209","messageId":"20160202053547.GF4978@wheezy.local","threadId":"40920","inReplyTo":"CACsJy8Am7rQ=pm0C7bw0gQ=aic3opmBos+3+1Awrko8TT2uHrg@mail.gmail.com","subject":"Re: [PATCH v3 6/6] worktree add: switch to worktree version 1","fromName":"Max Kirillov","fromEmail":"max@max630.net","sentAt":"2016-02-02T05:35:47Z","receivedAt":"2016-02-02T05:35:47Z","isPatch":true,"sender":{"key":"max@max630.net","avatar":"https://avatars.githubusercontent.com/u/381560?v=4"},"body":"On Mon, Feb 01, 2016 at 01:05:05PM +0700, Duy Nguyen wrote:\n> On Mon, Feb 1, 2016 at 12:33 PM, Max Kirillov <max@max630.net> wrote:\n>> 1. For submodules (which must be left per-worktree) this\n>> approach is not going to work, because you don't know all\n>> variables in advance. You could scan the config file and\n>> match those actual keys which are there with patterns.\n\n> Hmm.. we could keep existing submodule.* per-worktree. New variables\n> are per-worktree by default, unless you do \"git config --repo\" in\n> git-submodule.sh. Am I missing something?\n\nSubmodules in new worktree should be not initialized, and as\nfar as I understand this means that submodule variables\nshould be removed from common config.\n\nI used test from\nhttp://article.gmane.org/gmane.comp.version-control.git/266621\nto verify expectations for submodules.\n\n>> 2. This migrates variables to the default (or current?)\n>> worktree, what about others existing?\n> \n> In v0, $C/config contains all shared variables, once we move these\n> shared vars to $C/common/config, they will be visible to all other\n> worktrees. Or do you replicate per-worktree vars in $C/config to all\n> worktrees ?\n\nIf would make sense for some variables definitely. For\nexample, the submodule related variables.\n\n-- \nMax\n"},{"id":"277444","messageId":"jwvfux8uzki.fsf-monnier+gmane.comp.version-control.git@gnu.org","threadId":"40920","inReplyTo":"CACsJy8DGsDFnX57eQ7rN2hkOR3Wuw_eQ9ED4e-9FhAm30sBFEQ@mail.gmail.com","subject":"git worktree (was: [PATCH v3 1/6] worktree: new repo extension to manage worktree behaviors)","fromName":"Stefan Monnier","fromEmail":"monnier@iro.umontreal.ca","sentAt":"2016-02-04T18:12:11Z","receivedAt":"2016-02-04T18:12:11Z","isPatch":true,"sender":{"key":"monnier@iro.umontreal.ca","avatar":null},"body":">> As a heavy user of the git-new-worktree \"hack / script\", is there\n>> something I can do to help \"get more experience\"?\n> You can try out \"git worktree\" command (in \"lab\" environment) and see\n> what's missing, what use cases of yours it does not support.\n\nCool, didn't know about it, and it's even already in Debian testing!\nUsing it right now.  So far so good,\n\n\n        Stefan\n"}]}