When the .gitmodules file is not available in the working tree, try using HEAD:.gitmodules from the current branch. This covers the case when the file is part of the repository but for some reason it is not checked out, for example because of a sparse checkout. This makes it possible to use at least the 'git submodule' commands which *read* the gitmodules configuration file without fully populating the working tree. Writing to .gitmodules will still require that the file is checked out, so check for that before calling config_set_in_gitmodules_file_gently. Signed-off-by: Antonio Ospite <ao2@xxxxxx> --- builtin/submodule--helper.c | 17 ++++++++++++++++- cache.h | 1 + submodule-config.c | 16 ++++++++++++++-- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c index c388f4ee6f..616d5de0a9 100644 --- a/builtin/submodule--helper.c +++ b/builtin/submodule--helper.c @@ -2089,8 +2089,23 @@ static int module_config(int argc, const char **argv, const char *prefix) return print_config_from_gitmodules(argv[1]); /* Equivalent to ACTION_SET in builtin/config.c */ - if (argc == 3) + if (argc == 3) { + struct object_id oid; + + /* + * If the .gitmodules file is not in the working tree but it + * is in the current branch, stop, as writing new values and + * staging them would blindly overwrite ALL the old content. + * + * This still makes it possible to create a brand new + * .gitmodules when neither GITMODULES_FILE nor + * GITMODULES_HEAD exist. + */ + if (!file_exists(GITMODULES_FILE) && get_oid(GITMODULES_HEAD, &oid) >= 0) + die(_("please make sure that the .gitmodules file in the current branch is checked out")); + return config_set_in_gitmodules_file_gently(argv[1], argv[2]); + } return 0; } diff --git a/cache.h b/cache.h index 8b447652a7..8f75cafbb6 100644 --- a/cache.h +++ b/cache.h @@ -424,6 +424,7 @@ static inline enum object_type object_type(unsigned int mode) #define INFOATTRIBUTES_FILE "info/attributes" #define ATTRIBUTE_MACRO_PREFIX "[attr]" #define GITMODULES_FILE ".gitmodules" +#define GITMODULES_HEAD "HEAD:.gitmodules" #define GIT_NOTES_REF_ENVIRONMENT "GIT_NOTES_REF" #define GIT_NOTES_DEFAULT_REF "refs/notes/commits" #define GIT_NOTES_DISPLAY_REF_ENVIRONMENT "GIT_NOTES_DISPLAY_REF" diff --git a/submodule-config.c b/submodule-config.c index 702d40dd6b..cf08264220 100644 --- a/submodule-config.c +++ b/submodule-config.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "dir.h" #include "repository.h" #include "config.h" #include "submodule-config.h" @@ -603,8 +604,19 @@ static void submodule_cache_check_init(struct repository *repo) static void config_from_gitmodules(config_fn_t fn, struct repository *repo, void *data) { if (repo->worktree) { - char *file = repo_worktree_path(repo, GITMODULES_FILE); - git_config_from_file(fn, file, data); + struct git_config_source config_source = { 0 }; + const struct config_options opts = { 0 }; + struct object_id oid; + char *file; + + file = repo_worktree_path(repo, GITMODULES_FILE); + if (file_exists(file)) + config_source.file = file; + else if (get_oid(GITMODULES_HEAD, &oid) >= 0) + config_source.blob = GITMODULES_HEAD; + + config_with_options(fn, data, &config_source, &opts); + free(file); } } -- 2.18.0