From: Junio C Hamano Date: Tue, 8 May 2018 06:59:17 +0000 (+0900) Subject: Merge branch 'sb/submodule-move-nested' X-Git-Tag: v2.18.0-rc0~102 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/0c7ecb7c311?hp=92034a9cd5e71cf686ef66029433bdaba75027b0 Merge branch 'sb/submodule-move-nested' Moving a submodule that itself has submodule in it with "git mv" forgot to make necessary adjustment to the nested sub-submodules; now the codepath learned to recurse into the submodules. * sb/submodule-move-nested: submodule: fixup nested submodules after moving the submodule submodule-config: remove submodule_from_cache submodule-config: add repository argument to submodule_from_{name, path} submodule-config: allow submodule_free to handle arbitrary repositories grep: remove "repo" arg from non-supporting funcs submodule.h: drop declaration of connect_work_tree_and_git_dir --- diff --git a/Documentation/technical/api-submodule-config.txt b/Documentation/technical/api-submodule-config.txt index ee907c4a82..fb06089393 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 5f32d2ce84..6e7bc76785 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -602,8 +602,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); @@ -630,7 +629,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; @@ -639,7 +638,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; @@ -652,11 +650,11 @@ 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, 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; @@ -1108,7 +1106,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) diff --git a/builtin/mv.c b/builtin/mv.c index 6d141f7a53..7a63667d64 100644 --- a/builtin/mv.c +++ b/builtin/mv.c @@ -276,10 +276,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 a404df3ea4..7586f776fe 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); @@ -746,7 +746,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'"), @@ -777,7 +777,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) || @@ -930,7 +930,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; @@ -1264,8 +1264,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) @@ -1372,7 +1371,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, @@ -1655,7 +1654,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/dir.c b/dir.c index 63a917be45..be08d3d296 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. @@ -3010,8 +3011,57 @@ void untracked_cache_add_to_index(struct index_state *istate, untracked_cache_invalidate_path(istate, path, 1); } -/* 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; @@ -3041,6 +3091,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); } @@ -3054,5 +3108,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 b0758b82a2..3870193e52 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 a4848c1bd0..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)); @@ -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/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-config.c b/submodule-config.c index 3f2075764f..d87c3ff63a 100644 --- a/submodule-config.c +++ b/submodule-config.c @@ -619,31 +619,24 @@ 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, - const struct object_id *treeish_name, - const char *key) +void submodule_free(struct repository *r) { - gitmodules_read_check(repo); - return config_from(repo->submodule_cache, treeish_name, - key, lookup_path); -} - -void submodule_free(void) -{ - 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..6f686184e8 100644 --- a/submodule-config.h +++ b/submodule-config.h @@ -39,13 +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); -extern const struct submodule *submodule_from_cache(struct repository *repo, - const struct object_id *treeish_name, - const char *key); -extern void submodule_free(void); +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); +void submodule_free(struct repository *r); #endif /* SUBMODULE_CONFIG_H */ diff --git a/submodule.c b/submodule.c index 9a50168b23..74d35b2577 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 @@ static int add_submodule_odb(const char *path) 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; @@ -230,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) @@ -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 */ @@ -1234,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) { @@ -1604,7 +1606,7 @@ int submodule_move_head(const char *path, if (old_head && !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); @@ -1623,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 */ @@ -1633,7 +1635,7 @@ int submodule_move_head(const char *path, if (old_head && (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); } } @@ -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,11 +1944,11 @@ 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, - 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); @@ -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/submodule.h b/submodule.h index 9589f13127..e5526f6aaa 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 diff --git a/t/helper/test-submodule-config.c b/t/helper/test-submodule-config.c index 5c6e4b010d..e2692746df 100644 --- a/t/helper/test-submodule-config.c +++ b/t/helper/test-submodule-config.c @@ -49,9 +49,11 @@ int cmd__submodule_config(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."); @@ -65,7 +67,7 @@ int cmd__submodule_config(int argc, const char **argv) arg += 2; } - submodule_free(); + submodule_free(the_repository); return 0; } diff --git a/t/t7001-mv.sh b/t/t7001-mv.sh index e96cbdb105..cc3fd2baf2 100755 --- a/t/t7001-mv.sh +++ b/t/t7001-mv.sh @@ -495,7 +495,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 && diff --git a/unpack-trees.c b/unpack-trees.c index e73745051e..dec37ad1e7 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); }