Re: [PATCH v4 4/6] config: correctly read worktree configs in submodules
From: Jonathan Nieder <hidden>
Date: 2020-09-01 02:41:36
Hi, Matheus Tavares wrote:
One of the steps in do_git_config_sequence() is to load the worktree-specific config file. Although the function receives a git_dir string, it relies on git_pathdup(), which uses the_repository->git_dir, to make the path to the file. Furthermore, it also checks that extensions.worktreeConfig is set through the repository_format_worktree_config variable, which refers to the_repository only. Thus, when a submodule has worktree-specific settings, a command executed in the superproject that recurses into the submodule won't find the said settings.
I think the above goes out of order: it states the "how" before the "what". Instead, a commit message should lead with the problem the change aims to solve. Is the idea here that until this patch, we're only able to read worktree config from a repository when extensions.worktreeConfig is set in the_repository, meaning that - when examining submodule config in a process where the_repository represents the superproject, we do not read the submodule's worktree config even if extensions.worktreeConfig is set in the submodule, unless the superproject has extensions.worktreeConfig set, and - when examining submodule config in a process where the_repository represents the superproject, we *do* read the submodule's worktree config even if extensions.worktreeConfig is not set in the submodule, if the superproject has extensions.worktreeConfig set, and ? That sounds like a serious problem indeed. Thanks for fixing it.
This will be especially important in the next patch: git-grep will learn to honor sparse checkouts and, when running with --recurse-submodules, the submodule's sparse checkout settings must be loaded. As these settings are stored in the config.worktree file, they would be ignored without this patch. So let's fix this by reading the right config.worktree file and extensions.worktreeConfig setting, based on the git_dir and commondir paths given to do_git_config_sequence(). Also add a test to avoid any regressions.
I see. I'm not sure that's more important than other cases, but I can understand if the problem was noticed in this circumstance. :)
quoted hunk ↗ jump to hunk
Signed-off-by: Matheus Tavares <redacted> --- config.c | 21 +++++++++--- t/helper/test-config.c | 67 +++++++++++++++++++++++++++++++++----- t/t2404-worktree-config.sh | 16 +++++++++ 3 files changed, 91 insertions(+), 13 deletions(-)diff --git a/config.c b/config.c index 8db9c77098..c2d56309dc 100644 --- a/config.c +++ b/config.c@@ -1747,11 +1747,22 @@ static int do_git_config_sequence(const struct config_options *opts, ret += git_config_from_file(fn, repo_config, data); current_parsing_scope = CONFIG_SCOPE_WORKTREE; - if (!opts->ignore_worktree && repository_format_worktree_config) { + if (!opts->ignore_worktree && repo_config && opts->git_dir) {
Can we eliminate the repository_format_worktree_config global to save the next caller from the same problem?
+ struct repository_format repo_fmt = REPOSITORY_FORMAT_INIT;
+ struct strbuf buf = STRBUF_INIT;
+
+ read_repository_format(&repo_fmt, repo_config);
+
+ if (!verify_repository_format(&repo_fmt, &buf) &&
+ repo_fmt.worktree_config) {This undoes the caching the repository_format_worktree_config means to do. Can we cache the value in "struct repository" instead? That way, in the common case where we're reading the_repository, we wouldn't experience a slowdown.
- char *path = git_pathdup("config.worktree");
+ char *path = mkpathdup("%s/config.worktree", opts->git_dir);Can this use a helper like repo_git_path or strbuf_repo_git_path (preferably one using strbuf like the latter)? [...]
quoted hunk ↗ jump to hunk
+ strbuf_release(&buf); + clear_repository_format(&repo_fmt); } current_parsing_scope = CONFIG_SCOPE_COMMAND;diff --git a/t/helper/test-config.c b/t/helper/test-config.c index 61da2574c5..284f83a921 100644 --- a/t/helper/test-config.c +++ b/t/helper/test-config.c@@ -2,12 +2,19 @@ #include "cache.h" #include "config.h" #include "string-list.h" +#include "submodule-config.h" /* * This program exposes the C API of the configuration mechanism * as a set of simple commands in order to facilitate testing. * - * Reads stdin and prints result of command to stdout: + * Usage: test-tool config [--submodule=<path>] <cmd> [<args>] + * + * If --submodule=<path> is given, <cmd> will operate on the submodule at the + * given <path>. This option is not valid for the commands: read_early_config, + * configset_get_value and configset_get_value_multi.
Nice! [...]
quoted hunk ↗ jump to hunk
@@ -93,7 +102,18 @@ int cmd__config(int argc, const char **argv) if (argc == 0) goto print_usage_error; + if (skip_prefix(*argv, "--submodule=", &subrepo_path)) { + argc--; + argv++; + if (argc == 0) + goto print_usage_error; + }
Can this use the parse_options API?
+
if (argc == 2 && !strcmp(argv[0], "read_early_config")) {
+ if (subrepo_path) {
+ fprintf(stderr, "Cannot use --submodule with read_early_config\n");
+ return TC_USAGE_ERROR;Should this use die() or BUG()?
quoted hunk ↗ jump to hunk
+ } read_early_config(early_config_cb, (void *)argv[1]); return TC_SUCCESS; }@@ -101,8 +121,23 @@ int cmd__config(int argc, const char **argv) setup_git_directory(); git_configset_init(&cs); + if (subrepo_path) { + const struct submodule *sub; + struct repository *subrepo = xcalloc(1, sizeof(*repo));
nit: this could be scoped to cmd__config:
struct repository subrepo = {0};
+
+ sub = submodule_from_path(the_repository, &null_oid, subrepo_path);
+ if (!sub || repo_submodule_init(subrepo, the_repository, sub)) {
+ fprintf(stderr, "Invalid argument to --submodule: '%s'\n",
+ subrepo_path);
+ free(subrepo);
+ ret = TC_USAGE_ERROR;Likewise: I think may want to use die() or BUG() (and likewise for other USAGE_ERROR cases). Thanks and hope that helps, Jonathan