From 61aad92b852278afc6364f9ab4c33c3740fb9e66 Mon Sep 17 00:00:00 2001 From: Stefan Beller Date: Wed, 28 Mar 2018 15:35:26 -0700 Subject: submodule.h: drop declaration of connect_work_tree_and_git_dir The function connect_work_tree_and_git_dir is declared in both submodule.h and dir.h, such that one of them is redundant. As the function is implemented in dir.c, drop the declaration from submodule.h Signed-off-by: Stefan Beller Reviewed-by: Jonathan Tan Signed-off-by: Junio C Hamano --- submodule.h | 1 - 1 file changed, 1 deletion(-) diff --git a/submodule.h b/submodule.h index b9b7ef0030..b6130e6287 100644 --- a/submodule.h +++ b/submodule.h @@ -105,7 +105,6 @@ extern int push_unpushed_submodules(struct oid_array *commits, const char **refspec, int refspec_nr, const struct string_list *push_options, int dry_run); -extern void connect_work_tree_and_git_dir(const char *work_tree, const char *git_dir); /* * Given a submodule path (as in the index), return the repository * path of that submodule in 'buf'. Return -1 on error or when the -- cgit v1.2.3 From 6856077ab063f16b4ccacff971c3ebb185935465 Mon Sep 17 00:00:00 2001 From: Jonathan Tan Date: Wed, 28 Mar 2018 15:35:27 -0700 Subject: grep: remove "repo" arg from non-supporting funcs As part of commit f9ee2fcdfa ("grep: recurse in-process using 'struct repository'", 2017-08-02), many functions in builtin/grep.c were converted to also take "struct repository *" arguments. Among them were grep_object() and grep_objects(). However, at least grep_objects() was converted incompletely - it calls gitmodules_config_oid(), which references the_repository. But it turns out that the conversion was extraneous anyway - there has been no user-visible effect - because grep_objects() is never invoked except with the_repository. This is because grepping through objects cannot be done recursively into submodules. Revert the changes to grep_objects() and grep_object() (which conversion is also extraneous) to show that both these functions do not support repositories other than the_repository. Signed-off-by: Jonathan Tan Signed-off-by: Stefan Beller Reviewed-by: Jonathan Tan Signed-off-by: Junio C Hamano --- builtin/grep.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/builtin/grep.c b/builtin/grep.c index 1e9cdbdf78..754eb6da3b 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -595,8 +595,7 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec, } static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec, - struct object *obj, const char *name, const char *path, - struct repository *repo) + struct object *obj, const char *name, const char *path) { if (obj->type == OBJ_BLOB) return grep_oid(opt, &obj->oid, name, 0, path); @@ -623,7 +622,7 @@ static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec, } init_tree_desc(&tree, data, size); hit = grep_tree(opt, pathspec, &tree, &base, base.len, - obj->type == OBJ_COMMIT, repo); + obj->type == OBJ_COMMIT, the_repository); strbuf_release(&base); free(data); return hit; @@ -632,7 +631,6 @@ static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec, } static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec, - struct repository *repo, const struct object_array *list) { unsigned int i; @@ -648,8 +646,8 @@ static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec, submodule_free(); gitmodules_config_oid(&real_obj->oid); } - if (grep_object(opt, pathspec, real_obj, list->objects[i].name, list->objects[i].path, - repo)) { + if (grep_object(opt, pathspec, real_obj, list->objects[i].name, + list->objects[i].path)) { hit = 1; if (opt->status_only) break; @@ -1098,7 +1096,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) if (cached) die(_("both --cached and trees are given.")); - hit = grep_objects(&opt, &pathspec, the_repository, &list); + hit = grep_objects(&opt, &pathspec, &list); } if (num_threads) -- cgit v1.2.3 From f793b895fd752e37301702eaff948a40e7c0a4b8 Mon Sep 17 00:00:00 2001 From: Stefan Beller Date: Wed, 28 Mar 2018 15:35:28 -0700 Subject: submodule-config: allow submodule_free to handle arbitrary repositories At some point we may want to rename the function so that it describes what it actually does as 'submodule_free' doesn't quite describe that this clears a repository's submodule cache. But that's beyond the scope of this series. While at it remove the extern key word from its declaration. Signed-off-by: Stefan Beller Reviewed-by: Jonathan Tan Signed-off-by: Junio C Hamano --- Documentation/technical/api-submodule-config.txt | 2 +- builtin/grep.c | 2 +- submodule-config.c | 6 +++--- submodule-config.h | 2 +- t/helper/test-submodule-config.c | 2 +- unpack-trees.c | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Documentation/technical/api-submodule-config.txt b/Documentation/technical/api-submodule-config.txt index 3dce003fda..44a85bbb8b 100644 --- a/Documentation/technical/api-submodule-config.txt +++ b/Documentation/technical/api-submodule-config.txt @@ -38,7 +38,7 @@ Data Structures Functions --------- -`void submodule_free()`:: +`void submodule_free(struct repository *r)`:: Use these to free the internally cached values. diff --git a/builtin/grep.c b/builtin/grep.c index 754eb6da3b..c1f22fb9fb 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -643,7 +643,7 @@ static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec, /* load the gitmodules file for this rev */ if (recurse_submodules) { - submodule_free(); + submodule_free(the_repository); gitmodules_config_oid(&real_obj->oid); } if (grep_object(opt, pathspec, real_obj, list->objects[i].name, diff --git a/submodule-config.c b/submodule-config.c index 2aa8a1747f..5b4f0baae8 100644 --- a/submodule-config.c +++ b/submodule-config.c @@ -642,8 +642,8 @@ const struct submodule *submodule_from_cache(struct repository *repo, key, lookup_path); } -void submodule_free(void) +void submodule_free(struct repository *r) { - if (the_repository->submodule_cache) - submodule_cache_clear(the_repository->submodule_cache); + if (r->submodule_cache) + submodule_cache_clear(r->submodule_cache); } diff --git a/submodule-config.h b/submodule-config.h index a5503a5d17..6b71a8cd30 100644 --- a/submodule-config.h +++ b/submodule-config.h @@ -46,6 +46,6 @@ extern const struct submodule *submodule_from_path( extern const struct submodule *submodule_from_cache(struct repository *repo, const struct object_id *treeish_name, const char *key); -extern void submodule_free(void); +void submodule_free(struct repository *r); #endif /* SUBMODULE_CONFIG_H */ diff --git a/t/helper/test-submodule-config.c b/t/helper/test-submodule-config.c index f23db3b19a..9971c5e9dd 100644 --- a/t/helper/test-submodule-config.c +++ b/t/helper/test-submodule-config.c @@ -64,7 +64,7 @@ int cmd_main(int argc, const char **argv) arg += 2; } - submodule_free(); + submodule_free(the_repository); return 0; } diff --git a/unpack-trees.c b/unpack-trees.c index e6a15bbe44..3a6a28e794 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -290,7 +290,7 @@ static void load_gitmodules_file(struct index_state *index, if (!state && ce->ce_flags & CE_WT_REMOVE) { repo_read_gitmodules(the_repository); } else if (state && (ce->ce_flags & CE_UPDATE)) { - submodule_free(); + submodule_free(the_repository); checkout_entry(ce, state, NULL); repo_read_gitmodules(the_repository); } -- cgit v1.2.3 From 3b8fb393bc32f8d96c2eb4c89349c864e5c56039 Mon Sep 17 00:00:00 2001 From: Stefan Beller Date: Wed, 28 Mar 2018 15:35:29 -0700 Subject: submodule-config: add repository argument to submodule_from_{name, path} This enables submodule_from_{name, path} to handle arbitrary repositories. All callers just pass in the_repository, a later patch will pass in other repos. While at it remove the extern key word from the declarations. Reviewed-by: Jonathan Tan Signed-off-by: Stefan Beller Reviewed-by: Jonathan Tan Signed-off-by: Junio C Hamano --- builtin/submodule--helper.c | 14 +++++++------- submodule-config.c | 14 ++++++++------ submodule-config.h | 10 ++++++---- submodule.c | 30 ++++++++++++++++-------------- t/helper/test-submodule-config.c | 6 ++++-- 5 files changed, 41 insertions(+), 33 deletions(-) diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c index 6d8e002be7..5551cf19c3 100644 --- a/builtin/submodule--helper.c +++ b/builtin/submodule--helper.c @@ -455,7 +455,7 @@ static void init_submodule(const char *path, const char *prefix, displaypath = get_submodule_displaypath(path, prefix); - sub = submodule_from_path(&null_oid, path); + sub = submodule_from_path(the_repository, &null_oid, path); if (!sub) die(_("No url found for submodule path '%s' in .gitmodules"), @@ -622,7 +622,7 @@ static void status_submodule(const char *path, const struct object_id *ce_oid, struct rev_info rev; int diff_files_result; - if (!submodule_from_path(&null_oid, path)) + if (!submodule_from_path(the_repository, &null_oid, path)) die(_("no submodule mapping found in .gitmodules for path '%s'"), path); @@ -742,7 +742,7 @@ static int module_name(int argc, const char **argv, const char *prefix) if (argc != 2) usage(_("git submodule--helper name ")); - sub = submodule_from_path(&null_oid, argv[1]); + sub = submodule_from_path(the_repository, &null_oid, argv[1]); if (!sub) die(_("no submodule mapping found in .gitmodules for path '%s'"), @@ -773,7 +773,7 @@ static void sync_submodule(const char *path, const char *prefix, if (!is_submodule_active(the_repository, path)) return; - sub = submodule_from_path(&null_oid, path); + sub = submodule_from_path(the_repository, &null_oid, path); if (sub && sub->url) { if (starts_with_dot_dot_slash(sub->url) || @@ -926,7 +926,7 @@ static void deinit_submodule(const char *path, const char *prefix, struct strbuf sb_config = STRBUF_INIT; char *sub_git_dir = xstrfmt("%s/.git", path); - sub = submodule_from_path(&null_oid, path); + sub = submodule_from_path(the_repository, &null_oid, path); if (!sub || !sub->name) goto cleanup; @@ -1368,7 +1368,7 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce, goto cleanup; } - sub = submodule_from_path(&null_oid, ce->name); + sub = submodule_from_path(the_repository, &null_oid, ce->name); if (suc->recursive_prefix) displaypath = relative_path(suc->recursive_prefix, @@ -1651,7 +1651,7 @@ static const char *remote_submodule_branch(const char *path) const char *branch = NULL; char *key; - sub = submodule_from_path(&null_oid, path); + sub = submodule_from_path(the_repository, &null_oid, path); if (!sub) return NULL; diff --git a/submodule-config.c b/submodule-config.c index 5b4f0baae8..0ea1e927d2 100644 --- a/submodule-config.c +++ b/submodule-config.c @@ -619,18 +619,20 @@ static void gitmodules_read_check(struct repository *repo) repo_read_gitmodules(repo); } -const struct submodule *submodule_from_name(const struct object_id *treeish_name, +const struct submodule *submodule_from_name(struct repository *r, + const struct object_id *treeish_name, const char *name) { - gitmodules_read_check(the_repository); - return config_from(the_repository->submodule_cache, treeish_name, name, lookup_name); + gitmodules_read_check(r); + return config_from(r->submodule_cache, treeish_name, name, lookup_name); } -const struct submodule *submodule_from_path(const struct object_id *treeish_name, +const struct submodule *submodule_from_path(struct repository *r, + const struct object_id *treeish_name, const char *path) { - gitmodules_read_check(the_repository); - return config_from(the_repository->submodule_cache, treeish_name, path, lookup_path); + gitmodules_read_check(r); + return config_from(r->submodule_cache, treeish_name, path, lookup_path); } const struct submodule *submodule_from_cache(struct repository *repo, diff --git a/submodule-config.h b/submodule-config.h index 6b71a8cd30..43dfe7dec0 100644 --- a/submodule-config.h +++ b/submodule-config.h @@ -39,10 +39,12 @@ extern int parse_update_recurse_submodules_arg(const char *opt, const char *arg) extern int parse_push_recurse_submodules_arg(const char *opt, const char *arg); extern void repo_read_gitmodules(struct repository *repo); extern void gitmodules_config_oid(const struct object_id *commit_oid); -extern const struct submodule *submodule_from_name( - const struct object_id *commit_or_tree, const char *name); -extern const struct submodule *submodule_from_path( - const struct object_id *commit_or_tree, const char *path); +const struct submodule *submodule_from_name(struct repository *r, + const struct object_id *commit_or_tree, + const char *name); +const struct submodule *submodule_from_path(struct repository *r, + const struct object_id *commit_or_tree, + const char *path); extern const struct submodule *submodule_from_cache(struct repository *repo, const struct object_id *treeish_name, const char *key); diff --git a/submodule.c b/submodule.c index b03e5f5045..9279cff2d7 100644 --- a/submodule.c +++ b/submodule.c @@ -96,7 +96,7 @@ int update_path_in_gitmodules(const char *oldpath, const char *newpath) if (is_gitmodules_unmerged(&the_index)) die(_("Cannot change unmerged .gitmodules, resolve merge conflicts first")); - submodule = submodule_from_path(&null_oid, oldpath); + submodule = submodule_from_path(the_repository, &null_oid, oldpath); if (!submodule || !submodule->name) { warning(_("Could not find section in .gitmodules where path=%s"), oldpath); return -1; @@ -130,7 +130,7 @@ int remove_path_from_gitmodules(const char *path) if (is_gitmodules_unmerged(&the_index)) die(_("Cannot change unmerged .gitmodules, resolve merge conflicts first")); - submodule = submodule_from_path(&null_oid, path); + submodule = submodule_from_path(the_repository, &null_oid, path); if (!submodule || !submodule->name) { warning(_("Could not find section in .gitmodules where path=%s"), path); return -1; @@ -174,7 +174,8 @@ done: void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt, const char *path) { - const struct submodule *submodule = submodule_from_path(&null_oid, path); + const struct submodule *submodule = submodule_from_path(the_repository, + &null_oid, path); if (submodule) { const char *ignore; char *key; @@ -674,7 +675,7 @@ const struct submodule *submodule_from_ce(const struct cache_entry *ce) if (!should_update_submodules()) return NULL; - return submodule_from_path(&null_oid, ce->name); + return submodule_from_path(the_repository, &null_oid, ce->name); } static struct oid_array *submodule_commits(struct string_list *submodules, @@ -731,13 +732,14 @@ static void collect_changed_submodules_cb(struct diff_queue_struct *q, if (!S_ISGITLINK(p->two->mode)) continue; - submodule = submodule_from_path(commit_oid, p->two->path); + submodule = submodule_from_path(the_repository, + commit_oid, p->two->path); if (submodule) name = submodule->name; else { name = default_name_or_path(p->two->path); /* make sure name does not collide with existing one */ - submodule = submodule_from_name(commit_oid, name); + submodule = submodule_from_name(the_repository, commit_oid, name); if (submodule) { warning("Submodule in commit %s at path: " "'%s' collides with a submodule named " @@ -945,7 +947,7 @@ int find_unpushed_submodules(struct oid_array *commits, const struct submodule *submodule; const char *path = NULL; - submodule = submodule_from_name(&null_oid, name->string); + submodule = submodule_from_name(the_repository, &null_oid, name->string); if (submodule) path = submodule->path; else @@ -1113,7 +1115,7 @@ static void calculate_changed_submodule_paths(void) const struct string_list_item *name; /* No need to check if there are no submodules configured */ - if (!submodule_from_path(NULL, NULL)) + if (!submodule_from_path(the_repository, NULL, NULL)) return; argv_array_push(&argv, "--"); /* argv[0] program name */ @@ -1134,7 +1136,7 @@ static void calculate_changed_submodule_paths(void) const struct submodule *submodule; const char *path = NULL; - submodule = submodule_from_name(&null_oid, name->string); + submodule = submodule_from_name(the_repository, &null_oid, name->string); if (submodule) path = submodule->path; else @@ -1162,7 +1164,7 @@ int submodule_touches_in_range(struct object_id *excl_oid, int ret; /* No need to check if there are no submodules configured */ - if (!submodule_from_path(NULL, NULL)) + if (!submodule_from_path(the_repository, NULL, NULL)) return 0; argv_array_push(&args, "--"); /* args[0] program name */ @@ -1604,7 +1606,7 @@ int submodule_move_head(const char *path, if (old && !is_submodule_populated_gently(path, error_code_ptr)) return 0; - sub = submodule_from_path(&null_oid, path); + sub = submodule_from_path(the_repository, &null_oid, path); if (!sub) die("BUG: could not get submodule information for '%s'", path); @@ -1886,7 +1888,7 @@ static void relocate_single_git_dir_into_superproject(const char *prefix, real_old_git_dir = real_pathdup(old_git_dir, 1); - sub = submodule_from_path(&null_oid, path); + sub = submodule_from_path(the_repository, &null_oid, path); if (!sub) die(_("could not lookup name for submodule '%s'"), path); @@ -1942,7 +1944,7 @@ void absorb_git_dir_into_superproject(const char *prefix, * superproject did not rewrite the git file links yet, * fix it now. */ - sub = submodule_from_path(&null_oid, path); + sub = submodule_from_path(the_repository, &null_oid, path); if (!sub) die(_("could not lookup name for submodule '%s'"), path); connect_work_tree_and_git_dir(path, @@ -2088,7 +2090,7 @@ int submodule_to_gitdir(struct strbuf *buf, const char *submodule) strbuf_addstr(buf, git_dir); } if (!is_git_directory(buf->buf)) { - sub = submodule_from_path(&null_oid, submodule); + sub = submodule_from_path(the_repository, &null_oid, submodule); if (!sub) { ret = -1; goto cleanup; diff --git a/t/helper/test-submodule-config.c b/t/helper/test-submodule-config.c index 9971c5e9dd..e044871cee 100644 --- a/t/helper/test-submodule-config.c +++ b/t/helper/test-submodule-config.c @@ -48,9 +48,11 @@ int cmd_main(int argc, const char **argv) die_usage(argc, argv, "Commit not found."); if (lookup_name) { - submodule = submodule_from_name(&commit_oid, path_or_name); + submodule = submodule_from_name(the_repository, + &commit_oid, path_or_name); } else - submodule = submodule_from_path(&commit_oid, path_or_name); + submodule = submodule_from_path(the_repository, + &commit_oid, path_or_name); if (!submodule) die_usage(argc, argv, "Submodule not found."); -- cgit v1.2.3 From 0c89fdd739183234f86fe2be03a0374705ed93ed Mon Sep 17 00:00:00 2001 From: Stefan Beller Date: Wed, 28 Mar 2018 15:35:30 -0700 Subject: submodule-config: remove submodule_from_cache This continues the story of bf12fcdf5e (submodule-config: store the_submodule_cache in the_repository, 2017-06-22). The previous patch taught submodule_from_path to take a repository into account, such that submodule_from_{path, cache} are the same now. Remove submodule_from_cache, migrating all its callers to submodule_from_path. Reviewed-by: Jonathan Tan Signed-off-by: Stefan Beller Reviewed-by: Jonathan Tan Signed-off-by: Junio C Hamano --- repository.c | 2 +- submodule-config.c | 9 --------- submodule-config.h | 3 --- submodule.c | 4 ++-- 4 files changed, 3 insertions(+), 15 deletions(-) diff --git a/repository.c b/repository.c index a4848c1bd0..eb5b8e9f5a 100644 --- a/repository.c +++ b/repository.c @@ -176,7 +176,7 @@ int repo_submodule_init(struct repository *submodule, struct strbuf worktree = STRBUF_INIT; int ret = 0; - sub = submodule_from_cache(superproject, &null_oid, path); + sub = submodule_from_path(superproject, &null_oid, path); if (!sub) { ret = -1; goto out; diff --git a/submodule-config.c b/submodule-config.c index 0ea1e927d2..9abe9166d5 100644 --- a/submodule-config.c +++ b/submodule-config.c @@ -635,15 +635,6 @@ const struct submodule *submodule_from_path(struct repository *r, return config_from(r->submodule_cache, treeish_name, path, lookup_path); } -const struct submodule *submodule_from_cache(struct repository *repo, - const struct object_id *treeish_name, - const char *key) -{ - gitmodules_read_check(repo); - return config_from(repo->submodule_cache, treeish_name, - key, lookup_path); -} - void submodule_free(struct repository *r) { if (r->submodule_cache) diff --git a/submodule-config.h b/submodule-config.h index 43dfe7dec0..6f686184e8 100644 --- a/submodule-config.h +++ b/submodule-config.h @@ -45,9 +45,6 @@ const struct submodule *submodule_from_name(struct repository *r, const struct submodule *submodule_from_path(struct repository *r, const struct object_id *commit_or_tree, const char *path); -extern const struct submodule *submodule_from_cache(struct repository *repo, - const struct object_id *treeish_name, - const char *key); void submodule_free(struct repository *r); #endif /* SUBMODULE_CONFIG_H */ diff --git a/submodule.c b/submodule.c index 9279cff2d7..dac73d10a7 100644 --- a/submodule.c +++ b/submodule.c @@ -231,7 +231,7 @@ int is_submodule_active(struct repository *repo, const char *path) const struct string_list *sl; const struct submodule *module; - module = submodule_from_cache(repo, &null_oid, path); + module = submodule_from_path(repo, &null_oid, path); /* early return if there isn't a path->module mapping */ if (!module) @@ -1236,7 +1236,7 @@ static int get_next_submodule(struct child_process *cp, if (!S_ISGITLINK(ce->ce_mode)) continue; - submodule = submodule_from_cache(spf->r, &null_oid, ce->name); + submodule = submodule_from_path(spf->r, &null_oid, ce->name); if (!submodule) { const char *name = default_name_or_path(ce->name); if (name) { -- cgit v1.2.3 From da62f786d2df60f3c8255cf4cbbcd9c1f9458d99 Mon Sep 17 00:00:00 2001 From: Stefan Beller Date: Wed, 28 Mar 2018 15:35:31 -0700 Subject: submodule: fixup nested submodules after moving the submodule connect_work_tree_and_git_dir is used to connect a submodule worktree with its git directory and vice versa after events that require a reconnection such as moving around the working tree. As submodules can have nested submodules themselves, we'd also want to fix the nested submodules when asked to. Add an option to recurse into the nested submodules and connect them as well. As submodules are identified by their name (which determines their git directory in relation to their superproject's git directory) internally and by their path in the working tree of the superproject, we need to make sure that the mapping of name <-> path is kept intact. We can do that in the git-mv command by writing out the gitmodules file first and then forcing a reload of the submodule config machinery. Signed-off-by: Stefan Beller Reviewed-by: Jonathan Tan Signed-off-by: Junio C Hamano --- builtin/mv.c | 6 +++-- builtin/submodule--helper.c | 3 +-- dir.c | 60 ++++++++++++++++++++++++++++++++++++++++++--- dir.h | 12 ++++++++- repository.c | 6 ++--- repository.h | 3 +++ submodule.c | 6 ++--- t/t7001-mv.sh | 2 +- 8 files changed, 83 insertions(+), 15 deletions(-) diff --git a/builtin/mv.c b/builtin/mv.c index cf3684d907..b0c5178e0d 100644 --- a/builtin/mv.c +++ b/builtin/mv.c @@ -275,10 +275,12 @@ int cmd_mv(int argc, const char **argv, const char *prefix) die_errno(_("renaming '%s' failed"), src); } if (submodule_gitfile[i]) { - if (submodule_gitfile[i] != SUBMODULE_WITH_GITDIR) - connect_work_tree_and_git_dir(dst, submodule_gitfile[i]); if (!update_path_in_gitmodules(src, dst)) gitmodules_modified = 1; + if (submodule_gitfile[i] != SUBMODULE_WITH_GITDIR) + connect_work_tree_and_git_dir(dst, + submodule_gitfile[i], + 1); } if (mode == WORKING_DIRECTORY) diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c index 5551cf19c3..ffdc51f426 100644 --- a/builtin/submodule--helper.c +++ b/builtin/submodule--helper.c @@ -1260,8 +1260,7 @@ static int module_clone(int argc, const char **argv, const char *prefix) strbuf_reset(&sb); } - /* Connect module worktree and git dir */ - connect_work_tree_and_git_dir(path, sm_gitdir); + connect_work_tree_and_git_dir(path, sm_gitdir, 0); p = git_pathdup_submodule(path, "config"); if (!p) diff --git a/dir.c b/dir.c index ce6e50d2a2..4f401b6a3c 100644 --- a/dir.c +++ b/dir.c @@ -19,6 +19,7 @@ #include "varint.h" #include "ewah/ewok.h" #include "fsmonitor.h" +#include "submodule-config.h" /* * Tells read_directory_recursive how a file or directory should be treated. @@ -2988,8 +2989,57 @@ void untracked_cache_add_to_index(struct index_state *istate, untracked_cache_invalidate_path(istate, path); } -/* Update gitfile and core.worktree setting to connect work tree and git dir */ -void connect_work_tree_and_git_dir(const char *work_tree_, const char *git_dir_) +static void connect_wt_gitdir_in_nested(const char *sub_worktree, + const char *sub_gitdir) +{ + int i; + struct repository subrepo; + struct strbuf sub_wt = STRBUF_INIT; + struct strbuf sub_gd = STRBUF_INIT; + + const struct submodule *sub; + + /* If the submodule has no working tree, we can ignore it. */ + if (repo_init(&subrepo, sub_gitdir, sub_worktree)) + return; + + if (repo_read_index(&subrepo) < 0) + die("index file corrupt in repo %s", subrepo.gitdir); + + for (i = 0; i < subrepo.index->cache_nr; i++) { + const struct cache_entry *ce = subrepo.index->cache[i]; + + if (!S_ISGITLINK(ce->ce_mode)) + continue; + + while (i + 1 < subrepo.index->cache_nr && + !strcmp(ce->name, subrepo.index->cache[i + 1]->name)) + /* + * Skip entries with the same name in different stages + * to make sure an entry is returned only once. + */ + i++; + + sub = submodule_from_path(&subrepo, &null_oid, ce->name); + if (!sub || !is_submodule_active(&subrepo, ce->name)) + /* .gitmodules broken or inactive sub */ + continue; + + strbuf_reset(&sub_wt); + strbuf_reset(&sub_gd); + strbuf_addf(&sub_wt, "%s/%s", sub_worktree, sub->path); + strbuf_addf(&sub_gd, "%s/modules/%s", sub_gitdir, sub->name); + + connect_work_tree_and_git_dir(sub_wt.buf, sub_gd.buf, 1); + } + strbuf_release(&sub_wt); + strbuf_release(&sub_gd); + repo_clear(&subrepo); +} + +void connect_work_tree_and_git_dir(const char *work_tree_, + const char *git_dir_, + int recurse_into_nested) { struct strbuf gitfile_sb = STRBUF_INIT; struct strbuf cfg_sb = STRBUF_INIT; @@ -3019,6 +3069,10 @@ void connect_work_tree_and_git_dir(const char *work_tree_, const char *git_dir_) strbuf_release(&gitfile_sb); strbuf_release(&cfg_sb); strbuf_release(&rel_path); + + if (recurse_into_nested) + connect_wt_gitdir_in_nested(work_tree, git_dir); + free(work_tree); free(git_dir); } @@ -3032,5 +3086,5 @@ void relocate_gitdir(const char *path, const char *old_git_dir, const char *new_ die_errno(_("could not migrate git directory from '%s' to '%s'"), old_git_dir, new_git_dir); - connect_work_tree_and_git_dir(path, new_git_dir); + connect_work_tree_and_git_dir(path, new_git_dir, 0); } diff --git a/dir.h b/dir.h index 11a047ba48..d2545a7685 100644 --- a/dir.h +++ b/dir.h @@ -359,7 +359,17 @@ struct untracked_cache *read_untracked_extension(const void *data, unsigned long void write_untracked_extension(struct strbuf *out, struct untracked_cache *untracked); void add_untracked_cache(struct index_state *istate); void remove_untracked_cache(struct index_state *istate); -extern void connect_work_tree_and_git_dir(const char *work_tree, const char *git_dir); + +/* + * Connect a worktree to a git directory by creating (or overwriting) a + * '.git' file containing the location of the git directory. In the git + * directory set the core.worktree setting to indicate where the worktree is. + * When `recurse_into_nested` is set, recurse into any nested submodules, + * connecting them as well. + */ +extern void connect_work_tree_and_git_dir(const char *work_tree, + const char *git_dir, + int recurse_into_nested); extern void relocate_gitdir(const char *path, const char *old_git_dir, const char *new_git_dir); diff --git a/repository.c b/repository.c index eb5b8e9f5a..beff3caa9e 100644 --- a/repository.c +++ b/repository.c @@ -135,9 +135,9 @@ static int read_and_verify_repository_format(struct repository_format *format, * Initialize 'repo' based on the provided 'gitdir'. * Return 0 upon success and a non-zero value upon failure. */ -static int repo_init(struct repository *repo, - const char *gitdir, - const char *worktree) +int repo_init(struct repository *repo, + const char *gitdir, + const char *worktree) { struct repository_format format; memset(repo, 0, sizeof(*repo)); diff --git a/repository.h b/repository.h index 09df94a472..6041367f08 100644 --- a/repository.h +++ b/repository.h @@ -97,6 +97,9 @@ extern void repo_set_gitdir(struct repository *repo, extern void repo_set_worktree(struct repository *repo, const char *path); extern void repo_set_hash_algo(struct repository *repo, int algo); extern void initialize_the_repository(void); +extern int repo_init(struct repository *r, + const char *gitdir, + const char *worktree); extern int repo_submodule_init(struct repository *submodule, struct repository *superproject, const char *path); diff --git a/submodule.c b/submodule.c index dac73d10a7..53c45e49d0 100644 --- a/submodule.c +++ b/submodule.c @@ -1625,7 +1625,7 @@ int submodule_move_head(const char *path, } else { char *gitdir = xstrfmt("%s/modules/%s", get_git_common_dir(), sub->name); - connect_work_tree_and_git_dir(path, gitdir); + connect_work_tree_and_git_dir(path, gitdir, 0); free(gitdir); /* make sure the index is clean as well */ @@ -1635,7 +1635,7 @@ int submodule_move_head(const char *path, if (old && (flags & SUBMODULE_MOVE_HEAD_FORCE)) { char *gitdir = xstrfmt("%s/modules/%s", get_git_common_dir(), sub->name); - connect_work_tree_and_git_dir(path, gitdir); + connect_work_tree_and_git_dir(path, gitdir, 1); free(gitdir); } } @@ -1948,7 +1948,7 @@ void absorb_git_dir_into_superproject(const char *prefix, if (!sub) die(_("could not lookup name for submodule '%s'"), path); connect_work_tree_and_git_dir(path, - git_path("modules/%s", sub->name)); + git_path("modules/%s", sub->name), 0); } else { /* Is it already absorbed into the superprojects git dir? */ char *real_sub_git_dir = real_pathdup(sub_git_dir, 1); diff --git a/t/t7001-mv.sh b/t/t7001-mv.sh index 6e5031f56f..bfe2c427f1 100755 --- a/t/t7001-mv.sh +++ b/t/t7001-mv.sh @@ -491,7 +491,7 @@ test_expect_success 'moving a submodule in nested directories' ' test_cmp expect actual ' -test_expect_failure 'moving nested submodules' ' +test_expect_success 'moving nested submodules' ' git commit -am "cleanup commit" && mkdir sub_nested_nested && (cd sub_nested_nested && -- cgit v1.2.3