From: "Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>
To: git@vger.kernel.org
Cc: git@drmicha.warpmail.net, max@max630.net, Jens.Lehmann@web.de,
"Junio C Hamano" <gitster@pobox.com>,
"Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>
Subject: [PATCH v2 2/6] config.c: move worktree-specific variables to .git/worktrees/...
Date: Sun, 27 Dec 2015 10:14:35 +0700 [thread overview]
Message-ID: <1451186079-6119-3-git-send-email-pclouds@gmail.com> (raw)
In-Reply-To: <1451186079-6119-1-git-send-email-pclouds@gmail.com>
In multiple worktree setup, a set of variables will be read from
$GIT_DIR/worktrees/<id>/config instead of $GIT_DIR/config, when the
config variables are accessed from a linked worktree. When accessed
from the main worktree, the same set is still read from $GIT_DIR/config.
This mechanism is needed because we do have worktree-specific config
variables such as core.worktree. But for now, no config variable is
marked per-worktree (so can't test yet).
This is the new behavior when repo extension worktree=1 is defined.
Helped-by: Max Kirillov <max@max630.net>
Helped-by: Jens Lehmann <Jens.Lehmann@web.de>
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
Documentation/config.txt | 4 ++
Documentation/git-worktree.txt | 11 +++
Documentation/gitrepository-layout.txt | 5 ++
builtin/config.c | 9 +++
cache.h | 2 +-
config.c | 121 +++++++++++++++++++++++++++++++--
setup.c | 2 +-
7 files changed, 145 insertions(+), 9 deletions(-)
diff --git a/Documentation/config.txt b/Documentation/config.txt
index f617886..d507b8a 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -8,6 +8,10 @@ is used to store the configuration for that repository, and
fallback values for the `.git/config` file. The file `/etc/gitconfig`
can be used to store a system-wide default configuration.
+Linked worktrees (see linkgit:git-worktree[1]) also have a
+worktree-specific file config. See linkgit:gitrepository-layout[5] for
+more information.
+
The configuration variables are used by both the Git plumbing
and the porcelains. The variables are divided into sections, wherein
the fully qualified variable name of the variable itself is the last
diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 5b9ad04..bc0734c 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -147,6 +147,17 @@ to `/path/main/.git/worktrees/test-next` then a file named
`test-next` entry from being pruned. See
linkgit:gitrepository-layout[5] for details.
+Similar to the file system split in ".git", the repository config file
+is also split. Certain variables, for example core.worktree, are
+per-worktree while the majority of variables are still shared (see
+linkgit:git-config[1] for details). Shared variables and per-working
+tree ones that belong to the main working tree are in .git/config.
+Per-working tree variables for working tree X are in
+$GIT_COMMON_DIR/worktrees/X/config. Even though per-working tree
+variables for the main working tree are in the default config place,
+they are invisible from all linked working trees. The following
+configuration variables are per working directory:
+
LIST OUTPUT FORMAT
------------------
The worktree list command has two output formats. The default format shows the
diff --git a/Documentation/gitrepository-layout.txt b/Documentation/gitrepository-layout.txt
index 577ee84..cf724e6 100644
--- a/Documentation/gitrepository-layout.txt
+++ b/Documentation/gitrepository-layout.txt
@@ -276,6 +276,11 @@ worktrees/<id>/link::
file. It is used to detect if the linked repository is
manually removed.
+worktrees/<id>/config::
+ This file contains worktree-specific configuration
+ variables. See the list of variables in linkgit:git-worktree[1].
+ The same variables in $GIT_COMMON_DIR/config are ignored.
+
SEE ALSO
--------
linkgit:git-init[1],
diff --git a/builtin/config.c b/builtin/config.c
index adc7727..2b4d56e 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -533,6 +533,15 @@ int cmd_config(int argc, const char **argv, const char *prefix)
default:
usage_with_options(builtin_config_usage, builtin_config_options);
}
+
+ /*
+ * For set operations, --local could be either config or
+ * config.worktree. Let config.c determine the path based on
+ * config keys.
+ */
+ if (use_local_config && actions != ACTION_LIST)
+ given_config_source.file = NULL;
+
if (omit_values &&
!(actions == ACTION_LIST || actions == ACTION_GET_REGEXP)) {
error("--name-only is only applicable to --list or --get-regexp");
diff --git a/cache.h b/cache.h
index fa0a64b..10f4ff8 100644
--- a/cache.h
+++ b/cache.h
@@ -1494,7 +1494,7 @@ extern void git_config(config_fn_t fn, void *);
extern int git_config_with_options(config_fn_t fn, void *,
struct git_config_source *config_source,
int respect_includes);
-extern int git_config_early(config_fn_t fn, void *, const char *repo_config);
+extern int git_config_early(config_fn_t fn, void *, const char *repo_config, const char *worktree_config);
extern int git_parse_ulong(const char *, unsigned long *);
extern int git_parse_maybe_bool(const char *);
extern int git_config_int(const char *, const char *);
diff --git a/config.c b/config.c
index 86a5eb2..7d94f21 100644
--- a/config.c
+++ b/config.c
@@ -37,10 +37,25 @@ struct config_source {
long (*do_ftell)(struct config_source *c);
};
+struct config_pattern {
+ unsigned int prefix;
+ unsigned int len;
+ const char *pattern;
+};
+
static struct config_source *cf;
static int zlib_compression_seen;
+static struct config_pattern worktree_v1[] = {
+ { 0, 0, NULL }
+};
+
+static struct config_pattern *worktree_patterns[] = {
+ NULL,
+ worktree_v1
+};
+
/*
* Default config_set that contains key-value pairs from the usual set of config
* config files (i.e repo specific .git/config, user wide ~/.gitconfig, XDG
@@ -89,6 +104,34 @@ static long config_buf_ftell(struct config_source *conf)
return conf->u.buf.pos;
}
+static int is_config_local(const char *key_)
+{
+ int len;
+ struct config_pattern *cp;
+
+ if (repository_format_worktree_version < 0 ||
+ repository_format_worktree_version >= ARRAY_SIZE(worktree_patterns))
+ die("unknown config version %d", repository_format_worktree_version);
+
+ cp = worktree_patterns[repository_format_worktree_version];
+ if (!cp)
+ return 0;
+ len = strlen(key_);
+ for (; ; cp++) {
+ if (!cp->pattern)
+ return 0;
+ if (!cp->len)
+ cp->len = strlen(cp->pattern);
+ if (len < cp->len)
+ continue;
+ if (strncmp(key_, cp->pattern, len))
+ continue;
+ if (!cp->prefix && len > cp->len)
+ continue;
+ return 1;
+ }
+}
+
#define MAX_INCLUDE_DEPTH 10
static const char include_depth_advice[] =
"exceeded maximum include depth (%d) while including\n"
@@ -1184,7 +1227,36 @@ int git_config_system(void)
return !git_env_bool("GIT_CONFIG_NOSYSTEM", 0);
}
-int git_config_early(config_fn_t fn, void *data, const char *repo_config)
+static char *worktree_config_path(void)
+{
+ struct strbuf sb = STRBUF_INIT;
+ strbuf_addf(&sb, "%s/config", get_git_dir());
+ return strbuf_detach(&sb, NULL);
+}
+
+static int config_worktree_filter_in(const char *var,
+ const char *value, void *data)
+{
+ struct config_include_data *inc = data;
+
+ if (!is_config_local(var))
+ return error("%s in per-worktree config file is ignored", var);
+ return inc->fn(var, value, inc->data);
+}
+
+static int config_worktree_filter_out(const char *var,
+ const char *value, void *data)
+{
+ struct config_include_data *inc = data;
+
+ if (is_config_local(var))
+ return 0; /* these are for main worktree only */
+
+ return inc->fn(var, value, inc->data);
+}
+
+int git_config_early(config_fn_t fn, void *data, const char *repo_config,
+ const char *worktree_config)
{
int ret = 0, found = 0;
char *xdg_config = xdg_config_home("config");
@@ -1206,7 +1278,23 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)
found += 1;
}
- if (repo_config && !access_or_die(repo_config, R_OK, 0)) {
+ if (worktree_config) {
+ struct config_include_data inc = CONFIG_INCLUDE_INIT;
+
+ inc.fn = fn;
+ inc.data = data;
+ if (!access_or_die(worktree_config, R_OK, 0)) {
+ ret += git_config_from_file(config_worktree_filter_in,
+ worktree_config, &inc);
+ found += 1;
+ }
+
+ if (repo_config && !access_or_die(repo_config, R_OK, 0)) {
+ ret += git_config_from_file(config_worktree_filter_out,
+ repo_config, &inc);
+ found += 1;
+ }
+ } else if (repo_config && !access_or_die(repo_config, R_OK, 0)) {
ret += git_config_from_file(fn, repo_config, data);
found += 1;
}
@@ -1232,6 +1320,7 @@ int git_config_with_options(config_fn_t fn, void *data,
int respect_includes)
{
char *repo_config = NULL;
+ char *worktree_config = NULL;
int ret;
struct config_include_data inc = CONFIG_INCLUDE_INIT;
@@ -1254,9 +1343,11 @@ int git_config_with_options(config_fn_t fn, void *data,
return git_config_from_blob_ref(fn, config_source->blob, data);
repo_config = git_pathdup("config");
- ret = git_config_early(fn, data, repo_config);
- if (repo_config)
- free(repo_config);
+ if (git_common_dir_env)
+ worktree_config = worktree_config_path();
+ ret = git_config_early(fn, data, repo_config, worktree_config);
+ free(repo_config);
+ free(worktree_config);
return ret;
}
@@ -1925,6 +2016,23 @@ int git_config_key_is_valid(const char *key)
return !git_config_parse_key_1(key, NULL, NULL, 1);
}
+static const char *get_config_filename(const char *config_filename,
+ const char *key,
+ char **filename_buf)
+{
+ if (config_filename)
+ return config_filename;
+ if (!git_common_dir_env) {
+ config_filename = *filename_buf = git_pathdup("config");
+ return config_filename;
+ }
+ if (!is_config_local(key))
+ config_filename = *filename_buf = git_pathdup("config");
+ else
+ config_filename = *filename_buf = worktree_config_path();
+ return config_filename;
+}
+
/*
* If value==NULL, unset in (remove from) config,
* if value_regex!=NULL, disregard key/value pairs where value does not match.
@@ -1968,8 +2076,7 @@ int git_config_set_multivar_in_file(const char *config_filename,
store.multi_replace = multi_replace;
- if (!config_filename)
- config_filename = filename_buf = git_pathdup("config");
+ config_filename = get_config_filename(config_filename, key, &filename_buf);
/*
* The lock serves a purpose in addition to locking: the new
diff --git a/setup.c b/setup.c
index 2f41648..9196945 100644
--- a/setup.c
+++ b/setup.c
@@ -407,7 +407,7 @@ static int check_repository_format_gently(const char *gitdir, int *nongit_ok)
* Use a gentler version of git_config() to check if this repo
* is a good one.
*/
- git_config_early(fn, NULL, repo_config);
+ git_config_early(fn, NULL, repo_config, NULL);
if (GIT_REPO_VERSION_READ < repository_format_version) {
if (!nongit_ok)
die ("Expected git repo version <= %d, found %d",
--
2.3.0.rc1.137.g477eb31
next prev parent reply other threads:[~2015-12-27 3:15 UTC|newest]
Thread overview: 53+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-12-02 19:13 [PATCH 0/5] Split .git/config in multiple worktree setup Nguyễn Thái Ngọc Duy
2015-12-02 19:13 ` [PATCH 1/5] dir.c: clean the entire struct in clear_exclude_list() Nguyễn Thái Ngọc Duy
2015-12-02 19:13 ` [PATCH 2/5] config.c: move worktree-specific variables to .git/worktrees/ Nguyễn Thái Ngọc Duy
2015-12-06 7:47 ` Eric Sunshine
2015-12-06 10:22 ` Duy Nguyen
2015-12-02 19:13 ` [PATCH 3/5] setup.c: remove special case of core.worktree and core.bare Nguyễn Thái Ngọc Duy
2015-12-02 19:13 ` [PATCH 4/5] worktree: make core.sparseCheckout and core.ignoreStat per-worktree Nguyễn Thái Ngọc Duy
2015-12-02 19:13 ` [PATCH 5/5] git-worktree.txt: mention about the config file split Nguyễn Thái Ngọc Duy
2015-12-06 8:02 ` Eric Sunshine
2015-12-03 6:15 ` [PATCH 0/5] Split .git/config in multiple worktree setup Max Kirillov
2015-12-03 8:07 ` Duy Nguyen
2015-12-03 19:52 ` Junio C Hamano
2015-12-03 21:00 ` Max Kirillov
2015-12-03 20:53 ` Max Kirillov
2015-12-04 15:57 ` Duy Nguyen
2015-12-27 3:14 ` [PATCH v2 0/6] " Nguyễn Thái Ngọc Duy
2015-12-27 3:14 ` [PATCH v2 1/6] Define new repo extension to manage multiple worktree behaviors Nguyễn Thái Ngọc Duy
2015-12-27 3:14 ` Nguyễn Thái Ngọc Duy [this message]
2015-12-27 3:14 ` [PATCH v2 3/6] setup.c: remove special case of core.worktree and core.bare Nguyễn Thái Ngọc Duy
2015-12-27 3:14 ` [PATCH v2 4/6] worktree: make core.sparseCheckout and core.ignoreStat per-worktree Nguyễn Thái Ngọc Duy
2015-12-27 3:14 ` [PATCH v2 5/6] config.c: allow to un-share certain config in multi-worktree setup Nguyễn Thái Ngọc Duy
2015-12-27 3:14 ` [PATCH v2 6/6] worktree: bump worktree version to 1 on "worktree add" Nguyễn Thái Ngọc Duy
2016-01-11 22:43 ` [PATCH v2 0/6] Split .git/config in multiple worktree setup Max Kirillov
2016-01-26 11:44 ` [PATCH v3 " Nguyễn Thái Ngọc Duy
2016-01-26 11:44 ` [PATCH v3 1/6] worktree: new repo extension to manage worktree behaviors Nguyễn Thái Ngọc Duy
2016-01-27 22:12 ` Junio C Hamano
2016-01-28 12:11 ` Duy Nguyen
2016-01-30 14:20 ` Max Kirillov
2016-01-31 16:42 ` Junio C Hamano
2016-02-01 2:41 ` Stefan Monnier
2016-02-01 2:47 ` Stefan Monnier
2016-02-01 5:23 ` Duy Nguyen
2016-02-01 18:19 ` Junio C Hamano
2016-02-04 18:12 ` git worktree (was: [PATCH v3 1/6] worktree: new repo extension to manage worktree behaviors) Stefan Monnier
2016-02-01 18:39 ` [PATCH v3 1/6] worktree: new repo extension to manage worktree behaviors Dennis Kaarsemaker
2016-01-30 13:59 ` Max Kirillov
2016-01-26 11:44 ` [PATCH v3 2/6] path.c: new (identical) list for worktree v1 Nguyễn Thái Ngọc Duy
2016-01-27 22:18 ` Junio C Hamano
2016-01-30 14:45 ` Max Kirillov
2016-01-26 11:44 ` [PATCH v3 3/6] worktree: share .git/common in v1 Nguyễn Thái Ngọc Duy
2016-01-26 11:44 ` [PATCH v3 4/6] worktree: new config file hierarchy Nguyễn Thái Ngọc Duy
2016-01-27 22:22 ` Junio C Hamano
2016-01-28 12:03 ` Duy Nguyen
2016-01-28 18:45 ` Junio C Hamano
2016-02-01 5:09 ` Duy Nguyen
2016-01-26 11:44 ` [PATCH v3 5/6] config: select .git/common/config with --repo Nguyễn Thái Ngọc Duy
2016-01-30 22:10 ` Max Kirillov
2016-02-01 5:15 ` Duy Nguyen
2016-01-26 11:44 ` [PATCH v3 6/6] worktree add: switch to worktree version 1 Nguyễn Thái Ngọc Duy
2016-02-01 5:33 ` Max Kirillov
2016-02-01 6:05 ` Duy Nguyen
2016-02-02 5:35 ` Max Kirillov
2016-01-27 22:23 ` [PATCH v3 0/6] Split .git/config in multiple worktree setup Junio C Hamano
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1451186079-6119-3-git-send-email-pclouds@gmail.com \
--to=pclouds@gmail.com \
--cc=Jens.Lehmann@web.de \
--cc=git@drmicha.warpmail.net \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=max@max630.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).