From: "Yoichi NAKAYAMA via GitGitGadget" <gitgitgadget@gmail.com>
To: git@vger.kernel.org
Cc: Yoichi NAKAYAMA <yoichi.nakayama@gmail.com>,
Yoichi NAKAYAMA <yoichi.nakayama@gmail.com>
Subject: [PATCH 3/3] submodule init: copy submodule.<name>.gitdir to config.worktree
Date: Thu, 12 Nov 2026 12:03:05 +0000 [thread overview]
Message-ID: <cdf089b6355440e6515723a47aacbcc1605ab3f0.1794484985.git.gitgitgadget@gmail.com> (raw)
In-Reply-To: <pull.2306.git.1794484985.gitgitgadget@gmail.com>
From: Yoichi NAKAYAMA <yoichi.nakayama@gmail.com>
If a repository already has gitdir settings in its repository config
when extensions.worktreeConfig is enabled, those settings belong to a
particular worktree. Make 'git submodule init' copy an existing
setting to the worktree config if it belongs to the current worktree;
otherwise, generate a new setting.
Signed-off-by: Yoichi NAKAYAMA <yoichi.nakayama@gmail.com>
---
builtin/submodule--helper.c | 100 ++++++++++++++++++---
t/t7425-submodule-gitdir-path-extension.sh | 65 +++++++++++++-
2 files changed, 151 insertions(+), 14 deletions(-)
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index f249582ca6..f34a22238f 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -480,10 +480,41 @@ struct init_cb {
};
#define INIT_CB_INIT { 0 }
+static int validate_submodule_git_dir_with_worktree(const char *gitdir)
+{
+ struct strbuf tmp = STRBUF_INIT;
+ struct strbuf submodule = STRBUF_INIT;
+ char *super;
+ int ret = 1;
+
+ if (is_absolute_path(gitdir))
+ strbuf_addstr(&submodule, gitdir);
+ else if (!repo_worktree_path_append(the_repository, &submodule,
+ "%s", gitdir))
+ return -1;
+
+ if (strbuf_normalize_path(&submodule)) {
+ strbuf_release(&submodule);
+ return -1;
+ }
+
+ super = absolute_pathdup(repo_get_git_dir(the_repository));
+
+ if (starts_with(relative_path(submodule.buf, super, &tmp), "modules/"))
+ ret = 0;
+
+ strbuf_release(&submodule);
+ strbuf_release(&tmp);
+ free(super);
+ return ret;
+}
+
static int validate_and_set_submodule_gitdir(struct strbuf *gitdir_path,
- const char *submodule_name)
+ const char *submodule_name,
+ struct worktree *wt)
{
- const char *value;
+ const char *value = gitdir_path->buf;
+ char *value_to_free = NULL;
char *key;
if (validate_submodule_git_dir(gitdir_path->buf, submodule_name))
@@ -491,18 +522,55 @@ static int validate_and_set_submodule_gitdir(struct strbuf *gitdir_path,
key = xstrfmt("submodule.%s.gitdir", submodule_name);
- /* Nothing to do if the config already exists. */
- if (!repo_config_get_string_tmp(the_repository, key, &value)) {
- free(key);
- return 0;
+ if (the_repository->repository_format_worktree_config) {
+ struct config_set cs = { 0 };
+ const char *filename = worktree_git_path(wt, "config.worktree");
+ char *tmp;
+
+ git_configset_init(&cs);
+ git_configset_add_file(&cs, filename);
+
+ /*
+ * Nothing to do if the config already exists in the config set
+ * for the current worktree.
+ */
+ if (!git_configset_get(&cs, key)) {
+ git_configset_clear(&cs);
+ free(key);
+ return 0;
+ }
+
+ git_configset_clear(&cs);
+
+ /*
+ * If the worktree config does not have this key, check the
+ * effective value from lower-priority config scopes and copy
+ * it to the worktree config if it belongs to the current
+ * worktree.
+ */
+ if (!repo_config_get_string(the_repository, key, &tmp)) {
+ if (validate_submodule_git_dir_with_worktree(tmp) ||
+ validate_submodule_git_dir(tmp, submodule_name))
+ free(tmp);
+ else
+ value = value_to_free = tmp;
+ }
+ } else {
+ /* Nothing to do if the config already exists. */
+ if (!repo_config_get_string_tmp(the_repository, key, &value)) {
+ free(key);
+ return 0;
+ }
}
- if (repo_config_set_worktree_gently(the_repository, key, gitdir_path->buf)) {
+ if (repo_config_set_worktree_gently(the_repository, key, value)) {
free(key);
+ free(value_to_free);
return -1;
}
free(key);
+ free(value_to_free);
return 0;
}
@@ -526,7 +594,8 @@ static void create_default_gitdir_config(const char *submodule_name)
strbuf_addstr(&gitdir_path, modules_dir);
strbuf_addstr(&gitdir_path, submodule_name);
if (!validate_and_set_submodule_gitdir(&gitdir_path,
- submodule_name))
+ submodule_name,
+ wt))
goto cleanup;
/* Case 2.1: Try URI-safe (RFC3986) encoding first, this fixes nested gitdirs */
@@ -534,7 +603,8 @@ static void create_default_gitdir_config(const char *submodule_name)
strbuf_addstr(&gitdir_path, modules_dir);
strbuf_addstr_urlencode(&gitdir_path, submodule_name, is_rfc3986_unreserved);
if (!validate_and_set_submodule_gitdir(&gitdir_path,
- submodule_name))
+ submodule_name,
+ wt))
goto cleanup;
/* Case 2.2: Try extended uppercase URI (RFC3986) encoding, to fix case-folding */
@@ -542,7 +612,8 @@ static void create_default_gitdir_config(const char *submodule_name)
strbuf_addstr(&gitdir_path, modules_dir);
strbuf_addstr_urlencode(&gitdir_path, submodule_name, is_casefolding_rfc3986_unreserved);
if (!validate_and_set_submodule_gitdir(&gitdir_path,
- submodule_name))
+ submodule_name,
+ wt))
goto cleanup;
/* Case 2.3: Try some derived gitdir names, see if one sticks */
@@ -552,7 +623,8 @@ static void create_default_gitdir_config(const char *submodule_name)
strbuf_addstr_urlencode(&gitdir_path, submodule_name, is_rfc3986_unreserved);
strbuf_addch(&gitdir_path, c);
if (!validate_and_set_submodule_gitdir(&gitdir_path,
- submodule_name))
+ submodule_name,
+ wt))
goto cleanup;
strbuf_reset(&gitdir_path);
@@ -560,7 +632,8 @@ static void create_default_gitdir_config(const char *submodule_name)
strbuf_addstr_urlencode(&gitdir_path, submodule_name, is_casefolding_rfc3986_unreserved);
strbuf_addch(&gitdir_path, c);
if (!validate_and_set_submodule_gitdir(&gitdir_path,
- submodule_name))
+ submodule_name,
+ wt))
goto cleanup;
}
@@ -577,7 +650,8 @@ static void create_default_gitdir_config(const char *submodule_name)
strbuf_addstr(&gitdir_path, modules_dir);
strbuf_addstr(&gitdir_path, hex_name_hash);
if (!validate_and_set_submodule_gitdir(&gitdir_path,
- submodule_name))
+ submodule_name,
+ wt))
goto cleanup;
/* Case 3: nothing worked, error out */
diff --git a/t/t7425-submodule-gitdir-path-extension.sh b/t/t7425-submodule-gitdir-path-extension.sh
index 3bae4c4ef1..36aac0f578 100755
--- a/t/t7425-submodule-gitdir-path-extension.sh
+++ b/t/t7425-submodule-gitdir-path-extension.sh
@@ -328,7 +328,47 @@ test_expect_success '`git clone --recurse-submodules` respects init.defaultSubmo
)
'
-test_expect_success 'git submodule init make gitdir relative' '
+test_expect_success 'git submodule init inherits related repository config for main' '
+ test_when_finished "rm -rf repo-clone-init-main" &&
+ git clone upstream repo-clone-init-main &&
+ (
+ cd repo-clone-init-main &&
+ git config core.repositoryformatversion 1 &&
+ git config extensions.submodulePathConfig true &&
+ git submodule init &&
+ git config submodule.sub1.gitdir >actual &&
+ echo ".git/modules/sub1" >expect &&
+ test_cmp expect actual &&
+ git config submodule.sub2.gitdir >actual &&
+ echo ".git/modules/sub2" >expect &&
+ test_cmp expect actual &&
+
+ # Modify values so that they can be distinguished from the default
+ git config submodule.sub1.gitdir .git/modules/sub1_custom &&
+ git config submodule.sub2.gitdir .git/modules/sub2_custom &&
+
+ git config extensions.worktreeConfig true &&
+ git submodule init &&
+ git config --worktree submodule.sub1.gitdir >actual &&
+ echo ".git/modules/sub1_custom" >expect &&
+ test_cmp expect actual &&
+ git config --worktree submodule.sub2.gitdir >actual &&
+ echo ".git/modules/sub2_custom" >expect &&
+ test_cmp expect actual &&
+
+ git worktree add wt &&
+ cd wt &&
+ git submodule init &&
+ git config --worktree submodule.sub1.gitdir >actual &&
+ echo "../.git/worktrees/wt/modules/sub1" >expect &&
+ test_cmp expect actual &&
+ git config --worktree submodule.sub2.gitdir >actual &&
+ echo "../.git/worktrees/wt/modules/sub2" >expect &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'git submodule init inherits related repository config for worktree' '
test_when_finished "rm -rf repo-clone-init-wt" &&
git clone upstream repo-clone-init-wt &&
(
@@ -343,6 +383,29 @@ test_expect_success 'git submodule init make gitdir relative' '
test_cmp expect actual &&
git config submodule.sub2.gitdir >actual &&
echo "../.git/worktrees/wt/modules/sub2" >expect &&
+ test_cmp expect actual &&
+
+ # Modify values so that they can be distinguished from the default
+ git config submodule.sub1.gitdir ../.git/worktrees/wt/modules/sub1_custom &&
+ # Use an absolute path to simulate a value written by older Git
+ git config submodule.sub2.gitdir "$(cd .. && pwd -P)/.git/worktrees/wt/modules/sub2_custom" &&
+
+ git config extensions.worktreeConfig true &&
+ git submodule init &&
+ git config --worktree submodule.sub1.gitdir >actual &&
+ echo "../.git/worktrees/wt/modules/sub1_custom" >expect &&
+ test_cmp expect actual &&
+ git config --worktree submodule.sub2.gitdir >actual &&
+ echo "$(cd .. && pwd -P)/.git/worktrees/wt/modules/sub2_custom" >expect &&
+ test_cmp expect actual &&
+
+ cd .. &&
+ git submodule init &&
+ git config --worktree submodule.sub1.gitdir >actual &&
+ echo ".git/modules/sub1" >expect &&
+ test_cmp expect actual &&
+ git config --worktree submodule.sub2.gitdir >actual &&
+ echo ".git/modules/sub2" >expect &&
test_cmp expect actual
)
'
--
gitgitgadget
prev parent reply other threads:[~2026-11-12 12:03 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-12 12:03 [PATCH 0/3] submodule: support worktree-specific configuration Yoichi NAKAYAMA via GitGitGadget
2026-11-12 12:03 ` [PATCH 1/3] submodule: make submodule.<name>.gitdir relative for worktrees Yoichi NAKAYAMA via GitGitGadget
2026-11-12 12:03 ` [PATCH 2/3] submodule: store settings in worktree config when enabled Yoichi NAKAYAMA via GitGitGadget
2026-11-12 12:03 ` Yoichi NAKAYAMA via GitGitGadget [this message]
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=cdf089b6355440e6515723a47aacbcc1605ab3f0.1794484985.git.gitgitgadget@gmail.com \
--to=gitgitgadget@gmail.com \
--cc=git@vger.kernel.org \
--cc=yoichi.nakayama@gmail.com \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.