{"thread":{"id":"38527","subject":"[PATCH/RFD 0/3] worktree.* config keys and submodule and multiple worktrees","startedAt":"2015-02-08T13:16:31Z","lastAt":"2015-04-20T03:22:39Z","messageCount":22,"participants":["Nguyễn Thái Ngọc Duy","Jens Lehmann","Duy Nguyen","Max Kirillov"],"isPatch":true,"patchVersion":1,"patchTotal":3},"messages":[{"id":"255763","messageId":"1423401394-13675-1-git-send-email-pclouds@gmail.com","threadId":"38527","inReplyTo":null,"subject":"[PATCH/RFD 0/3] worktree.* config keys and submodule and multiple worktrees","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2015-02-08T13:16:31Z","receivedAt":"2015-02-08T13:16:31Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"1/3 is a more complete version of a patch I posted earlier [1]. It\nmakes sure that worktree.* config keys are stored in a different place\nthan $GIT_DIR/config. This allows us to work around the core.worktree\nissue in multiple worktree setting.\n\nI think 1/3 and 2/3 are fine. 3/3 is probably not. It's more of a\nproof of concept. The tests pass, but there's no migration path for\nexisting submodules. Submodules modified by new Git will confuse old\nGit because the old ones do not understand worktree.path (the\nreplacement for core.worktree)\n\nBut I think it's a start..\n\n[1] http://article.gmane.org/gmane.comp.version-control.git/263134\n\nNguyễn Thái Ngọc Duy (3):\n  config.c: new config namespace worktree.* stored in $GIT_DIR/config.worktree\n  setup: add worktree.path to shadow core.worktree\n  submodule: use worktree.path instead of core.worktree\n\n Documentation/config.txt               |  7 ++++++-\n builtin/config.c                       |  8 +++++++\n config.c                               | 38 ++++++++++++++++++++++++++++++++++\n git-submodule.sh                       |  2 +-\n setup.c                                |  7 ++++++-\n submodule.c                            |  6 +++---\n t/lib-submodule-update.sh              |  8 +++----\n t/t1300-repo-config.sh                 | 31 +++++++++++++++++++++++++++\n t/t7400-submodule-basic.sh             |  4 ++--\n t/t7409-submodule-detached-worktree.sh |  6 +++---\n 10 files changed, 102 insertions(+), 15 deletions(-)\n\n-- \n2.3.0.rc1.137.g477eb31\n"},{"id":"255765","messageId":"1423401394-13675-2-git-send-email-pclouds@gmail.com","threadId":"38527","inReplyTo":"1423401394-13675-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 1/3] config.c: new config namespace worktree.* stored in $GIT_DIR/config.worktree","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2015-02-08T13:16:32Z","receivedAt":"2015-02-08T13:16:32Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On the surface, worktree.* variables are just like any other\nvariables. You can read or modify them with `git config` command, or\nconfig_* API. Underneath, worktree.* are always stored in\n$GIT_DIR/config.worktree instead of $GIT_DIR/config (and never in\n$HOME/.gitconfig or /etc/gitconfig)\n\nThe reason for this split is, as the name implies, for\nworktree-specific configuration. When the same repo is attached to\nmore than one worktree, we can't use $GIT_DIR/config to store worktree\nspecific stuff because it's shared across worktrees.\n\nWith this, both git-new-workdir and nd/multiple-work-trees will work.\ngit-new-workdir creates a symlink to $GIT_DIR/config in the new\nworktree, but not $GIT_DIR/config.worktree. That file will be created\nnew when worktree.* are written in the new worktree.\n`git checkout --to` can remap the path $GIT_DIR/config.worktree to make\nit worktree-specific.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/config.txt |  4 +++-\n builtin/config.c         |  8 ++++++++\n config.c                 | 38 ++++++++++++++++++++++++++++++++++++++\n t/t1300-repo-config.sh   | 31 +++++++++++++++++++++++++++++++\n 4 files changed, 80 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 04e2a71..26e4e07 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -2,11 +2,13 @@ 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+the Git commands' behavior. The `.git/config` and `.git/config.worktree`\n+files in each repository\n 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.\n+worktree.* variables can only be contained in `.git/config.worktree`\n \n The configuration variables are used by both the Git plumbing\n and the porcelains. The variables are divided into sections, wherein\ndiff --git a/builtin/config.c b/builtin/config.c\nindex 15a7bea..d9333cd 100644\n--- a/builtin/config.c\n+++ b/builtin/config.c\n@@ -552,6 +552,14 @@ int cmd_config(int argc, const char **argv, const char *prefix)\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 (actions == ACTION_LIST) {\n \t\tcheck_argc(argc, 0, 0);\n \t\tif (git_config_with_options(show_all_config, NULL,\ndiff --git a/config.c b/config.c\nindex 752e2e2..3d46192 100644\n--- a/config.c\n+++ b/config.c\n@@ -12,6 +12,7 @@\n #include \"quote.h\"\n #include \"hashmap.h\"\n #include \"string-list.h\"\n+#include \"dir.h\"\n \n struct config_source {\n \tstruct config_source *prev;\n@@ -1177,6 +1178,15 @@ int git_config_system(void)\n \treturn !git_env_bool(\"GIT_CONFIG_NOSYSTEM\", 0);\n }\n \n+static int config_worktree_filter(const char *var, const char *value, void *data)\n+{\n+\tstruct config_include_data *inc = data;\n+\n+\tif (!starts_with(var, \"worktree.\"))\n+\t\treturn error(\"$GIT_DIR/config.worktree can only contain worktree.*\");\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 {\n \tint ret = 0, found = 0;\n@@ -1202,8 +1212,19 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)\n \t}\n \n \tif (repo_config && !access_or_die(repo_config, R_OK, 0)) {\n+\t\tchar *wt_config;\n \t\tret += git_config_from_file(fn, repo_config, data);\n \t\tfound += 1;\n+\t\twt_config = git_pathdup(\"config.worktree\");\n+\t\tif (!access_or_die(wt_config, R_OK, 0)) {\n+\t\t\tstruct config_include_data inc = CONFIG_INCLUDE_INIT;\n+\t\t\tinc.fn = fn;\n+\t\t\tinc.data = data;\n+\t\t\tret += git_config_from_file(config_worktree_filter,\n+\t\t\t\t\t\t    wt_config, &inc);\n+\t\t\tfound += 1;\n+\t\t}\n+\t\tfree(wt_config);\n \t}\n \n \tswitch (git_config_from_parameters(fn, data)) {\n@@ -1942,6 +1963,23 @@ int git_config_set_multivar_in_file(const char *config_filename,\n \n \tstore.multi_replace = multi_replace;\n \n+\tif (starts_with(key, \"worktree.\")) {\n+\t\tif (!config_filename)\n+\t\t\tconfig_filename = filename_buf = git_pathdup(\"config.worktree\");\n+\t\t/* cheap trick, but should work 90% of time */\n+\t\telse if (!ends_with(config_filename, \".worktree\"))\n+\t\t\tdie(\"worktree.* can only be stored in %s\",\n+\t\t\t    git_path(\"config.worktree\"));\n+\t\telse {\n+\t\t\tstruct strbuf sb = STRBUF_INIT;\n+\t\t\tstrbuf_addstr(&sb, real_path(config_filename));\n+\t\t\tif (strcmp_icase(sb.buf,\n+\t\t\t\t\t real_path(git_path(\"config.worktree\"))))\n+\t\t\t\tdie(\"worktree.* can only be stored in %s\",\n+\t\t\t\t    git_path(\"config.worktree\"));\n+\t\t\tstrbuf_release(&sb);\n+\t\t}\n+\t}\n \tif (!config_filename)\n \t\tconfig_filename = filename_buf = git_pathdup(\"config\");\n \ndiff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh\nindex 938fc8b..58a5009 100755\n--- a/t/t1300-repo-config.sh\n+++ b/t/t1300-repo-config.sh\n@@ -1179,4 +1179,35 @@ test_expect_success POSIXPERM,PERL 'preserves existing permissions' '\n \t  \"die q(badrename) if ((stat(q(.git/config)))[2] & 07777) != 0600\"\n '\n \n+test_expect_success 'setting worktree.foo goes to config.worktree' '\n+\ttest_when_finished \"rm .git/config.worktree\" &&\n+\tgit config worktree.foo bar &&\n+\tcat >expect <<\\EOF &&\n+[worktree]\n+\tfoo = bar\n+EOF\n+\ttest_cmp expect .git/config.worktree &&\n+\ttest \"`git config worktree.foo`\" = bar\n+'\n+\n+test_expect_success 'setting --local worktree.foo goes to config.worktree' '\n+\ttest_when_finished \"rm .git/config.worktree\" &&\n+\tgit config --local worktree.fooo barr &&\n+\tcat >expect <<\\EOF &&\n+[worktree]\n+\tfooo = barr\n+EOF\n+\ttest_cmp expect .git/config.worktree &&\n+\ttest \"`git config worktree.fooo`\" = barr\n+'\n+\n+test_expect_success 'setting worktree.foo outside config.worktree' '\n+\ttest_must_fail git config --global worktree.foo bar 2>err &&\n+\tgrep config.worktree err &&\n+\ttest_must_fail git config --system worktree.foo bar 2>err &&\n+\tgrep config.worktree err &&\n+\ttest_must_fail git config --file foo.worktree worktree.foo bar 2>err &&\n+\tgrep config.worktree err\n+'\n+\n test_done\n-- \n2.3.0.rc1.137.g477eb31\n"},{"id":"255764","messageId":"1423401394-13675-3-git-send-email-pclouds@gmail.com","threadId":"38527","inReplyTo":"1423401394-13675-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 2/3] setup: add worktree.path to shadow core.worktree","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2015-02-08T13:16:33Z","receivedAt":"2015-02-08T13:16:33Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"They have the same purpose. But they are located in different places:\ncore.worktree in $GIT_DIR/config while worktree.path in\n$GIT_DIR/config.worktree\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/config.txt | 3 +++\n setup.c                  | 7 ++++++-\n 2 files changed, 9 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 26e4e07..b717881 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -410,6 +410,7 @@ false), while all other repositories are assumed to be bare (bare\n = true).\n \n core.worktree::\n+worktree.path::\n \tSet the path to the root of the working tree.\n \tThis can be overridden by the GIT_WORK_TREE environment\n \tvariable and the '--work-tree' command-line option.\n@@ -430,6 +431,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+worktree.path takes precedence over core.worktree.\n \n core.logAllRefUpdates::\n \tEnable the reflog. Updates to a ref <ref> is logged to the file\ndiff --git a/setup.c b/setup.c\nindex 979b13f..bc27f8b 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -4,6 +4,7 @@\n \n static int inside_git_dir = -1;\n static int inside_work_tree = -1;\n+static int worktree_path_set;\n \n /*\n  * The input parameter must contain an absolute path, and it must already be\n@@ -807,12 +808,16 @@ int check_repository_format_version(const char *var, const char *value, void *cb\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-\t} else if (strcmp(var, \"core.worktree\") == 0) {\n+\t} else if (strcmp(var, \"worktree.path\") == 0 ||\n+\t\t   (strcmp(var, \"core.worktree\") == 0 &&\n+\t\t    !worktree_path_set)) {\n \t\tif (!value)\n \t\t\treturn config_error_nonbool(var);\n \t\tfree(git_work_tree_cfg);\n \t\tgit_work_tree_cfg = xstrdup(value);\n \t\tinside_work_tree = -1;\n+\t\tif (!strcmp(var, \"worktree.path\"))\n+\t\t\tworktree_path_set = 1;\n \t}\n \treturn 0;\n }\n-- \n2.3.0.rc1.137.g477eb31\n"},{"id":"255766","messageId":"1423401394-13675-4-git-send-email-pclouds@gmail.com","threadId":"38527","inReplyTo":"1423401394-13675-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 3/3] submodule: use worktree.path instead of core.worktree","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2015-02-08T13:16:34Z","receivedAt":"2015-02-08T13:16:34Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This opens a door of using submodule with multiple worktrees\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n git-submodule.sh                       | 2 +-\n submodule.c                            | 6 +++---\n t/lib-submodule-update.sh              | 8 ++++----\n t/t7400-submodule-basic.sh             | 4 ++--\n t/t7409-submodule-detached-worktree.sh | 6 +++---\n 5 files changed, 13 insertions(+), 13 deletions(-)\n\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex 9245abf..6e9e1d1 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -309,7 +309,7 @@ module_clone()\n \tprintf '%s\\n' \"gitdir: $rel/$a\" >\"$sm_path/.git\"\n \n \trel=$(printf '%s\\n' \"$a\" | sed -e 's|[^/][^/]*|..|g')\n-\t(clear_local_git_env; cd \"$sm_path\" && GIT_WORK_TREE=. git config core.worktree \"$rel/$b\")\n+\t(clear_local_git_env; cd \"$sm_path\" && GIT_WORK_TREE=. git config worktree.path \"$rel/$b\")\n }\n \n isnumber()\ndiff --git a/submodule.c b/submodule.c\nindex d37d400..f886fa6 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -1115,11 +1115,11 @@ void connect_work_tree_and_git_dir(const char *work_tree, const char *git_dir)\n \n \t/* Update core.worktree setting */\n \tstrbuf_reset(&file_name);\n-\tstrbuf_addf(&file_name, \"%s/config\", git_dir);\n-\tif (git_config_set_in_file(file_name.buf, \"core.worktree\",\n+\tstrbuf_addf(&file_name, \"%s/config.worktree\", git_dir);\n+\tif (git_config_set_in_file(file_name.buf, \"worktree.path\",\n \t\t\t\t   relative_path(real_work_tree, git_dir,\n \t\t\t\t\t\t &rel_path)))\n-\t\tdie(_(\"Could not set core.worktree in %s\"),\n+\t\tdie(_(\"Could not set worktree.path in %s\"),\n \t\t    file_name.buf);\n \n \tstrbuf_release(&file_name);\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex 79cdd34..ce140cf 100755\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -105,7 +105,7 @@ replace_gitfile_with_git_dir () {\n \t\tgit_dir=\"$(git rev-parse --git-dir)\" &&\n \t\trm -f .git &&\n \t\tcp -R \"$git_dir\" .git &&\n-\t\tGIT_WORK_TREE=. git config --unset core.worktree\n+\t\tGIT_WORK_TREE=. git config --unset worktree.path\n \t)\n }\n \n@@ -120,16 +120,16 @@ test_git_directory_is_unchanged () {\n \t(\n \t\tcd \".git/modules/$1\" &&\n \t\t# does core.worktree point at the right place?\n-\t\ttest \"$(git config core.worktree)\" = \"../../../$1\" &&\n+\t\ttest \"$(git config worktree.path)\" = \"../../../$1\" &&\n \t\t# remove it temporarily before comparing, as\n \t\t# \"$1/.git/config\" lacks it...\n-\t\tgit config --unset core.worktree\n+\t\tgit config --unset worktree.path\n \t) &&\n \tdiff -r \".git/modules/$1\" \"$1/.git\" &&\n \t(\n \t\t# ... and then restore.\n \t\tcd \".git/modules/$1\" &&\n-\t\tgit config core.worktree \"../../../$1\"\n+\t\tgit config worktree.path \"../../../$1\"\n \t)\n }\n \ndiff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh\nindex 7c88245..def28e6 100755\n--- a/t/t7400-submodule-basic.sh\n+++ b/t/t7400-submodule-basic.sh\n@@ -93,7 +93,7 @@ test_expect_success 'submodule add' '\n \t\ttest_cmp expect submod/.git &&\n \t\t(\n \t\t\tcd submod &&\n-\t\t\tgit config core.worktree >actual &&\n+\t\t\tgit config worktree.path >actual &&\n \t\t\techo \"../../../submod\" >expect &&\n \t\t\ttest_cmp expect actual &&\n \t\t\trm -f actual expect\n@@ -945,7 +945,7 @@ test_expect_success 'submodule deinit fails when submodule has a .git directory\n \t\tcd init &&\n \t\trm .git &&\n \t\tcp -R ../.git/modules/example .git &&\n-\t\tGIT_WORK_TREE=. git config --unset core.worktree\n+\t\tGIT_WORK_TREE=. git config --unset worktree.path\n \t) &&\n \ttest_must_fail git submodule deinit init &&\n \ttest_must_fail git submodule deinit -f init &&\ndiff --git a/t/t7409-submodule-detached-worktree.sh b/t/t7409-submodule-detached-worktree.sh\nindex c207171..ba50d77 100755\n--- a/t/t7409-submodule-detached-worktree.sh\n+++ b/t/t7409-submodule-detached-worktree.sh\n@@ -55,7 +55,7 @@ test_expect_success 'submodule on detached working tree' '\n \t)\n '\n \n-test_expect_success 'submodule on detached working pointed by core.worktree' '\n+test_expect_success 'submodule on detached working pointed by worktree.path' '\n \tmkdir home3 &&\n \t(\n \t\tcd home3 &&\n@@ -63,7 +63,7 @@ test_expect_success 'submodule on detached working pointed by core.worktree' '\n \t\texport GIT_DIR &&\n \t\tgit clone --bare ../remote \"$GIT_DIR\" &&\n \t\tgit config core.bare false &&\n-\t\tgit config core.worktree .. &&\n+\t\tgit config worktree.path .. &&\n \t\tgit checkout master &&\n \t\tgit submodule add ../bundle1 .vim/bundle/dupe &&\n \t\ttest_commit \"dupe\" &&\n@@ -74,7 +74,7 @@ test_expect_success 'submodule on detached working pointed by core.worktree' '\n \t\tGIT_DIR=\"$(pwd)/.dotfiles\" &&\n \t\texport GIT_DIR &&\n \t\tgit config core.bare false &&\n-\t\tgit config core.worktree .. &&\n+\t\tgit config worktree.path .. &&\n \t\tgit pull &&\n \t\tgit submodule update --init &&\n \t\ttest -f .vim/bundle/dupe/shoot.t\n-- \n2.3.0.rc1.137.g477eb31\n"},{"id":"255782","messageId":"54D79EAB.6060301@web.de","threadId":"38527","inReplyTo":"1423401394-13675-1-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH/RFD 0/3] worktree.* config keys and submodule and multiple worktrees","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2015-02-08T17:36:43Z","receivedAt":"2015-02-08T17:36:43Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Am 08.02.2015 um 05:16 schrieb Nguyễn Thái Ngọc Duy:\n> 1/3 is a more complete version of a patch I posted earlier [1]. It\n> makes sure that worktree.* config keys are stored in a different place\n> than $GIT_DIR/config. This allows us to work around the core.worktree\n> issue in multiple worktree setting.\n>\n> I think 1/3 and 2/3 are fine. 3/3 is probably not. It's more of a\n> proof of concept. The tests pass, but there's no migration path for\n> existing submodules. Submodules modified by new Git will confuse old\n> Git because the old ones do not understand worktree.path (the\n> replacement for core.worktree)\n\nYeah, breaking every submodule cloned with v1.7.9 or newer is not\nthe way to go. You'd still have to support the old configuration\nname for a very long time.\n\nI wonder if it's worth all the hassle to invent new names. Wouldn't\nit be much better to just keep a list of per-worktree configuration\nvalue names and use that inside the config code to decide where to\nfind them for multiple work trees. That would also work easily for\nstuff like EOL-config and would push the complexity in the config\nmachinery and not onto the user.\n"},{"id":"255783","messageId":"54D79FCD.6060602@web.de","threadId":"38527","inReplyTo":"54D79EAB.6060301@web.de","subject":"Re: [PATCH/RFD 0/3] worktree.* config keys and submodule and multiple worktrees","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2015-02-08T17:41:33Z","receivedAt":"2015-02-08T17:41:33Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Am 08.02.2015 um 09:36 schrieb Jens Lehmann:\n> Am 08.02.2015 um 05:16 schrieb Nguyễn Thái Ngọc Duy:\n>> 1/3 is a more complete version of a patch I posted earlier [1]. It\n>> makes sure that worktree.* config keys are stored in a different place\n>> than $GIT_DIR/config. This allows us to work around the core.worktree\n>> issue in multiple worktree setting.\n>>\n>> I think 1/3 and 2/3 are fine. 3/3 is probably not. It's more of a\n>> proof of concept. The tests pass, but there's no migration path for\n>> existing submodules. Submodules modified by new Git will confuse old\n>> Git because the old ones do not understand worktree.path (the\n>> replacement for core.worktree)\n>\n> Yeah, breaking every submodule cloned with v1.7.9 or newer is not\n\nThat's v1.7.8 of course ...\n\n> the way to go. You'd still have to support the old configuration\n> name for a very long time.\n>\n> I wonder if it's worth all the hassle to invent new names. Wouldn't\n> it be much better to just keep a list of per-worktree configuration\n> value names and use that inside the config code to decide where to\n> find them for multiple work trees. That would also work easily for\n> stuff like EOL-config and would push the complexity in the config\n> machinery and not onto the user.\n"},{"id":"255809","messageId":"CACsJy8D8Ur4W348t-WFUPrb7SQxmff5MJ4aRp+w+ZiQ7VVvipg@mail.gmail.com","threadId":"38527","inReplyTo":"54D79EAB.6060301@web.de","subject":"Re: [PATCH/RFD 0/3] worktree.* config keys and submodule and multiple worktrees","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2015-02-09T09:35:29Z","receivedAt":"2015-02-09T09:35:29Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Mon, Feb 9, 2015 at 12:36 AM, Jens Lehmann <Jens.Lehmann@web.de> wrote:\n> I wonder if it's worth all the hassle to invent new names. Wouldn't\n> it be much better to just keep a list of per-worktree configuration\n> value names and use that inside the config code to decide where to\n> find them for multiple work trees. That would also work easily for\n> stuff like EOL-config and would push the complexity in the config\n> machinery and not onto the user.\n\nIt's certainly possible to relocate core.worktree to outside\n$GIT_DIR/config. But I don't think it helps. If anything it'll make it\nharder to distinguish the old setup and the new one. I think we need a\nclear signal that will make old git barf on new setup, to be safe.\nMaybe stepping core.repositoryformatversion, or breaking .git file\nformat when we switch to the new setup (with $GIT_COMMON_DIR).\n\nOr.. perhaps we could use the old setup for \"primary\" worktree and the\nnew one for secondary worktrees of the same submodule. In these\nsecondary submodules, $GIT_COMMON_DIR is enough to make old git reject\nthem. And we could just reuse core.worktree, if we can make\ncore.worktree in $GIT_DIR/config.worktree shadow one in\n$GIT_DIR/config..\n\nNeed to study git-submodule.sh some more..\n-- \nDuy\n"},{"id":"257988","messageId":"20150318213342.GA25692@wheezy.local","threadId":"38527","inReplyTo":"54D79EAB.6060301@web.de","subject":"per-repository and per-worktree config variables","fromName":"Max Kirillov","fromEmail":"max@max630.net","sentAt":"2015-03-18T21:33:42Z","receivedAt":"2015-03-18T21:33:42Z","isPatch":false,"sender":{"key":"max@max630.net","avatar":"https://avatars.githubusercontent.com/u/381560?v=4"},"body":"On Sun, Feb 08, 2015 at 09:36:43AM -0800, Jens Lehmann wrote:\n> I wonder if it's worth all the hassle to invent new names. Wouldn't\n> it be much better to just keep a list of per-worktree configuration\n> value names and use that inside the config code to decide where to\n> find them for multiple work trees. That would also work easily for\n> stuff like EOL-config and would push the complexity in the config\n> machinery and not onto the user.\n\nI actually thought about the same, and now tend to think\nthat most of config variables make sense to be per-worktree\nin some cases. Only few variable must always be per\nrepository. I tried to summarize the variables which now\n(in current pu) should be common, also listed all the rest\nso somebody could scan through the list and spot anything I\ncould miss.\n\nPS: some variables are with older case, they were mostly\ncollected before I got aware of their rename.\n\n-- \nMax\n\nStrictly common only\n~~~~~~~~~~~~~~~~~~~~\n\nDistributiveness\n^^^^^^^^^^^^^^^^\n\nA repository should behave same way regartdless of\nwhich worktree is being accessed.\n\ncore.gitProxy::\ncore.askpass::\ncredential.helper::\ncredential.useHttpPath::\ncredential.username::\ncredential.<url>.*::\nfetch.fsckObjects::\nfetch.prune::\ngitcvs.*::\ngitweb.*::\ngui.pruneduringfetch::\nhttp.*::\npush.followTags::\nreceive.*::\nremote.<name>.*::\nremotes.<group>::\ntransfer.fsckObjects::\ntransfer.hiderefs::\nuploadarchive.allowUnreachable::\nuploadpack.*::\nurl.<base>.insteadOf::\nurl.<base>.pushInsteadOf::\nimap.*::\n\nRepository storage options\n^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nThere should be same options of purging, compression etc.\n\ncore.compression::\ncore.loosecompression::\ncore.packedGitWindowSize::\ncore.packedGitLimit::\ncore.deltaBaseCacheLimit::\ncore.bigFileThreshold::\ncore.fsyncobjectfiles::\ncore.createObject::\ncore.logAllRefUpdates::\ncore.protectHFS::\ncore.protectNTFS::\nfetch.unpackLimit::\nfsck.skipList::\nfsck.error::\nfsck.warn::\nfsck.ignore::\ngc.*\npack.*\nrepack.*\n\nBranch tracking settings\n^^^^^^^^^^^^^^^^^^^^^^^^\n\nSince branch are shared, they should be tracked same way\nregardless of where are they updated.\n\nbranch.<name>.remote::\nbranch.<name>.pushremote::\nbranch.<name>.merge::\nbranch.<name>.mergeoptions::\nbranch.<name>.rebase::\n\nNotes handling\n^^^^^^^^^^^^^^\n\nI don't know much about notes, and not sure about these ones, but notes looks\nlike a part of common history, and the options affect all of them.\n\nnotes.rewrite.<command>::\nnotes.rewriteMode::\nnotes.rewriteRef::\n\nMisc\n^^^^\n\ncore.preferSymlinkRefs::\n\tAs description says, useful mostly for older scripts, which definitely\n\tnot going to understand the new format. Probably incompatible with\n\tmultiple worktrees at all.\ncore.repositoryFormatVersion::\n\tLooks like this is not used.\ninit.templatedir::\n\tThis makes sense only as a global option.\n\nPrefer common\n~~~~~~~~~~~~~\n\nTechnically can be used per-worktree, but does not seem to have much sense.\n\nMany of them are are actualy expected to be global.\n\nadvice.*::\ncore.ignorecase::\ncore.precomposeunicode::\ncore.trustctime::\ncore.checkstat::\ncore.quotepath::\ncore.symlinks::\ncore.ignoreStat::\ncore.warnAmbiguousRefs::\ncore.attributesfile::\n\tThis should be common if it names tracked file.\ncore.editor::\ncore.commentchar::\nsequence.editor::\ncore.pager::\ncore.preloadindex::\nalias.*::\nbrowser.<tool>.path::\ncolor.branch::\ncolor.diff::\ncolor.diff.<slot>::\ncolor.decorate.<slot>::\ncolor.grep::\ncolor.grep.<slot>::\ncolor.interactive::\ncolor.interactive.<slot>::\ncolor.pager::\ncolor.showbranch::\ncolor.status::\ncolor.status.<slot>::\ncolor.ui::\ncolor.branch.<slot>::\ncolumn.*::\ncommit.cleanup::\ncommit.gpgsign::\ncommit.status::\ncommit.template::\ndifftool.*::\nfetch.recurseSubmodules::\n\tSince submodules can differ, this also can.\ngui.commitmsgwidth::\ngui.diffcontext::\ngui.encoding::\n\tWhile in theory possible to use per-workree value, probably this is intended\n\tto correspond to the actual data in repository. Not sure though.\ngui.trustmtime::\ngui.spellingdictionary::\nhelp.*\ni18n.commitEncoding::\ni18n.logOutputEncoding::\nindex.version::\ninstaweb.*::\nmailmap.*::\nman.*::\nmergetool.*::\npager.*::\nsendemail.*::\ntar.umask::\nuser.email::\nuser.name::\nuser.signingkey::\nweb.browser::\nmailinfo.scissors::\n\nOk to be per-worktree\n~~~~~~~~~~~~~~~~~~~~~\n\ncore.fileMode::\ncore.eol::\ncore.safecrlf::\ncore.autocrlf::\ncore.bare::\ncore.worktree::\ncore.excludesfile::\ncore.whitespace::\ncore.notesRef::\ncore.sparseCheckout::\ncore.abbrev::\nadd.ignore-errors::\nadd.ignoreErrors::\nam.keepcr::\napply.ignorewhitespace::\napply.whitespace::\nbranch.autosetupmerge::\nbranch.autosetuprebase::\nclean.requireForce::\nformat.*::\nfilter.*::\n\tFor some worktrees it may be desired to have them unsmudged.\ngrep.*::\ngpg.program::\ngui.displayuntracked::\ngui.matchtrackingbranch::\ngui.newbranchtemplate::\ngui.fastcopyblame::\ngui.copyblamethreshold::\ngui.blamehistoryctx::\nguitool.*\ninteractive.singlekey::\nlog.*::\nnotes.displayRef::\npretty.<name>::\npull.ff::\npull.rebase::\npull.octopus::\npull.twohead::\npush.default::\nrebase.stat::\nrebase.autosquash::\nrebase.autostash::\nremote.pushdefault::\nrerere.*::\nshowbranch.*::\nstatus.*::\nsubmodule.*::\ntag.sort::\ndiff.*::\n\tnot sure about  \"diff.<driver>\" commands, but I could imagine cases when it is desirable\nmerge.*::\n\tnot sure about  \"merge.<driver>\" commands, but I could imagine cases when it is desirable\nversionsort.prereleaseSuffix::\n"},{"id":"258410","messageId":"CACsJy8CYgMDY_zGi6o=UtD7QV+DQUcaDgwxo6tGrfktRXj+QSw@mail.gmail.com","threadId":"38527","inReplyTo":"20150318213342.GA25692@wheezy.local","subject":"Re: per-repository and per-worktree config variables","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2015-03-24T13:48:49Z","receivedAt":"2015-03-24T13:48:49Z","isPatch":false,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Thu, Mar 19, 2015 at 4:33 AM, Max Kirillov <max@max630.net> wrote:\n> On Sun, Feb 08, 2015 at 09:36:43AM -0800, Jens Lehmann wrote:\n>> I wonder if it's worth all the hassle to invent new names. Wouldn't\n>> it be much better to just keep a list of per-worktree configuration\n>> value names and use that inside the config code to decide where to\n>> find them for multiple work trees. That would also work easily for\n>> stuff like EOL-config and would push the complexity in the config\n>> machinery and not onto the user.\n>\n> I actually thought about the same, and now tend to think\n> that most of config variables make sense to be per-worktree\n> in some cases. Only few variable must always be per\n> repository. I tried to summarize the variables which now\n> (in current pu) should be common, also listed all the rest\n> so somebody could scan through the list and spot anything I\n> could miss.\n\nThanks for compiling the list. At this point I think it may not be\nsensible to hard code some config vars (e.g. core.worktree) to be\nlocal or shared. So I'm thinking (out loud) that we may have a file\n$GIT_DIR/worktrees/<id>/local-config-patterns (or some other name)\nthat would define what vars are local. gitignore syntax will be reused\nfor this. The file would provide more flexibility..\n-- \nDuy\n"},{"id":"258525","messageId":"551329BC.8050207@web.de","threadId":"38527","inReplyTo":"20150318213342.GA25692@wheezy.local","subject":"Re: per-repository and per-worktree config variables","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2015-03-25T21:33:48Z","receivedAt":"2015-03-25T21:33:48Z","isPatch":false,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Am 18.03.2015 um 22:33 schrieb Max Kirillov:\n> On Sun, Feb 08, 2015 at 09:36:43AM -0800, Jens Lehmann wrote:\n>> I wonder if it's worth all the hassle to invent new names. Wouldn't\n>> it be much better to just keep a list of per-worktree configuration\n>> value names and use that inside the config code to decide where to\n>> find them for multiple work trees. That would also work easily for\n>> stuff like EOL-config and would push the complexity in the config\n>> machinery and not onto the user.\n>\n> I actually thought about the same, and now tend to think\n> that most of config variables make sense to be per-worktree\n> in some cases. Only few variable must always be per\n> repository. I tried to summarize the variables which now\n> (in current pu) should be common, also listed all the rest\n> so somebody could scan through the list and spot anything I\n> could miss.\n\nThanks for your effort! Looks like my suspicion that not only\nsubmodule specific configuration should be kept per worktree\nwasn't completely wrong ;-)\n\nMe thinks Duy's proposal to configure the per worktree settings\nin a config file might make lots of sense. We could then provide\na default version of that file with settings that fit most use\ncases and the user could then adapt that to her special needs if\nneeded.\n"},{"id":"258544","messageId":"1427371464-22237-1-git-send-email-pclouds@gmail.com","threadId":"38527","inReplyTo":"CACsJy8CYgMDY_zGi6o=UtD7QV+DQUcaDgwxo6tGrfktRXj+QSw@mail.gmail.com","subject":"[PATCH v2] config.c: split some variables to $GIT_DIR/config.worktree","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2015-03-26T12:04:24Z","receivedAt":"2015-03-26T12:04:24Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"When you define $GIT_DIR/info/config.worktree, which contains of\ngitignore-style patterns (*), config variables that match these\npatterns will be saved in $GIT_DIR/config.worktree instead of\n$GIT_DIR/config.\n\nOn the surface, they are just like any other variables. You can read\nor modify them with `git config` command, or config_* API. Underneath,\nthey are always stored in $GIT_DIR/config.worktree instead of\n$GIT_DIR/config (and never in $HOME/.gitconfig or /etc/gitconfig)\n\nThe reason for this split is, as the name implies, for\nworktree-specific configuration. When the same repo is attached to\nmore than one worktree, we can't use $GIT_DIR/config to store worktree\nspecific stuff because it's shared across worktrees.\n\n(*) Config variable names are separated by dots. However as this is a\nquick and dirty patch to experiment with submodules and multiple\nworktrees, you must substitute dots with slashes when writing these\npatterns, for now. E.g. write \"remote/*/foo\" instead of \"remote.*.foo\"\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Something for Max to play with if he's still experimenting with\n multiple worktree support for submodules :-) It's far from perfect,\n but good enough for this purpose.\n\n Documentation/config.txt |  6 ++++-\n builtin/config.c         |  8 ++++++\n config.c                 | 67 ++++++++++++++++++++++++++++++++++++++++++++++++\n t/t1300-repo-config.sh   | 34 ++++++++++++++++++++++++\n 4 files changed, 114 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 2700a1b..6d00f49 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -2,11 +2,15 @@ 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+the Git commands' behavior. The `.git/config` and `.git/config.worktree`\n+files in each repository\n 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.\n+If `.git/info/core.worktree` exists, it contains gitignore-style\n+patterns. Variables that match these patterns can only be contained in\n+`.git/config.worktree`.\n \n The configuration variables are used by both the Git plumbing\n and the porcelains. The variables are divided into sections, wherein\ndiff --git a/builtin/config.c b/builtin/config.c\nindex 8cc2604..4ca8fc2 100644\n--- a/builtin/config.c\n+++ b/builtin/config.c\n@@ -555,6 +555,14 @@ int cmd_config(int argc, const char **argv, const char *prefix)\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 (actions == ACTION_LIST) {\n \t\tcheck_argc(argc, 0, 0);\n \t\tif (git_config_with_options(show_all_config, NULL,\ndiff --git a/config.c b/config.c\nindex 15a2983..f68eb6a 100644\n--- a/config.c\n+++ b/config.c\n@@ -12,6 +12,7 @@\n #include \"quote.h\"\n #include \"hashmap.h\"\n #include \"string-list.h\"\n+#include \"dir.h\"\n \n struct config_source {\n \tstruct config_source *prev;\n@@ -37,6 +38,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@@ -84,6 +86,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+\tstatic struct strbuf key = STRBUF_INIT;\n+\tstatic int loaded;\n+\tint i, dtype;\n+\n+\tif (!loaded) {\n+\t\tadd_excludes_from_file_to_list(git_path(\"info/config.worktree\"),\n+\t\t\t\t\t       \"\", 0, &config_local, 0);\n+\t\tloaded = 1;\n+\t}\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@@ -1167,6 +1197,15 @@ int git_config_system(void)\n \treturn !git_env_bool(\"GIT_CONFIG_NOSYSTEM\", 0);\n }\n \n+static int config_local_filter(const char *var, 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 does not belong to config.worktree\", var);\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 {\n \tint ret = 0, found = 0;\n@@ -1192,8 +1231,19 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)\n \t}\n \n \tif (repo_config && !access_or_die(repo_config, R_OK, 0)) {\n+\t\tchar *wt_config;\n \t\tret += git_config_from_file(fn, repo_config, data);\n \t\tfound += 1;\n+\t\twt_config = git_pathdup(\"config.worktree\");\n+\t\tif (!access_or_die(wt_config, R_OK, 0)) {\n+\t\t\tstruct config_include_data inc = CONFIG_INCLUDE_INIT;\n+\t\t\tinc.fn = fn;\n+\t\t\tinc.data = data;\n+\t\t\tret += git_config_from_file(config_local_filter,\n+\t\t\t\t\t\t    wt_config, &inc);\n+\t\t\tfound += 1;\n+\t\t}\n+\t\tfree(wt_config);\n \t}\n \n \tswitch (git_config_from_parameters(fn, data)) {\n@@ -1932,6 +1982,23 @@ int git_config_set_multivar_in_file(const char *config_filename,\n \n \tstore.multi_replace = multi_replace;\n \n+\tif (is_config_local(key)) {\n+\t\tif (!config_filename)\n+\t\t\tconfig_filename = filename_buf = git_pathdup(\"config.worktree\");\n+\t\t/* cheap trick, but should work 90% of time */\n+\t\telse if (!ends_with(config_filename, \".worktree\"))\n+\t\t\tdie(\"%s can only be stored in %s\",\n+\t\t\t    key, git_path(\"config.worktree\"));\n+\t\telse {\n+\t\t\tstruct strbuf sb = STRBUF_INIT;\n+\t\t\tstrbuf_addstr(&sb, real_path(config_filename));\n+\t\t\tif (strcmp_icase(sb.buf,\n+\t\t\t\t\t real_path(git_path(\"config.worktree\"))))\n+\t\t\t\tdie(\"%s can only be stored in %s\",\n+\t\t\t\t    key, git_path(\"config.worktree\"));\n+\t\t\tstrbuf_release(&sb);\n+\t\t}\n+\t}\n \tif (!config_filename)\n \t\tconfig_filename = filename_buf = git_pathdup(\"config\");\n \ndiff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh\nindex 938fc8b..c01effb 100755\n--- a/t/t1300-repo-config.sh\n+++ b/t/t1300-repo-config.sh\n@@ -1179,4 +1179,38 @@ test_expect_success POSIXPERM,PERL 'preserves existing permissions' '\n \t  \"die q(badrename) if ((stat(q(.git/config)))[2] & 07777) != 0600\"\n '\n \n+test_expect_success 'setting worktree.foo goes to config.worktree' '\n+\ttest_when_finished \"rm .git/config.worktree\" &&\n+\techo \"worktree/*\" >.git/info/config.worktree &&\n+\tgit config wOrktree.foo bar &&\n+\tcat >expect <<\\EOF &&\n+[wOrktree]\n+\tfoo = bar\n+EOF\n+\ttest_cmp expect .git/config.worktree &&\n+\ttest \"`git config woRktree.foo`\" = bar\n+'\n+\n+test_expect_success 'setting --local worktree.foo goes to config.worktree' '\n+\ttest_when_finished \"rm .git/config.worktree\" &&\n+\techo \"worktree/*\" >.git/info/config.worktree &&\n+\tgit config --local worKtree.fooo barr &&\n+\tcat >expect <<\\EOF &&\n+[worKtree]\n+\tfooo = barr\n+EOF\n+\ttest_cmp expect .git/config.worktree &&\n+\ttest \"`git config worktreE.fooo`\" = barr\n+'\n+\n+test_expect_success 'setting worktree.foo outside config.worktree' '\n+\techo \"worktree/*\" >.git/info/config.worktree &&\n+\ttest_must_fail git config --global Worktree.foo bar 2>err &&\n+\tgrep config.worktree err &&\n+\ttest_must_fail git config --system workTree.foo bar 2>err &&\n+\tgrep config.worktree err &&\n+\ttest_must_fail git config --file foo.worktree worktree.foo bar 2>err &&\n+\tgrep config.worktree err\n+'\n+\n test_done\n-- \n2.3.0.rc1.137.g477eb31\n"},{"id":"258574","messageId":"20150326221906.GA6745@wheezy.local","threadId":"38527","inReplyTo":"1427371464-22237-1-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH v2] config.c: split some variables to $GIT_DIR/config.worktree","fromName":"Max Kirillov","fromEmail":"max@max630.net","sentAt":"2015-03-26T22:19:06Z","receivedAt":"2015-03-26T22:19:06Z","isPatch":true,"sender":{"key":"max@max630.net","avatar":"https://avatars.githubusercontent.com/u/381560?v=4"},"body":"On Thu, Mar 26, 2015 at 07:04:24PM +0700, Nguyễn Thái Ngọc Duy wrote:\n> When you define $GIT_DIR/info/config.worktree, which contains of\n> gitignore-style patterns (*), config variables that match these\n> patterns will be saved in $GIT_DIR/config.worktree instead of\n> $GIT_DIR/config.\n\nShould it rather be in GIT_COMMON_DIR? As far as I\nunderstand, its meaning is \"variables which we allow to use\nper-worktree because we intend to have them different in\ndifferent worktrees, and sure no bad issues\ncan happen because this. It is not hardcored in git because\nthe list is going to extend, and we'd like to allow older\nversions of git (and other git implementations) to be still\nable to understand newer repositories\". So there should be\nno sense to make the list worktree-specific.\n\nAlso, probably the per-worktree variables should be searched\nfor in both common config and per-worktree config, and the\nmain repository should not have config.worktree, to be able\nto work with implementations which are not aware of the\nwhole multiple worktrees feature. And in worktrees, if the\nvariable is not defined in config.wortree, the default\nvaalue should come from common config. This though has\ndownside that worktree cannot use the more global vlue for\nvariable implicitly.\n\n-- \nMax\n\n> On the surface, they are just like any other variables. You can read\n> or modify them with `git config` command, or config_* API. Underneath,\n> they are always stored in $GIT_DIR/config.worktree instead of\n> $GIT_DIR/config (and never in $HOME/.gitconfig or /etc/gitconfig)\n> \n> The reason for this split is, as the name implies, for\n> worktree-specific configuration. When the same repo is attached to\n> more than one worktree, we can't use $GIT_DIR/config to store worktree\n> specific stuff because it's shared across worktrees.\n> \n> (*) Config variable names are separated by dots. However as this is a\n> quick and dirty patch to experiment with submodules and multiple\n> worktrees, you must substitute dots with slashes when writing these\n> patterns, for now. E.g. write \"remote/*/foo\" instead of \"remote.*.foo\"\n> \n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> ---\n>  Something for Max to play with if he's still experimenting with\n>  multiple worktree support for submodules :-) It's far from perfect,\n>  but good enough for this purpose.\n> \n>  Documentation/config.txt |  6 ++++-\n>  builtin/config.c         |  8 ++++++\n>  config.c                 | 67 ++++++++++++++++++++++++++++++++++++++++++++++++\n>  t/t1300-repo-config.sh   | 34 ++++++++++++++++++++++++\n>  4 files changed, 114 insertions(+), 1 deletion(-)\n> \n> diff --git a/Documentation/config.txt b/Documentation/config.txt\n> index 2700a1b..6d00f49 100644\n> --- a/Documentation/config.txt\n> +++ b/Documentation/config.txt\n> @@ -2,11 +2,15 @@ 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> +the Git commands' behavior. The `.git/config` and `.git/config.worktree`\n> +files in each repository\n>  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.\n> +If `.git/info/core.worktree` exists, it contains gitignore-style\n> +patterns. Variables that match these patterns can only be contained in\n> +`.git/config.worktree`.\n>  \n>  The configuration variables are used by both the Git plumbing\n>  and the porcelains. The variables are divided into sections, wherein\n> diff --git a/builtin/config.c b/builtin/config.c\n> index 8cc2604..4ca8fc2 100644\n> --- a/builtin/config.c\n> +++ b/builtin/config.c\n> @@ -555,6 +555,14 @@ int cmd_config(int argc, const char **argv, const char *prefix)\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 (actions == ACTION_LIST) {\n>  \t\tcheck_argc(argc, 0, 0);\n>  \t\tif (git_config_with_options(show_all_config, NULL,\n> diff --git a/config.c b/config.c\n> index 15a2983..f68eb6a 100644\n> --- a/config.c\n> +++ b/config.c\n> @@ -12,6 +12,7 @@\n>  #include \"quote.h\"\n>  #include \"hashmap.h\"\n>  #include \"string-list.h\"\n> +#include \"dir.h\"\n>  \n>  struct config_source {\n>  \tstruct config_source *prev;\n> @@ -37,6 +38,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> @@ -84,6 +86,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> +\tstatic struct strbuf key = STRBUF_INIT;\n> +\tstatic int loaded;\n> +\tint i, dtype;\n> +\n> +\tif (!loaded) {\n> +\t\tadd_excludes_from_file_to_list(git_path(\"info/config.worktree\"),\n> +\t\t\t\t\t       \"\", 0, &config_local, 0);\n> +\t\tloaded = 1;\n> +\t}\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> @@ -1167,6 +1197,15 @@ int git_config_system(void)\n>  \treturn !git_env_bool(\"GIT_CONFIG_NOSYSTEM\", 0);\n>  }\n>  \n> +static int config_local_filter(const char *var, 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 does not belong to config.worktree\", var);\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>  {\n>  \tint ret = 0, found = 0;\n> @@ -1192,8 +1231,19 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)\n>  \t}\n>  \n>  \tif (repo_config && !access_or_die(repo_config, R_OK, 0)) {\n> +\t\tchar *wt_config;\n>  \t\tret += git_config_from_file(fn, repo_config, data);\n>  \t\tfound += 1;\n> +\t\twt_config = git_pathdup(\"config.worktree\");\n> +\t\tif (!access_or_die(wt_config, R_OK, 0)) {\n> +\t\t\tstruct config_include_data inc = CONFIG_INCLUDE_INIT;\n> +\t\t\tinc.fn = fn;\n> +\t\t\tinc.data = data;\n> +\t\t\tret += git_config_from_file(config_local_filter,\n> +\t\t\t\t\t\t    wt_config, &inc);\n> +\t\t\tfound += 1;\n> +\t\t}\n> +\t\tfree(wt_config);\n>  \t}\n>  \n>  \tswitch (git_config_from_parameters(fn, data)) {\n> @@ -1932,6 +1982,23 @@ int git_config_set_multivar_in_file(const char *config_filename,\n>  \n>  \tstore.multi_replace = multi_replace;\n>  \n> +\tif (is_config_local(key)) {\n> +\t\tif (!config_filename)\n> +\t\t\tconfig_filename = filename_buf = git_pathdup(\"config.worktree\");\n> +\t\t/* cheap trick, but should work 90% of time */\n> +\t\telse if (!ends_with(config_filename, \".worktree\"))\n> +\t\t\tdie(\"%s can only be stored in %s\",\n> +\t\t\t    key, git_path(\"config.worktree\"));\n> +\t\telse {\n> +\t\t\tstruct strbuf sb = STRBUF_INIT;\n> +\t\t\tstrbuf_addstr(&sb, real_path(config_filename));\n> +\t\t\tif (strcmp_icase(sb.buf,\n> +\t\t\t\t\t real_path(git_path(\"config.worktree\"))))\n> +\t\t\t\tdie(\"%s can only be stored in %s\",\n> +\t\t\t\t    key, git_path(\"config.worktree\"));\n> +\t\t\tstrbuf_release(&sb);\n> +\t\t}\n> +\t}\n>  \tif (!config_filename)\n>  \t\tconfig_filename = filename_buf = git_pathdup(\"config\");\n>  \n> diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh\n> index 938fc8b..c01effb 100755\n> --- a/t/t1300-repo-config.sh\n> +++ b/t/t1300-repo-config.sh\n> @@ -1179,4 +1179,38 @@ test_expect_success POSIXPERM,PERL 'preserves existing permissions' '\n>  \t  \"die q(badrename) if ((stat(q(.git/config)))[2] & 07777) != 0600\"\n>  '\n>  \n> +test_expect_success 'setting worktree.foo goes to config.worktree' '\n> +\ttest_when_finished \"rm .git/config.worktree\" &&\n> +\techo \"worktree/*\" >.git/info/config.worktree &&\n> +\tgit config wOrktree.foo bar &&\n> +\tcat >expect <<\\EOF &&\n> +[wOrktree]\n> +\tfoo = bar\n> +EOF\n> +\ttest_cmp expect .git/config.worktree &&\n> +\ttest \"`git config woRktree.foo`\" = bar\n> +'\n> +\n> +test_expect_success 'setting --local worktree.foo goes to config.worktree' '\n> +\ttest_when_finished \"rm .git/config.worktree\" &&\n> +\techo \"worktree/*\" >.git/info/config.worktree &&\n> +\tgit config --local worKtree.fooo barr &&\n> +\tcat >expect <<\\EOF &&\n> +[worKtree]\n> +\tfooo = barr\n> +EOF\n> +\ttest_cmp expect .git/config.worktree &&\n> +\ttest \"`git config worktreE.fooo`\" = barr\n> +'\n> +\n> +test_expect_success 'setting worktree.foo outside config.worktree' '\n> +\techo \"worktree/*\" >.git/info/config.worktree &&\n> +\ttest_must_fail git config --global Worktree.foo bar 2>err &&\n> +\tgrep config.worktree err &&\n> +\ttest_must_fail git config --system workTree.foo bar 2>err &&\n> +\tgrep config.worktree err &&\n> +\ttest_must_fail git config --file foo.worktree worktree.foo bar 2>err &&\n> +\tgrep config.worktree err\n> +'\n> +\n>  test_done\n> -- \n> 2.3.0.rc1.137.g477eb31\n> \n"},{"id":"258645","messageId":"CACsJy8DqgX91KYd5m3PvYSTXYdCO8YV-5R+v6LnzerS6TOr+5A@mail.gmail.com","threadId":"38527","inReplyTo":"20150326221906.GA6745@wheezy.local","subject":"Re: [PATCH v2] config.c: split some variables to $GIT_DIR/config.worktree","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2015-03-29T01:25:33Z","receivedAt":"2015-03-29T01:25:33Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Fri, Mar 27, 2015 at 5:19 AM, Max Kirillov <max@max630.net> wrote:\n> On Thu, Mar 26, 2015 at 07:04:24PM +0700, Nguyễn Thái Ngọc Duy wrote:\n>> When you define $GIT_DIR/info/config.worktree, which contains of\n>> gitignore-style patterns (*), config variables that match these\n>> patterns will be saved in $GIT_DIR/config.worktree instead of\n>> $GIT_DIR/config.\n>\n> Should it rather be in GIT_COMMON_DIR? As far as I\n> understand, its meaning is \"variables which we allow to use\n> per-worktree because we intend to have them different in\n> different worktrees, and sure no bad issues\n> can happen because this. It is not hardcored in git because\n> the list is going to extend, and we'd like to allow older\n> versions of git (and other git implementations) to be still\n> able to understand newer repositories\". So there should be\n> no sense to make the list worktree-specific.\n\nI'm not sure if \"it\" means $GIT_DIR/config.worktree or\n$GIT_DIR/info/config.worktree. At this point $GIT_COMMON_DIR is not\ninvolved (i.e. you can still spit config even in a normal repo).\n.../info/config.worktree may be shared, I guess.\n\nThe \"older versions of git (and other git implementations)\" raises an\nissue with this patch. Older impl just ignore config.worktree. I think\nI need to bump core.repositoryformatversion up to avoid that.\n\n> Also, probably the per-worktree variables should be searched\n> for in both common config and per-worktree config, and the\n> main repository should not have config.worktree, to be able\n> to work with implementations which are not aware of the\n> whole multiple worktrees feature. And in worktrees, if the\n> variable is not defined in config.wortree, the default\n> vaalue should come from common config. This though has\n> downside that worktree cannot use the more global vlue for\n> variable implicitly.\n\nThe main worktree may or may not use per-worktree config (it's\ntechnically possible): if we enforce config.worktree on the main\nworktree, we don't have to worry about the same variable defined in\nboth common and per-worktree config. Enforcing may require more work:\nimagine the worktree list is updated, some in the common config may\nbecome per-worktree and need to be moved to config.worktree.. If we\nallow per-worktree vars in the common config, other worktrees should\nignore them in common config.\n-- \nDuy\n"},{"id":"258696","messageId":"20150330212642.GA28003@wheezy.local","threadId":"38527","inReplyTo":"CACsJy8DqgX91KYd5m3PvYSTXYdCO8YV-5R+v6LnzerS6TOr+5A@mail.gmail.com","subject":"Re: [PATCH v2] config.c: split some variables to $GIT_DIR/config.worktree","fromName":"Max Kirillov","fromEmail":"max@max630.net","sentAt":"2015-03-30T21:26:42Z","receivedAt":"2015-03-30T21:26:42Z","isPatch":true,"sender":{"key":"max@max630.net","avatar":"https://avatars.githubusercontent.com/u/381560?v=4"},"body":"On Sun, Mar 29, 2015 at 08:25:33AM +0700, Duy Nguyen wrote:\n> I'm not sure if \"it\" means $GIT_DIR/config.worktree or\n> $GIT_DIR/info/config.worktree. At this point $GIT_COMMON_DIR is not\n> involved (i.e. you can still spit config even in a normal repo).\n> .../info/config.worktree may be shared, I guess.\n\nYes, I meant info/config.worktree\n\n> The \"older versions of git (and other git implementations)\" raises an\n> issue with this patch. Older impl just ignore config.worktree. I think\n> I need to bump core.repositoryformatversion up to avoid that.\n\nAs a user I would like to still use some older tools, so I\ncannot say I like it.\n\nAnd, I guess bumping repository verion is something the\nwhole git ecosystem has not experienced yet. So it should be\nmuch more work and much more time, I cannot even imagine how\nmuch. I would still search for option without bumping\nversion.\n\n>> Also, probably the per-worktree variables should be searched\n>> for in both common config and per-worktree config, and the\n>> main repository should not have config.worktree, to be able\n>> to work with implementations which are not aware of the\n>> whole multiple worktrees feature. And in worktrees, if the\n>> variable is not defined in config.wortree, the default\n>> vaalue should come from common config. This though has\n>> downside that worktree cannot use the more global vlue for\n>> variable implicitly.\n> \n> The main worktree may or may not use per-worktree config (it's\n> technically possible): if we enforce config.worktree on the main\n> worktree, we don't have to worry about the same variable defined in\n> both common and per-worktree config. Enforcing may require more work:\n> imagine the worktree list is updated, some in the common config may\n> become per-worktree and need to be moved to config.worktree.. If we\n> allow per-worktree vars in the common config, other worktrees should\n> ignore them in common config.\n\nYes, probably always ignoring is good idea. They could be\ninitialized from the common config at worktree creation.\n\nPS: I wrote that nearly all variables could be per worktree.\nFor maintainability probably a better idea would be to start\nwith as few as possible and extend their default list as\nit's clear nothing will break.\n\n-- \nMax\n"},{"id":"258738","messageId":"1427804079-13061-1-git-send-email-pclouds@gmail.com","threadId":"38527","inReplyTo":"1427371464-22237-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v3] config.c: split some variables to $GIT_DIR/config.worktree","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2015-03-31T12:14:39Z","receivedAt":"2015-03-31T12:14:39Z","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 common set that does not match the patterns and the\nworktree set.\n\nIn normal worktree, or in the main worktree when \"git checkout --to\"\nis used, both sets are stored in .git/config. Nothing interesting.\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.\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.\n\ncore.worktree and core.bare, which are treated specially in 31e26eb [1],\nare now moved to info/core.worktree and the special treatment reverted.\n\n[1] 31e26eb (setup.c: support multi-checkout repo setup - 2014-11-30)\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 Much happier with this version, especially when we can now generalize\n the treatment for core.worktree and core.bare.\n \n The general principle is like in the last mail: .git/config is for\n both shared and private keys of main worktree (i.e. nothing is\n changed from today).  .git/worktrees/xx/config.worktree is for\n private keys only (and private keys in .git/config are ignored)\n \n With this we don't have to bump core.repository_format_version for\n main worktree because nothing is changed. There will be problems\n with info/config.worktree:\n\n  - it's customizable, so expect the user to break it (*)\n\n  - if we add new stuff to the template, we'll need to help migrate\n    current info/core.worktree (which does not have new stuff).\n    Auto updating this file could be risky. I'm tend to just\n    warn the user that this and that keys should be included and let\n    them modify the file.\n\n (*) but I don't want to keep the hard coded version of this in git\n binary either, simply to avoid this customization problem. The list\n compiled by Max shows that many keys may or may not be shared. So let\n the user decide what's best for them.\n\n Documentation/config.txt               | 10 ++++\n Documentation/gitrepository-layout.txt |  6 +++\n builtin/config.c                       |  8 +++\n cache.h                                |  2 +-\n config.c                               | 97 ++++++++++++++++++++++++++++++++--\n dir.c                                  | 41 ++++++++++++++\n dir.h                                  |  1 +\n setup.c                                |  8 +--\n t/t2025-checkout-to.sh                 | 26 +++++++++\n templates/info--config.worktree (new)  |  2 +\n 10 files changed, 189 insertions(+), 12 deletions(-)\n create mode 100644 templates/info--config.worktree\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 2700a1b..ca4de1f 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -8,6 +8,16 @@ 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 \"multple working trees\" in\n+linkgit:git-checkout[1]) have two config files under its \".git\"\n+directory: \"config\" is shared with other worktrees while\n+\"config.worktree\" is per worktree. Configuration variables that match\n+patterns in $GIT_DIR/info/config.worktree are stored and read from\n+\"config.worktree\". Matched configuration variables in \"config\" is\n+ignored by linked worktrees. They are only used by the main\n+worktree. The patterns follow gitignore syntax, where the separator is\n+'.' instead of '/'.\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 7173b38..6228280 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/checkout.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',\ndiff --git a/builtin/config.c b/builtin/config.c\nindex 8cc2604..4ca8fc2 100644\n--- a/builtin/config.c\n+++ b/builtin/config.c\n@@ -555,6 +555,14 @@ int cmd_config(int argc, const char **argv, const char *prefix)\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 (actions == ACTION_LIST) {\n \t\tcheck_argc(argc, 0, 0);\n \t\tif (git_config_with_options(show_all_config, NULL,\ndiff --git a/cache.h b/cache.h\nindex 670e861..9431117 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1355,7 +1355,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_config_int(const char *, const char *);\n extern int64_t git_config_int64(const char *, const char *);\ndiff --git a/config.c b/config.c\nindex 15a2983..3857023 100644\n--- a/config.c\n+++ b/config.c\n@@ -12,6 +12,7 @@\n #include \"quote.h\"\n #include \"hashmap.h\"\n #include \"string-list.h\"\n+#include \"dir.h\"\n \n struct config_source {\n \tstruct config_source *prev;\n@@ -37,6 +38,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@@ -84,6 +86,33 @@ 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+\tstatic struct strbuf key = STRBUF_INIT;\n+\tstatic int loaded;\n+\tint i, dtype;\n+\n+\tif (!loaded) {\n+\t\tload_config_worktree(&config_local, git_path(\"info/config.worktree\"));\n+\t\tloaded = 1;\n+\t}\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@@ -1167,7 +1196,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 = NULL;\n@@ -1191,7 +1242,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@@ -1217,6 +1284,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@@ -1239,9 +1307,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@@ -1932,6 +2002,23 @@ int git_config_set_multivar_in_file(const char *config_filename,\n \n \tstore.multi_replace = multi_replace;\n \n+\tif (git_common_dir_env && is_config_local(key)) {\n+\t\tif (!config_filename)\n+\t\t\tconfig_filename = filename_buf = git_pathdup(\"config.worktree\");\n+\t\t/* cheap trick, but should work 90% of time */\n+\t\telse if (!ends_with(config_filename, \".worktree\"))\n+\t\t\tdie(\"%s can only be stored in %s\",\n+\t\t\t    key, git_path(\"config.worktree\"));\n+\t\telse {\n+\t\t\tstruct strbuf sb = STRBUF_INIT;\n+\t\t\tstrbuf_addstr(&sb, real_path(config_filename));\n+\t\t\tif (strcmp_icase(sb.buf,\n+\t\t\t\t\t real_path(git_path(\"config.worktree\"))))\n+\t\t\t\tdie(\"%s can only be stored in %s\",\n+\t\t\t\t    key, git_path(\"config.worktree\"));\n+\t\t\tstrbuf_release(&sb);\n+\t\t}\n+\t}\n \tif (!config_filename)\n \t\tconfig_filename = filename_buf = git_pathdup(\"config\");\n \ndiff --git a/dir.c b/dir.c\nindex 3f7a025..69bf491 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -589,6 +589,47 @@ int add_excludes_from_file_to_list(const char *fname,\n \treturn 0;\n }\n \n+void load_config_worktree(struct exclude_list *el, const char *path)\n+{\n+\tstruct strbuf sb = STRBUF_INIT;\n+\tint i, lineno = 1;\n+\tchar *buf, *entry;\n+\tsize_t size;\n+\n+\tif (strbuf_read_file(&sb, path, 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 struct exclude_list *add_exclude_list(struct dir_struct *dir,\n \t\t\t\t      int group_type, const char *src)\n {\ndiff --git a/dir.h b/dir.h\nindex 6c45e9d..539423d 100644\n--- a/dir.h\n+++ b/dir.h\n@@ -165,6 +165,7 @@ extern struct exclude_list *add_exclude_list(struct dir_struct *dir,\n \t\t\t\t\t     int group_type, const char *src);\n extern int add_excludes_from_file_to_list(const char *fname, const char *base, int baselen,\n \t\t\t\t\t  struct exclude_list *el, int check_index);\n+extern void load_config_worktree(struct exclude_list *el, const char *fname);\n extern void add_excludes_from_file(struct dir_struct *, const char *fname);\n extern void parse_exclude_pattern(const char **string, int *patternlen, int *flags, int *nowildcardlen);\n extern void add_exclude(const char *string, const char *base,\ndiff --git a/setup.c b/setup.c\nindex fb61860..61e0403 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -356,13 +356,9 @@ static int check_repository_format_gently(const char *gitdir, int *nongit_ok)\n {\n \tstruct strbuf sb = STRBUF_INIT;\n \tconst char *repo_config;\n-\tconfig_fn_t fn;\n \tint ret = 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+\tget_common_dir(&sb, gitdir);\n \tstrbuf_addstr(&sb, \"/config\");\n \trepo_config = sb.buf;\n \n@@ -375,7 +371,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(check_repository_format_version, NULL, repo_config, NULL);\n \tif (GIT_REPO_VERSION < repository_format_version) {\n \t\tif (!nongit_ok)\n \t\t\tdie (\"Expected git repo version <= %d, found %d\",\ndiff --git a/t/t2025-checkout-to.sh b/t/t2025-checkout-to.sh\nindex f8e4df4..6f98279 100755\n--- a/t/t2025-checkout-to.sh\n+++ b/t/t2025-checkout-to.sh\n@@ -126,4 +126,30 @@ test_expect_success 'checkout with grafts' '\n \ttest_cmp expected actual\n '\n \n+test_expect_success 'setting worktree.foo goes to config.worktree' '\n+\techo worKtree.Foo >> .git/info/config.worktree &&\n+\tgit checkout --to 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\ndiff --git a/templates/info--config.worktree b/templates/info--config.worktree\nnew file mode 100644\nindex 0000000..f358230\n--- /dev/null\n+++ b/templates/info--config.worktree\n@@ -0,0 +1,2 @@\n+core.worktree\n+core.bare\n-- \n2.3.0.rc1.137.g477eb31\n"},{"id":"258739","messageId":"CACsJy8DQZmySvakBnjgEX2rPb4ndYo52XSoCeNHosh2VNaRFCg@mail.gmail.com","threadId":"38527","inReplyTo":"1427804079-13061-1-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH v3] config.c: split some variables to $GIT_DIR/config.worktree","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2015-03-31T12:17:10Z","receivedAt":"2015-03-31T12:17:10Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Tue, Mar 31, 2015 at 7:14 PM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:\n>  The general principle is like in the last mail: .git/config is for\n>  both shared and private keys of main worktree (i.e. nothing is\n>  changed from today).  .git/worktrees/xx/config.worktree is for\n>  private keys only (and private keys in .git/config are ignored)\n\nWhen I put it this way, I realize that\n.git/worktrees/xx/config.worktree can simply be\n.git/worktrees/xx/config. No \".worktree\". Looks nice (or it's just a\nsource of more confusion later)\n-- \nDuy\n"},{"id":"258836","messageId":"20150401205644.GA3656@wheezy.local","threadId":"38527","inReplyTo":"1427804079-13061-1-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH v3] config.c: split some variables to $GIT_DIR/config.worktree","fromName":"Max Kirillov","fromEmail":"max@max630.net","sentAt":"2015-04-01T20:56:44Z","receivedAt":"2015-04-01T20:56:44Z","isPatch":true,"sender":{"key":"max@max630.net","avatar":"https://avatars.githubusercontent.com/u/381560?v=4"},"body":"On Tue, Mar 31, 2015 at 07:14:39PM +0700, Nguyễn Thái Ngọc Duy wrote:\n>  The general principle is like in the last mail: .git/config is for\n>  both shared and private keys of main worktree (i.e. nothing is\n>  changed from today).  .git/worktrees/xx/config.worktree is for\n>  private keys only (and private keys in .git/config are ignored)\n>  \n>  With this we don't have to bump core.repository_format_version for\n>  main worktree because nothing is changed. There will be problems\n>  with info/config.worktree:\n> \n>   - it's customizable, so expect the user to break it (*)\n\nI would rather say it's manual tuning rather than a break.\n\n>   - if we add new stuff to the template, we'll need to help migrate\n>     current info/core.worktree (which does not have new stuff).\n>     Auto updating this file could be risky. I'm tend to just\n>     warn the user that this and that keys should be included and let\n>     them modify the file.\n\nI don't think there even should be warning. Just don't\nchange the info/config.worktree in the existing repositories\nand let users extend it as they feel a need for it.\n\nLater there could be a tool (an option to git config for\nexample) which adds a variable or pattern to the\ninfo/core.worktree and copied existing variable(s) from\ncommong config to worktree-specific ones.\n\n....\n\n> diff --git a/config.c b/config.c\n> index 15a2983..3857023 100644\n> --- a/config.c\n> +++ b/config.c\n....\n> @@ -1932,6 +2002,23 @@ int git_config_set_multivar_in_file(const char *config_filename,\n>  \n>  \tstore.multi_replace = multi_replace;\n>  \n> +\tif (git_common_dir_env && is_config_local(key)) {\n> +\t\tif (!config_filename)\n> +\t\t\tconfig_filename = filename_buf = git_pathdup(\"config.worktree\");\n> +\t\t/* cheap trick, but should work 90% of time */\n> +\t\telse if (!ends_with(config_filename, \".worktree\"))\n> +\t\t\tdie(\"%s can only be stored in %s\",\n> +\t\t\t    key, git_path(\"config.worktree\"));\n\nIs `config_filename` set only for cases when config file is\nexplicitly set for \"git config\" command with \"--file\"\noption? Then probably here should not be any intelligence at\nall; if user resort to manual picking the file he must be\nallowed to do stupid things.\n\n-- \nMax\n"},{"id":"258919","messageId":"CACsJy8C=MPLyba68ttQ2hhrM7bg8E-tEG-0kUjTLnNMMbX0MUQ@mail.gmail.com","threadId":"38527","inReplyTo":"20150401205644.GA3656@wheezy.local","subject":"Re: [PATCH v3] config.c: split some variables to $GIT_DIR/config.worktree","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2015-04-03T10:30:58Z","receivedAt":"2015-04-03T10:30:58Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Thu, Apr 2, 2015 at 3:56 AM, Max Kirillov <max@max630.net> wrote:\n> On Tue, Mar 31, 2015 at 07:14:39PM +0700, Nguyễn Thái Ngọc Duy wrote:\n>>  The general principle is like in the last mail: .git/config is for\n>>  both shared and private keys of main worktree (i.e. nothing is\n>>  changed from today).  .git/worktrees/xx/config.worktree is for\n>>  private keys only (and private keys in .git/config are ignored)\n>>\n>>  With this we don't have to bump core.repository_format_version for\n>>  main worktree because nothing is changed. There will be problems\n>>  with info/config.worktree:\n>>\n>>   - it's customizable, so expect the user to break it (*)\n>\n> I would rather say it's manual tuning rather than a break.\n\nBut if the user accidentally deletes core.worktree then something will break.\n\n>>   - if we add new stuff to the template, we'll need to help migrate\n>>     current info/core.worktree (which does not have new stuff).\n>>     Auto updating this file could be risky. I'm tend to just\n>>     warn the user that this and that keys should be included and let\n>>     them modify the file.\n>\n> I don't think there even should be warning. Just don't\n> change the info/config.worktree in the existing repositories\n> and let users extend it as they feel a need for it.\n>\n> Later there could be a tool (an option to git config for\n> example) which adds a variable or pattern to the\n> info/core.worktree and copied existing variable(s) from\n> commong config to worktree-specific ones.\n\nI was thinking \"git checkout --to\" would do this. It checks if the\nmain worktree has info/core.worktree, if not, re-init the repo to add\nthis file from default template.\n\n>> @@ -1932,6 +2002,23 @@ int git_config_set_multivar_in_file(const char *config_filename,\n>>\n>>       store.multi_replace = multi_replace;\n>>\n>> +     if (git_common_dir_env && is_config_local(key)) {\n>> +             if (!config_filename)\n>> +                     config_filename = filename_buf = git_pathdup(\"config.worktree\");\n>> +             /* cheap trick, but should work 90% of time */\n>> +             else if (!ends_with(config_filename, \".worktree\"))\n>> +                     die(\"%s can only be stored in %s\",\n>> +                         key, git_path(\"config.worktree\"));\n>\n> Is `config_filename` set only for cases when config file is\n> explicitly set for \"git config\" command with \"--file\"\n> option? Then probably here should not be any intelligence at\n> all; if user resort to manual picking the file he must be\n> allowed to do stupid things.\n\nYes. It may make sense in the previous versions where this feature\ncould work in a normal worktree, but when it becomes\nmultiworktree-specific, I guess we can drop this.\n-- \nDuy\n"},{"id":"259313","messageId":"20150413233739.GA786@wheezy.local","threadId":"38527","inReplyTo":"1427804079-13061-1-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH v3] config.c: split some variables to $GIT_DIR/config.worktree","fromName":"Max Kirillov","fromEmail":"max@max630.net","sentAt":"2015-04-13T23:37:39Z","receivedAt":"2015-04-13T23:37:39Z","isPatch":true,"sender":{"key":"max@max630.net","avatar":"https://avatars.githubusercontent.com/u/381560?v=4"},"body":"On Tue, Mar 31, 2015 at 07:14:39PM +0700, Nguyễn Thái Ngọc Duy wrote:\n> core.worktree and core.bare, which are treated specially in 31e26eb [1],\n> are now moved to info/core.worktree and the special treatment reverted.\n<...>\n> -\tif (get_common_dir(&sb, gitdir))\n> -\t\tfn = check_repo_format;\n> -\telse\n> -\t\tfn = check_repository_format_version;\n\nBy the way, after this '$GIT_DIR/common overrides core.worktree'\nfrom t1501 started failing. I don't know what would be\nbetter to do with the case, just remove maybe?\n\n-- \nMax\n"},{"id":"259623","messageId":"20150418111023.GA1496@lanh","threadId":"38527","inReplyTo":"20150413233739.GA786@wheezy.local","subject":"Re: [PATCH v3] config.c: split some variables to $GIT_DIR/config.worktree","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2015-04-18T11:10:23Z","receivedAt":"2015-04-18T11:10:23Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Tue, Apr 14, 2015 at 02:37:39AM +0300, Max Kirillov wrote:\n> On Tue, Mar 31, 2015 at 07:14:39PM +0700, Nguyễn Thái Ngọc Duy wrote:\n> > core.worktree and core.bare, which are treated specially in 31e26eb [1],\n> > are now moved to info/core.worktree and the special treatment reverted.\n> <...>\n> > -\tif (get_common_dir(&sb, gitdir))\n> > -\t\tfn = check_repo_format;\n> > -\telse\n> > -\t\tfn = check_repository_format_version;\n> \n> By the way, after this '$GIT_DIR/common overrides core.worktree'\n> from t1501 started failing. I don't know what would be\n> better to do with the case, just remove maybe?\n\nI think that test spots a real problem. In this function, I ignore the\nconfig split when I pass NULL as worktree_config to git_config_early().\nSomething like this should fix it.\n\n-- 8< --\ndiff --git a/setup.c b/setup.c\nindex 61e0403..4799e7d 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -355,10 +355,15 @@ 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 sb_wt = STRBUF_INIT;\n \tconst char *repo_config;\n+\tconst char *worktree_config = NULL;\n \tint ret = 0;\n \n-\tget_common_dir(&sb, gitdir);\n+\tif (get_common_dir(&sb, gitdir)) {\n+\t\tstrbuf_addf(&sb_wt, \"%s/config.worktree\", get_git_dir());\n+\t\tworktree_config = sb_wt.buf;\n+\t}\n \tstrbuf_addstr(&sb, \"/config\");\n \trepo_config = sb.buf;\n \n@@ -371,7 +376,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(check_repository_format_version, 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 < repository_format_version) {\n \t\tif (!nongit_ok)\n \t\t\tdie (\"Expected git repo version <= %d, found %d\",\n@@ -383,6 +389,7 @@ static int check_repository_format_gently(const char *gitdir, int *nongit_ok)\n \t\tret = -1;\n \t}\n \tstrbuf_release(&sb);\n+\tstrbuf_release(&sb_wt);\n \treturn ret;\n }\n \n-- 8< --\n"},{"id":"259654","messageId":"20150420025110.GD786@wheezy.local","threadId":"38527","inReplyTo":"20150418111023.GA1496@lanh","subject":"Re: [PATCH v3] config.c: split some variables to $GIT_DIR/config.worktree","fromName":"Max Kirillov","fromEmail":"max@max630.net","sentAt":"2015-04-20T02:51:32Z","receivedAt":"2015-04-20T02:51:32Z","isPatch":true,"sender":{"key":"max@max630.net","avatar":"https://avatars.githubusercontent.com/u/381560?v=4"},"body":"On Sat, Apr 18, 2015 at 06:10:23PM +0700, Duy Nguyen wrote:\n> On Tue, Apr 14, 2015 at 02:37:39AM +0300, Max Kirillov wrote:\n> > On Tue, Mar 31, 2015 at 07:14:39PM +0700, Nguyễn Thái Ngọc Duy wrote:\n> > > core.worktree and core.bare, which are treated specially in 31e26eb [1],\n> > > are now moved to info/core.worktree and the special treatment reverted.\n> > <...>\n> > > -\tif (get_common_dir(&sb, gitdir))\n> > > -\t\tfn = check_repo_format;\n> > > -\telse\n> > > -\t\tfn = check_repository_format_version;\n> > \n> > By the way, after this '$GIT_DIR/common overrides core.worktree'\n> > from t1501 started failing. I don't know what would be\n> > better to do with the case, just remove maybe?\n> \n> I think that test spots a real problem. In this function, I ignore the\n> config split when I pass NULL as worktree_config to git_config_early().\n> Something like this should fix it.\n\nI just realized that the testcase does have\ninfo/config.worktree with the variable included, because\nany repository has it. Then, of course, the variable from\ncommon directory should be ignored and the testcase is correct.\n\nBy the way, if checkout --to run on repository created\nbefore the feaure added, the linked checkout will not be\nable to use own variables. Should checkout --to check that\nthe file exists and create it in case it does not?\n"},{"id":"259655","messageId":"CACsJy8CLHwkiRn6+f4rjXDjWzJsJN8eN7rZJVewZg6mmrncbRQ@mail.gmail.com","threadId":"38527","inReplyTo":"20150420025110.GD786@wheezy.local","subject":"Re: [PATCH v3] config.c: split some variables to $GIT_DIR/config.worktree","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2015-04-20T03:22:39Z","receivedAt":"2015-04-20T03:22:39Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Mon, Apr 20, 2015 at 9:51 AM, Max Kirillov <max@max630.net> wrote:\n> By the way, if checkout --to run on repository created\n> before the feaure added, the linked checkout will not be\n> able to use own variables. Should checkout --to check that\n> the file exists and create it in case it does not?\n\nYes it should. I made some changes for that [1] but haven't posted in\nthe list yet because it's incomplete imo. I should check again after\nreinitializing the repo, whether core.worktree is in\ninfo/config.worktree, if not warn the user. This could happen if the\nuser defines a custom template.\n\n[1] https://github.com/pclouds/git/commit/f2276a37039d7a1f99fbcbc72e7d87b0782e4663\n-- \nDuy\n"}]}