[PATCH v6 06/10] submodule--helper: add gitdir migration command
- From
Adrian Ratiu <adrian.ratiu@collabora.com>
- Date
- Dec 13, 2025, 08:08 UTC
- Message-ID
- <20251213080817.347922-7-adrian.ratiu@collabora.com>
- In-Reply-To
- <20251213080817.347922-1-adrian.ratiu@collabora.com>
Manually running "git config submodule.<name>.gitdir .git/modules/<name>" for each submodule can be impractical, so add a migration command to submodule--helper to automatically create configs for all submodules as required by extensions.submodulePathConfig.
The command calls create_default_gitdir_config() which validates the gitdir paths before adding the configs.
Suggested-by: Junio C Hamano <gitster@pobox.com> Suggested-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com> --- Documentation/config/extensions.adoc | 6 ++- builtin/submodule--helper.c | 58 ++++++++++++++++++++++ t/t7425-submodule-gitdir-path-extension.sh | 34 +++++++++++++ 3 files changed, 96 insertions(+), 2 deletions(-)
diff --git a/Documentation/config/extensions.adoc b/Documentation/config/extensions.adoc index 929e4e1bf1..63c8727c3b 100644 --- a/Documentation/config/extensions.adoc +++ b/Documentation/config/extensions.adoc @@ -80,8 +80,10 @@ submodulePathConfig::: This extension can also be enabled as a global runtime config, with the local repository config having precedence (overwrites it). Existing pre-extension submodules need to be migrated by adding the - missing config entries. This is done manually for now, e.g. for each - submodule: "git config submodule.<name>.gitdir .git/modules/<name>". + missing config entries. This can be done manually, e.g. for each + submodule: "git config submodule.<name>.gitdir .git/modules/<name>", + or via the "git submodule--helper migrate-gitdir-configs" command + which iterates over all submodules and attempts to migrate them. worktreeConfig::: If enabled, then worktrees will load config settings from the diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c index 2b5b4f575b..458dc863df 100644 --- a/builtin/submodule--helper.c +++ b/builtin/submodule--helper.c @@ -1270,6 +1270,63 @@ static int module_gitdir(int argc, const char **argv, const char *prefix UNUSED, return 0; } +static int module_migrate(int argc UNUSED, const char **argv UNUSED, + const char *prefix UNUSED, struct repository *repo) +{ + struct strbuf module_dir = STRBUF_INIT; + DIR *dir; + struct dirent *de; + + if (repo_config_set_gently(repo, "core.repositoryformatversion", "1")) + die(_("could not set core.repositoryformatversion to 1. " + "Please enable it for migration to work, for example: " + "git config core.repositoryformatversion 1")); + + if (repo_config_set_gently(repo, "extensions.submodulePathConfig", "true")) + die(_("could not enable submodulePathConfig extension. It is required " + "for migration to work. Please enable it in the root repo: " + "git config extensions.submodulePathConfig true")); + + repo->repository_format_submodule_path_cfg = 1; + + repo_git_path_append(repo, &module_dir, "modules/"); + + dir = opendir(module_dir.buf); + if (!dir) + die(_("could not open '%s'"), module_dir.buf); + + while ((de = readdir(dir))) { + struct strbuf gitdir_path = STRBUF_INIT; + char *key; + const char *value; + + if (is_dot_or_dotdot(de->d_name)) + continue; + + strbuf_addf(&gitdir_path, "%s/%s", module_dir.buf, de->d_name); + if (!is_git_directory(gitdir_path.buf)) { + strbuf_release(&gitdir_path); + continue; + } + strbuf_release(&gitdir_path); + + key = xstrfmt("submodule.%s.gitdir", de->d_name); + if (!repo_config_get_string_tmp(repo, key, &value)) { + /* Already has a gitdir config, nothing to do. */ + free(key); + continue; + } + free(key); + + create_default_gitdir_config(de->d_name); + } + + closedir(dir); + strbuf_release(&module_dir); + + return 0; +} + struct sync_cb { const char *prefix; const char *super_prefix; @@ -3654,6 +3711,7 @@ int cmd_submodule__helper(int argc, NULL }; struct option options[] = { + OPT_SUBCOMMAND("migrate-gitdir-configs", &fn, module_migrate), OPT_SUBCOMMAND("gitdir", &fn, module_gitdir), OPT_SUBCOMMAND("clone", &fn, module_clone), OPT_SUBCOMMAND("add", &fn, module_add), diff --git a/t/t7425-submodule-gitdir-path-extension.sh b/t/t7425-submodule-gitdir-path-extension.sh index 2f198bff82..b7f0e8cdf4 100755 --- a/t/t7425-submodule-gitdir-path-extension.sh +++ b/t/t7425-submodule-gitdir-path-extension.sh @@ -181,4 +181,38 @@ test_expect_success 'runtime config extensions.submodulePathConfig on existing r ) ' +test_expect_success 'submodule--helper migrates legacy modules' ' + git init sm-repo-1 && + test_commit -C sm-repo-1 initial-1 && + git init sm-repo-2 && + test_commit -C sm-repo-2 initial-2 && + + # ensure the global config is disabled so we can actually test migration + git config --global extensions.submodulePathConfig false && + + git init -b main migrate-test && + ( + cd migrate-test && + + git submodule add ../sm-repo-1 sub1 && + git submodule add ../sm-repo-2 sub2 && + test_commit add-submodules && + + # gitdir configs should not exist + test_must_fail git config submodule.sub1.gitdir && + test_must_fail git config submodule.sub2.gitdir && + + git submodule--helper migrate-gitdir-configs && + + # gitdir configs must exist after migration + 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 + ) +' + test_done
-- 2.51.2