git@vger.kernel.org list mirror (unofficial, one of many)
 help / color / mirror / Atom feed
* [PATCH 0/5] Moving submodules with nested submodules
@ 2018-03-27 21:39 Stefan Beller
  2018-03-27 21:39 ` [PATCH 1/5] submodule.h: drop declaration of connect_work_tree_and_git_dir Stefan Beller
                   ` (4 more replies)
  0 siblings, 5 replies; 36+ messages in thread
From: Stefan Beller @ 2018-03-27 21:39 UTC (permalink / raw)
  To: git; +Cc: seanwbehan, bmwill, hvoigt, Stefan Beller

This fixes the bug reported in [1] ("Bug: moving submodules that have submodules
inside them causes a fatal error in git status")

[1] https://public-inbox.org/git/20180306192017.GA5797@riseup.net/

Thanks,
Stefan

Stefan Beller (5):
  submodule.h: drop declaration of connect_work_tree_and_git_dir
  submodule-config: allow submodule_free to handle arbitrary
    repositories
  submodule-config: add repository argument to submodule_from_{name,
    path}
  submodule-config: remove submodule_from_cache
  submodule: fixup nested submodules after moving the submodule

 .../technical/api-submodule-config.txt        |  2 +-
 builtin/grep.c                                |  2 +-
 builtin/mv.c                                  |  6 +-
 builtin/submodule--helper.c                   | 17 +++--
 dir.c                                         | 70 ++++++++++++++++++-
 dir.h                                         | 12 +++-
 repository.c                                  |  2 +-
 submodule-config.c                            | 29 +++-----
 submodule-config.h                            |  9 +--
 submodule.c                                   | 40 ++++++-----
 submodule.h                                   |  1 -
 t/helper/test-submodule-config.c              |  8 ++-
 t/t7001-mv.sh                                 |  2 +-
 unpack-trees.c                                |  2 +-
 14 files changed, 135 insertions(+), 67 deletions(-)

-- 
2.17.0.rc1.321.gba9d0f2565-goog


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 1/5] submodule.h: drop declaration of connect_work_tree_and_git_dir
  2018-03-27 21:39 [PATCH 0/5] Moving submodules with nested submodules Stefan Beller
@ 2018-03-27 21:39 ` Stefan Beller
  2018-03-27 21:39 ` [PATCH 2/5] submodule-config: allow submodule_free to handle arbitrary repositories Stefan Beller
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 36+ messages in thread
From: Stefan Beller @ 2018-03-27 21:39 UTC (permalink / raw)
  To: git; +Cc: seanwbehan, bmwill, hvoigt, Stefan Beller

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 <sbeller@google.com>
---
 submodule.h | 1 -
 1 file changed, 1 deletion(-)

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
-- 
2.17.0.rc1.321.gba9d0f2565-goog


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 2/5] submodule-config: allow submodule_free to handle arbitrary repositories
  2018-03-27 21:39 [PATCH 0/5] Moving submodules with nested submodules Stefan Beller
  2018-03-27 21:39 ` [PATCH 1/5] submodule.h: drop declaration of connect_work_tree_and_git_dir Stefan Beller
@ 2018-03-27 21:39 ` Stefan Beller
  2018-03-27 22:57   ` Brandon Williams
  2018-03-27 22:58   ` [PATCH] grep: remove "repo" arg from non-supporting funcs Jonathan Tan
  2018-03-27 21:39 ` [PATCH 3/5] submodule-config: add repository argument to submodule_from_{name, path} Stefan Beller
                   ` (2 subsequent siblings)
  4 siblings, 2 replies; 36+ messages in thread
From: Stefan Beller @ 2018-03-27 21:39 UTC (permalink / raw)
  To: git; +Cc: seanwbehan, bmwill, hvoigt, Stefan Beller

Signed-off-by: Stefan Beller <sbeller@google.com>
---
 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 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 789a89133a..8f04cde18e 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -651,7 +651,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(repo);
 			gitmodules_config_oid(&real_obj->oid);
 		}
 		if (grep_object(opt, pathspec, real_obj, list->objects[i].name, list->objects[i].path,
diff --git a/submodule-config.c b/submodule-config.c
index 602ba8ca8b..a3efff1a34 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..df6bd6e6db 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);
+extern 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 d5685891a5..05e5fa77eb 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);
 		}
-- 
2.17.0.rc1.321.gba9d0f2565-goog


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 3/5] submodule-config: add repository argument to submodule_from_{name, path}
  2018-03-27 21:39 [PATCH 0/5] Moving submodules with nested submodules Stefan Beller
  2018-03-27 21:39 ` [PATCH 1/5] submodule.h: drop declaration of connect_work_tree_and_git_dir Stefan Beller
  2018-03-27 21:39 ` [PATCH 2/5] submodule-config: allow submodule_free to handle arbitrary repositories Stefan Beller
@ 2018-03-27 21:39 ` Stefan Beller
  2018-03-27 23:04   ` Jonathan Tan
  2018-03-27 21:39 ` [PATCH 4/5] submodule-config: remove submodule_from_cache Stefan Beller
  2018-03-27 21:39 ` [PATCH 5/5] submodule: fixup nested submodules after moving the submodule Stefan Beller
  4 siblings, 1 reply; 36+ messages in thread
From: Stefan Beller @ 2018-03-27 21:39 UTC (permalink / raw)
  To: git; +Cc: seanwbehan, bmwill, hvoigt, Stefan Beller

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.

Signed-off-by: Stefan Beller <sbeller@google.com>
---
 builtin/submodule--helper.c      | 14 +++++++-------
 submodule-config.c               | 14 ++++++++------
 submodule-config.h               |  4 ++--
 submodule.c                      | 30 ++++++++++++++++--------------
 t/helper/test-submodule-config.c |  6 ++++--
 5 files changed, 37 insertions(+), 31 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index ee020d4749..a921fbbf56 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -454,7 +454,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"),
@@ -621,7 +621,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);
 
@@ -741,7 +741,7 @@ static int module_name(int argc, const char **argv, const char *prefix)
 	if (argc != 2)
 		usage(_("git submodule--helper name <path>"));
 
-	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'"),
@@ -772,7 +772,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) ||
@@ -925,7 +925,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;
@@ -1367,7 +1367,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,
@@ -1650,7 +1650,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 a3efff1a34..4b7803e6ed 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 df6bd6e6db..ff3c9e0b5c 100644
--- a/submodule-config.h
+++ b/submodule-config.h
@@ -39,9 +39,9 @@ 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(
+extern const struct submodule *submodule_from_name(struct repository *r,
 		const struct object_id *commit_or_tree, const char *name);
-extern const struct submodule *submodule_from_path(
+extern 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,
diff --git a/submodule.c b/submodule.c
index 12a2503fda..e94b7f9acd 100644
--- a/submodule.c
+++ b/submodule.c
@@ -95,7 +95,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;
@@ -129,7 +129,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;
@@ -173,7 +173,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;
@@ -673,7 +674,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,
@@ -730,13 +731,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 "
@@ -944,7 +946,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
@@ -1112,7 +1114,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 */
@@ -1133,7 +1135,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
@@ -1161,7 +1163,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 */
@@ -1603,7 +1605,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);
@@ -1885,7 +1887,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);
 
@@ -1941,7 +1943,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,
@@ -2087,7 +2089,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.");
 
-- 
2.17.0.rc1.321.gba9d0f2565-goog


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 4/5] submodule-config: remove submodule_from_cache
  2018-03-27 21:39 [PATCH 0/5] Moving submodules with nested submodules Stefan Beller
                   ` (2 preceding siblings ...)
  2018-03-27 21:39 ` [PATCH 3/5] submodule-config: add repository argument to submodule_from_{name, path} Stefan Beller
@ 2018-03-27 21:39 ` Stefan Beller
  2018-03-27 23:07   ` Jonathan Tan
  2018-03-27 21:39 ` [PATCH 5/5] submodule: fixup nested submodules after moving the submodule Stefan Beller
  4 siblings, 1 reply; 36+ messages in thread
From: Stefan Beller @ 2018-03-27 21:39 UTC (permalink / raw)
  To: git; +Cc: seanwbehan, bmwill, hvoigt, Stefan Beller

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.

Signed-off-by: Stefan Beller <sbeller@google.com>
---
 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 4ffbe9bc94..fa0a132e22 100644
--- a/repository.c
+++ b/repository.c
@@ -167,7 +167,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 4b7803e6ed..cb65354d4c 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 ff3c9e0b5c..3ae8a1e51b 100644
--- a/submodule-config.h
+++ b/submodule-config.h
@@ -43,9 +43,6 @@ extern const struct submodule *submodule_from_name(struct repository *r,
 		const struct object_id *commit_or_tree, const char *name);
 extern 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);
 extern void submodule_free(struct repository *r);
 
 #endif /* SUBMODULE_CONFIG_H */
diff --git a/submodule.c b/submodule.c
index e94b7f9acd..89d0aee086 100644
--- a/submodule.c
+++ b/submodule.c
@@ -230,7 +230,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)
@@ -1235,7 +1235,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) {
-- 
2.17.0.rc1.321.gba9d0f2565-goog


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 5/5] submodule: fixup nested submodules after moving the submodule
  2018-03-27 21:39 [PATCH 0/5] Moving submodules with nested submodules Stefan Beller
                   ` (3 preceding siblings ...)
  2018-03-27 21:39 ` [PATCH 4/5] submodule-config: remove submodule_from_cache Stefan Beller
@ 2018-03-27 21:39 ` Stefan Beller
  2018-03-27 23:25   ` Brandon Williams
  2018-03-28  0:07   ` Jonathan Tan
  4 siblings, 2 replies; 36+ messages in thread
From: Stefan Beller @ 2018-03-27 21:39 UTC (permalink / raw)
  To: git; +Cc: seanwbehan, bmwill, hvoigt, Stefan Beller

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
submoduled 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 superprojects 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 and first
and then force a reload of the submodule config machinery.

Signed-off-by: Stefan Beller <sbeller@google.com>
---
 builtin/mv.c                |  6 ++--
 builtin/submodule--helper.c |  3 +-
 dir.c                       | 70 +++++++++++++++++++++++++++++++++++--
 dir.h                       | 12 ++++++-
 submodule.c                 |  6 ++--
 t/t7001-mv.sh               |  2 +-
 6 files changed, 87 insertions(+), 12 deletions(-)

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 a921fbbf56..05fd657f99 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -1259,8 +1259,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 dedbf5d476..313176e291 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,67 @@ 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,
+					struct repository *superproject)
+{
+	int i;
+	struct repository subrepo;
+	struct strbuf sub_wt = STRBUF_INIT;
+	struct strbuf sub_gd = STRBUF_INIT;
+	const struct submodule *sub;
+	const char *super_worktree,
+		   *sub_path; /* path inside the superproject */
+
+	/* subrepo got moved, so superproject has outdated information */
+	submodule_free(superproject);
+
+	super_worktree = real_pathdup(superproject->worktree, 1);
+
+	sub_path = sub_worktree + strlen(super_worktree) + 1;
+
+	if (repo_submodule_init(&subrepo, superproject, sub_path))
+		return;
+
+	repo_read_index(&subrepo);
+
+	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)
+			/* submodule not checked out? */
+			continue;
+
+		strbuf_reset(&sub_wt);
+		strbuf_addf(&sub_wt, "%s/%s/.git", sub_worktree, sub->path);
+
+		strbuf_reset(&sub_gd);
+		strbuf_addf(&sub_gd, "%s/modules/%s", sub_gitdir, sub->name);
+
+		strbuf_setlen(&sub_wt, sub_wt.len - strlen("/.git"));
+
+		if (is_submodule_active(&subrepo, ce->name)) {
+			connect_work_tree_and_git_dir(sub_wt.buf, sub_gd.buf, 0);
+			connect_wt_gitdir_in_nested(sub_wt.buf, sub_gd.buf, &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 +3101,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, the_repository);
+
 	free(work_tree);
 	free(git_dir);
 }
@@ -3054,5 +3118,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/submodule.c b/submodule.c
index 89d0aee086..c2dac6c00f 100644
--- a/submodule.c
+++ b/submodule.c
@@ -1624,7 +1624,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 */
@@ -1634,7 +1634,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);
 		}
 	}
@@ -1947,7 +1947,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 d4e6485a26..ff70244620 100755
--- a/t/t7001-mv.sh
+++ b/t/t7001-mv.sh
@@ -497,7 +497,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 &&
-- 
2.17.0.rc1.321.gba9d0f2565-goog


^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 2/5] submodule-config: allow submodule_free to handle arbitrary repositories
  2018-03-27 21:39 ` [PATCH 2/5] submodule-config: allow submodule_free to handle arbitrary repositories Stefan Beller
@ 2018-03-27 22:57   ` Brandon Williams
  2018-03-27 22:58   ` [PATCH] grep: remove "repo" arg from non-supporting funcs Jonathan Tan
  1 sibling, 0 replies; 36+ messages in thread
From: Brandon Williams @ 2018-03-27 22:57 UTC (permalink / raw)
  To: Stefan Beller; +Cc: git, seanwbehan, hvoigt

On 03/27, Stefan Beller wrote:
> Signed-off-by: Stefan Beller <sbeller@google.com>

Looks good.  At some point we may want to rename this 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.

> ---
>  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 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 789a89133a..8f04cde18e 100644
> --- a/builtin/grep.c
> +++ b/builtin/grep.c
> @@ -651,7 +651,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(repo);
>  			gitmodules_config_oid(&real_obj->oid);
>  		}
>  		if (grep_object(opt, pathspec, real_obj, list->objects[i].name, list->objects[i].path,
> diff --git a/submodule-config.c b/submodule-config.c
> index 602ba8ca8b..a3efff1a34 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..df6bd6e6db 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);
> +extern 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 d5685891a5..05e5fa77eb 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);
>  		}
> -- 
> 2.17.0.rc1.321.gba9d0f2565-goog
> 

-- 
Brandon Williams

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH] grep: remove "repo" arg from non-supporting funcs
  2018-03-27 21:39 ` [PATCH 2/5] submodule-config: allow submodule_free to handle arbitrary repositories Stefan Beller
  2018-03-27 22:57   ` Brandon Williams
@ 2018-03-27 22:58   ` Jonathan Tan
  2018-03-27 23:20     ` Stefan Beller
  1 sibling, 1 reply; 36+ messages in thread
From: Jonathan Tan @ 2018-03-27 22:58 UTC (permalink / raw)
  To: sbeller, git; +Cc: bmwill, hvoigt, seanwbehan, Jonathan Tan

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.

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 <jonathantanmy@google.com>
---
Patch 1/5 of your series is obviously correct.

I investigated the change to grep_objects() in patch 2/5, and here is a
patch summarizing my findings. Consider including this patch before 2/5
(or before 1/5). You'll probably need to write
"submodule_free(the_repository);" instead of what you have currently,
but other than that, I don't think this affects your patch set much.
---
 builtin/grep.c | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/builtin/grep.c b/builtin/grep.c
index 789a89133..f286f2375 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -601,8 +601,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);
@@ -629,7 +628,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;
@@ -638,7 +637,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;
@@ -654,8 +652,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;
@@ -1107,7 +1105,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)
-- 
2.16.0.rc0.35.ga4d78ce26


^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 3/5] submodule-config: add repository argument to submodule_from_{name, path}
  2018-03-27 21:39 ` [PATCH 3/5] submodule-config: add repository argument to submodule_from_{name, path} Stefan Beller
@ 2018-03-27 23:04   ` Jonathan Tan
  2018-03-27 23:53     ` Stefan Beller
  0 siblings, 1 reply; 36+ messages in thread
From: Jonathan Tan @ 2018-03-27 23:04 UTC (permalink / raw)
  To: Stefan Beller; +Cc: git, seanwbehan, bmwill, hvoigt

On Tue, 27 Mar 2018 14:39:16 -0700
Stefan Beller <sbeller@google.com> wrote:

> -extern const struct submodule *submodule_from_name(
> +extern const struct submodule *submodule_from_name(struct repository *r,
>  		const struct object_id *commit_or_tree, const char *name);
> -extern const struct submodule *submodule_from_path(
> +extern const struct submodule *submodule_from_path(struct repository *r,
>  		const struct object_id *commit_or_tree, const char *path);

There is a recent change to CodingGuidelines that states to not include
"extern" in 89a9f2c862 ("CodingGuidelines: mention "static" and
"extern"", 2018-02-08), so consider removing "extern" since you're
already changing this file.

Other than that,

Reviewed-by: Jonathan Tan <jonathantanmy@google.com>

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 4/5] submodule-config: remove submodule_from_cache
  2018-03-27 21:39 ` [PATCH 4/5] submodule-config: remove submodule_from_cache Stefan Beller
@ 2018-03-27 23:07   ` Jonathan Tan
  0 siblings, 0 replies; 36+ messages in thread
From: Jonathan Tan @ 2018-03-27 23:07 UTC (permalink / raw)
  To: Stefan Beller; +Cc: git, seanwbehan, bmwill, hvoigt

On Tue, 27 Mar 2018 14:39:17 -0700
Stefan Beller <sbeller@google.com> wrote:

> 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.
> 
> Signed-off-by: Stefan Beller <sbeller@google.com>

Obviously correct, since submodule_from_{path,cache} are word-for-word
identical (other than parameter names).

Reviewed-by: Jonathan Tan <jonathantanmy@google.com>

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] grep: remove "repo" arg from non-supporting funcs
  2018-03-27 22:58   ` [PATCH] grep: remove "repo" arg from non-supporting funcs Jonathan Tan
@ 2018-03-27 23:20     ` Stefan Beller
  2018-03-28  0:24       ` Jonathan Tan
  0 siblings, 1 reply; 36+ messages in thread
From: Stefan Beller @ 2018-03-27 23:20 UTC (permalink / raw)
  To: Jonathan Tan; +Cc: git, Brandon Williams, Heiko Voigt, seanwbehan

On Tue, Mar 27, 2018 at 3:58 PM, Jonathan Tan <jonathantanmy@google.com> wrote:
> 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.
>
> 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.

I'd rather convert gitmodules_config_oid instead of reverting the other
functions into a world without an arbitrary repository object.

>
> Signed-off-by: Jonathan Tan <jonathantanmy@google.com>
> ---
> Patch 1/5 of your series is obviously correct.
>
> I investigated the change to grep_objects() in patch 2/5, and here is a
> patch summarizing my findings. Consider including this patch before 2/5
> (or before 1/5). You'll probably need to write
> "submodule_free(the_repository);" instead of what you have currently,
> but other than that, I don't think this affects your patch set much.

Thanks for looking at the patches!
I'd think this patch is orthogonal to the series, as this is about the effort
of converting parts of git-grep whereas this series is fixing a bug (by
converting parts of the submodule config machinery))?

Thanks,
Stefan

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 5/5] submodule: fixup nested submodules after moving the submodule
  2018-03-27 21:39 ` [PATCH 5/5] submodule: fixup nested submodules after moving the submodule Stefan Beller
@ 2018-03-27 23:25   ` Brandon Williams
  2018-03-28  0:07   ` Jonathan Tan
  1 sibling, 0 replies; 36+ messages in thread
From: Brandon Williams @ 2018-03-27 23:25 UTC (permalink / raw)
  To: Stefan Beller; +Cc: git, seanwbehan, hvoigt

On 03/27, Stefan Beller wrote:
> 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
> submoduled 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 superprojects 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 and first
> and then force a reload of the submodule config machinery.
> 
> Signed-off-by: Stefan Beller <sbeller@google.com>
> ---
>  builtin/mv.c                |  6 ++--
>  builtin/submodule--helper.c |  3 +-
>  dir.c                       | 70 +++++++++++++++++++++++++++++++++++--
>  dir.h                       | 12 ++++++-
>  submodule.c                 |  6 ++--
>  t/t7001-mv.sh               |  2 +-
>  6 files changed, 87 insertions(+), 12 deletions(-)
> 
> 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 a921fbbf56..05fd657f99 100644
> --- a/builtin/submodule--helper.c
> +++ b/builtin/submodule--helper.c
> @@ -1259,8 +1259,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 dedbf5d476..313176e291 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,67 @@ 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,
> +					struct repository *superproject)
> +{
> +	int i;
> +	struct repository subrepo;

You never clear this struct which means it leaks the memory it points
to.

> +	struct strbuf sub_wt = STRBUF_INIT;
> +	struct strbuf sub_gd = STRBUF_INIT;
> +	const struct submodule *sub;
> +	const char *super_worktree,
> +		   *sub_path; /* path inside the superproject */
> +
> +	/* subrepo got moved, so superproject has outdated information */
> +	submodule_free(superproject);
> +
> +	super_worktree = real_pathdup(superproject->worktree, 1);
> +
> +	sub_path = sub_worktree + strlen(super_worktree) + 1;
> +
> +	if (repo_submodule_init(&subrepo, superproject, sub_path))
> +		return;
> +
> +	repo_read_index(&subrepo);

You may want to check the return value to see if reading the index was
successful.

> +
> +	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)
> +			/* submodule not checked out? */
> +			continue;
> +
> +		strbuf_reset(&sub_wt);
> +		strbuf_addf(&sub_wt, "%s/%s/.git", sub_worktree, sub->path);
> +
> +		strbuf_reset(&sub_gd);
> +		strbuf_addf(&sub_gd, "%s/modules/%s", sub_gitdir, sub->name);
> +
> +		strbuf_setlen(&sub_wt, sub_wt.len - strlen("/.git"));
> +
> +		if (is_submodule_active(&subrepo, ce->name)) {
> +			connect_work_tree_and_git_dir(sub_wt.buf, sub_gd.buf, 0);
> +			connect_wt_gitdir_in_nested(sub_wt.buf, sub_gd.buf, &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 +3101,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, the_repository);
> +
>  	free(work_tree);
>  	free(git_dir);
>  }
> @@ -3054,5 +3118,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/submodule.c b/submodule.c
> index 89d0aee086..c2dac6c00f 100644
> --- a/submodule.c
> +++ b/submodule.c
> @@ -1624,7 +1624,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 */
> @@ -1634,7 +1634,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);
>  		}
>  	}
> @@ -1947,7 +1947,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 d4e6485a26..ff70244620 100755
> --- a/t/t7001-mv.sh
> +++ b/t/t7001-mv.sh
> @@ -497,7 +497,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 &&
> -- 
> 2.17.0.rc1.321.gba9d0f2565-goog
> 

-- 
Brandon Williams

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 3/5] submodule-config: add repository argument to submodule_from_{name, path}
  2018-03-27 23:04   ` Jonathan Tan
@ 2018-03-27 23:53     ` Stefan Beller
  0 siblings, 0 replies; 36+ messages in thread
From: Stefan Beller @ 2018-03-27 23:53 UTC (permalink / raw)
  To: Jonathan Tan; +Cc: git, seanwbehan, Brandon Williams, Heiko Voigt

On Tue, Mar 27, 2018 at 4:04 PM, Jonathan Tan <jonathantanmy@google.com> wrote:
> On Tue, 27 Mar 2018 14:39:16 -0700
> Stefan Beller <sbeller@google.com> wrote:
>
>> -extern const struct submodule *submodule_from_name(
>> +extern const struct submodule *submodule_from_name(struct repository *r,
>>               const struct object_id *commit_or_tree, const char *name);
>> -extern const struct submodule *submodule_from_path(
>> +extern const struct submodule *submodule_from_path(struct repository *r,
>>               const struct object_id *commit_or_tree, const char *path);
>
> There is a recent change to CodingGuidelines that states to not include
> "extern" in 89a9f2c862 ("CodingGuidelines: mention "static" and
> "extern"", 2018-02-08), so consider removing "extern" since you're
> already changing this file.

Gah!

I have that fixed locally; it will be included in the next version

>
> Other than that,
>
> Reviewed-by: Jonathan Tan <jonathantanmy@google.com>

Thanks!

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 5/5] submodule: fixup nested submodules after moving the submodule
  2018-03-27 21:39 ` [PATCH 5/5] submodule: fixup nested submodules after moving the submodule Stefan Beller
  2018-03-27 23:25   ` Brandon Williams
@ 2018-03-28  0:07   ` Jonathan Tan
  2018-03-28  0:42     ` Stefan Beller
  1 sibling, 1 reply; 36+ messages in thread
From: Jonathan Tan @ 2018-03-28  0:07 UTC (permalink / raw)
  To: Stefan Beller; +Cc: git, seanwbehan, bmwill, hvoigt

On Tue, 27 Mar 2018 14:39:18 -0700
Stefan Beller <sbeller@google.com> wrote:

> 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
> submoduled themselves, we'd also want to fix the nested submodules when

s/submoduled/submodules

> 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 superprojects git directory) internally

s/superprojects/superproject's/

> 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 and first

s/and //

> and then force a reload of the submodule config machinery.

s/force/forcing/

> 
> Signed-off-by: Stefan Beller <sbeller@google.com>

[snip]

> +static void connect_wt_gitdir_in_nested(const char *sub_worktree,
> +					const char *sub_gitdir,
> +					struct repository *superproject)
> +{
> +	int i;
> +	struct repository subrepo;
> +	struct strbuf sub_wt = STRBUF_INIT;
> +	struct strbuf sub_gd = STRBUF_INIT;
> +	const struct submodule *sub;
> +	const char *super_worktree,
> +		   *sub_path; /* path inside the superproject */
> +
> +	/* subrepo got moved, so superproject has outdated information */
> +	submodule_free(superproject);
> +
> +	super_worktree = real_pathdup(superproject->worktree, 1);
> +
> +	sub_path = sub_worktree + strlen(super_worktree) + 1;
> +
> +	if (repo_submodule_init(&subrepo, superproject, sub_path))
> +		return;
> +
> +	repo_read_index(&subrepo);

From the name of this function and its usage in
connect_work_tree_and_git_dir(), I expected this function to just
iterate through all the files in its workdir (which it is doing in the
"for" loop below) and connect any nested submodules. Why does it need
access to its superproject? (I would think that repo_init() would be
sufficient here instead of repo_submodule_init().)

> +
> +	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)
> +			/* submodule not checked out? */
> +			continue;
> +
> +		strbuf_reset(&sub_wt);
> +		strbuf_addf(&sub_wt, "%s/%s/.git", sub_worktree, sub->path);
> +
> +		strbuf_reset(&sub_gd);
> +		strbuf_addf(&sub_gd, "%s/modules/%s", sub_gitdir, sub->name);
> +
> +		strbuf_setlen(&sub_wt, sub_wt.len - strlen("/.git"));
> +
> +		if (is_submodule_active(&subrepo, ce->name)) {
> +			connect_work_tree_and_git_dir(sub_wt.buf, sub_gd.buf, 0);
> +			connect_wt_gitdir_in_nested(sub_wt.buf, sub_gd.buf, &subrepo);

The modifications of sub_wt and sub_gd should probably go here, since
they are not used unless this "if" block is executed.

> +void connect_work_tree_and_git_dir(const char *work_tree_,
> +				   const char *git_dir_,
> +				   int recurse_into_nested)

How is this function expected to be used? From what I see:
 - if recurse_into_nested is 0, this works regardless of whether the
   work_tree_ and git_dir_ is directly or indirectly a submodule of
   the_repository
 - if recurse_into_nested is 1, work_tree_ and git_dir_ must be directly
   a submodule of the_repository (since it is referenced directly)

This seems confusing - is this expected?

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] grep: remove "repo" arg from non-supporting funcs
  2018-03-27 23:20     ` Stefan Beller
@ 2018-03-28  0:24       ` Jonathan Tan
  2018-03-28  0:35         ` Stefan Beller
  0 siblings, 1 reply; 36+ messages in thread
From: Jonathan Tan @ 2018-03-28  0:24 UTC (permalink / raw)
  To: Stefan Beller; +Cc: git, Brandon Williams, Heiko Voigt, seanwbehan

On Tue, 27 Mar 2018 16:20:25 -0700
Stefan Beller <sbeller@google.com> wrote:

> On Tue, Mar 27, 2018 at 3:58 PM, Jonathan Tan <jonathantanmy@google.com> wrote:
> > 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.
> >
> > 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.
> 
> I'd rather convert gitmodules_config_oid instead of reverting the other
> functions into a world without an arbitrary repository object.

I don't really think of it as a reversion, since grep_objects() didn't
fully support repos other than the_repository anyway.

Besides that, that's fine, but then:

 (1) You would have to explain both in the gitmodules_config_oid() and
     in this patch why "gitmodules_config_oid(...)" ->
     "gitmodules_config_oid(repo, ...)" and "submodule_free()" ->
     "submodule_free(repo)" are safe, since they have different behavior
     upon first glance. (They have the same behavior only because
     grep_objects() is always called with the_repository.) I was trying
     to explain this in as clear a way as possible, by showing (with
     code) that grep_objects() only works with, and is only called with,
     the_repository.
 (2) The code path where repo != the_repository would still never be
     exercised, and I prefer to not have such code paths.

I don't feel too strongly about (1), since they just concern commit
messages, of which there are many valid opinions on how to write them. I
feel a bit more strongly about (2), but can concede my point if the
project is OK with a code path not being exercised.

> Thanks for looking at the patches!
> I'd think this patch is orthogonal to the series, as this is about the effort
> of converting parts of git-grep whereas this series is fixing a bug (by
> converting parts of the submodule config machinery))?

It is orthogonal in the same way as your patch 1/5, I think - a
preparatory patch to make your "real" patches easier to understand.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] grep: remove "repo" arg from non-supporting funcs
  2018-03-28  0:24       ` Jonathan Tan
@ 2018-03-28  0:35         ` Stefan Beller
  0 siblings, 0 replies; 36+ messages in thread
From: Stefan Beller @ 2018-03-28  0:35 UTC (permalink / raw)
  To: Jonathan Tan; +Cc: git, Brandon Williams, Heiko Voigt, seanwbehan

On Tue, Mar 27, 2018 at 5:24 PM, Jonathan Tan <jonathantanmy@google.com> wrote:
> On Tue, 27 Mar 2018 16:20:25 -0700
> Stefan Beller <sbeller@google.com> wrote:
>
>> On Tue, Mar 27, 2018 at 3:58 PM, Jonathan Tan <jonathantanmy@google.com> wrote:
>> > 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.
>> >
>> > 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.
>>
>> I'd rather convert gitmodules_config_oid instead of reverting the other
>> functions into a world without an arbitrary repository object.
>
> I don't really think of it as a reversion, since grep_objects() didn't
> fully support repos other than the_repository anyway.
>
> Besides that, that's fine, but then:
>
>  (1) You would have to explain both in the gitmodules_config_oid() and
>      in this patch why "gitmodules_config_oid(...)" ->
>      "gitmodules_config_oid(repo, ...)" and "submodule_free()" ->
>      "submodule_free(repo)" are safe, since they have different behavior
>      upon first glance. (They have the same behavior only because
>      grep_objects() is always called with the_repository.) I was trying
>      to explain this in as clear a way as possible, by showing (with
>      code) that grep_objects() only works with, and is only called with,
>      the_repository.
>  (2) The code path where repo != the_repository would still never be
>      exercised, and I prefer to not have such code paths.
>
> I don't feel too strongly about (1), since they just concern commit
> messages, of which there are many valid opinions on how to write them. I
> feel a bit more strongly about (2), but can concede my point if the
> project is OK with a code path not being exercised.

Ok. I admit not having looked at the code beforehand, and I was
just arguing based on intuition. Turns out I was wrong.

I thought that we'd have to have arbitrary repos for proper submodule
recursion, but this specific code is for grepping thru given tree objects,
which for now is assumed that the user can only give trees of
the_repository and we'd error out in case of a submodule tree.
Makes sense.

In that case, I agree with your patch. Thanks for writing it.
I'll take it into the series.

Thanks,
Stefan

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 5/5] submodule: fixup nested submodules after moving the submodule
  2018-03-28  0:07   ` Jonathan Tan
@ 2018-03-28  0:42     ` Stefan Beller
  2018-03-28 17:24       ` [PATCHv2 0/6] Moving submodules with nested submodules Stefan Beller
  0 siblings, 1 reply; 36+ messages in thread
From: Stefan Beller @ 2018-03-28  0:42 UTC (permalink / raw)
  To: Jonathan Tan; +Cc: git, seanwbehan, Brandon Williams, Heiko Voigt

On Tue, Mar 27, 2018 at 5:07 PM, Jonathan Tan <jonathantanmy@google.com> wrote:

> s/submoduled/submodules

> s/superprojects/superproject's/

> s/and //
>
> s/force/forcing/

All wording fixed.

>> +     sub_path = sub_worktree + strlen(super_worktree) + 1;
>> +
>> +     if (repo_submodule_init(&subrepo, superproject, sub_path))
>> +             return;
>> +
>> +     repo_read_index(&subrepo);
>
> From the name of this function and its usage in
> connect_work_tree_and_git_dir(), I expected this function to just
> iterate through all the files in its workdir (which it is doing in the
> "for" loop below) and connect any nested submodules. Why does it need
> access to its superproject? (I would think that repo_init() would be
> sufficient here instead of repo_submodule_init().)

Testing validates your thinking (for now).

If we ever want to have good error reporting (see bmwills hint to
check for index corruption), we may want to have all the repos constructed
as submodules from the_repository, as then the error messages might
be better (e.g. in the future we could display the
"submodule nesting stack").

I'll remove the superproject argument for now.

>> +
>> +             strbuf_reset(&sub_wt);
>> +             strbuf_addf(&sub_wt, "%s/%s/.git", sub_worktree, sub->path);
>> +
>> +             strbuf_reset(&sub_gd);
>> +             strbuf_addf(&sub_gd, "%s/modules/%s", sub_gitdir, sub->name);
>> +
>> +             strbuf_setlen(&sub_wt, sub_wt.len - strlen("/.git"));
>> +
>> +             if (is_submodule_active(&subrepo, ce->name)) {
>> +                     connect_work_tree_and_git_dir(sub_wt.buf, sub_gd.buf, 0);
>> +                     connect_wt_gitdir_in_nested(sub_wt.buf, sub_gd.buf, &subrepo);
>
> The modifications of sub_wt and sub_gd should probably go here, since
> they are not used unless this "if" block is executed.

Thanks! I also cut out the setlen call by giving the correct format string.
(The code presented here is not very old, I just fired it off as soon as the
test passed)

>
>> +void connect_work_tree_and_git_dir(const char *work_tree_,
>> +                                const char *git_dir_,
>> +                                int recurse_into_nested)
>
> How is this function expected to be used? From what I see:
>  - if recurse_into_nested is 0, this works regardless of whether the
>    work_tree_ and git_dir_ is directly or indirectly a submodule of
>    the_repository
>  - if recurse_into_nested is 1, work_tree_ and git_dir_ must be directly
>    a submodule of the_repository (since it is referenced directly)
>
> This seems confusing - is this expected?

In the next revision of the series connect_wt_gitdir_in_nested
will no longer have a third argument for the repo, as we use repo_init.

That eases the handling a bit here.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCHv2 0/6] Moving submodules with nested submodules
  2018-03-28  0:42     ` Stefan Beller
@ 2018-03-28 17:24       ` Stefan Beller
  2018-03-28 17:24         ` [PATCH 1/6] submodule.h: drop declaration of connect_work_tree_and_git_dir Stefan Beller
                           ` (6 more replies)
  0 siblings, 7 replies; 36+ messages in thread
From: Stefan Beller @ 2018-03-28 17:24 UTC (permalink / raw)
  To: sbeller, gitster; +Cc: bmwill, git, hvoigt, jonathantanmy, seanwbehan

v2:
* addressed memleaks and messy code in patch 5
* removed the extern keyword where applicable
* extended the commit message, stating we want to rename submodule_free
  in the future.
* picked up Jonathans patch and added it as a nice finish of the series.
  I did not see the need or aesthetic desire to put that patch earlier
  in the series.
  
Thanks,
Stefan

v1:

This fixes the bug reported in [1] ("Bug: moving submodules that have submodules
inside them causes a fatal error in git status")

[1] https://public-inbox.org/git/20180306192017.GA5797@riseup.net/

Thanks,
Stefan

Jonathan Tan (1):
  grep: remove "repo" arg from non-supporting funcs

Stefan Beller (5):
  submodule.h: drop declaration of connect_work_tree_and_git_dir
  submodule-config: allow submodule_free to handle arbitrary
    repositories
  submodule-config: add repository argument to submodule_from_{name,
    path}
  submodule-config: remove submodule_from_cache
  submodule: fixup nested submodules after moving the submodule

 .../technical/api-submodule-config.txt        |  2 +-
 builtin/grep.c                                | 14 ++---
 builtin/mv.c                                  |  6 +-
 builtin/submodule--helper.c                   | 17 +++--
 dir.c                                         | 63 ++++++++++++++++++-
 dir.h                                         | 12 +++-
 repository.c                                  |  2 +-
 submodule-config.c                            | 29 ++++-----
 submodule-config.h                            | 15 +++--
 submodule.c                                   | 40 ++++++------
 submodule.h                                   |  1 -
 t/helper/test-submodule-config.c              |  8 ++-
 t/t7001-mv.sh                                 |  2 +-
 unpack-trees.c                                |  2 +-
 14 files changed, 137 insertions(+), 76 deletions(-)

-- 
2.17.0.rc1.321.gba9d0f2565-goog


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 1/6] submodule.h: drop declaration of connect_work_tree_and_git_dir
  2018-03-28 17:24       ` [PATCHv2 0/6] Moving submodules with nested submodules Stefan Beller
@ 2018-03-28 17:24         ` Stefan Beller
  2018-03-28 17:24         ` [PATCH 2/6] submodule-config: allow submodule_free to handle arbitrary repositories Stefan Beller
                           ` (5 subsequent siblings)
  6 siblings, 0 replies; 36+ messages in thread
From: Stefan Beller @ 2018-03-28 17:24 UTC (permalink / raw)
  To: sbeller, gitster; +Cc: bmwill, git, hvoigt, jonathantanmy, seanwbehan

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 <sbeller@google.com>
---
 submodule.h | 1 -
 1 file changed, 1 deletion(-)

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
-- 
2.17.0.rc1.321.gba9d0f2565-goog


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 2/6] submodule-config: allow submodule_free to handle arbitrary repositories
  2018-03-28 17:24       ` [PATCHv2 0/6] Moving submodules with nested submodules Stefan Beller
  2018-03-28 17:24         ` [PATCH 1/6] submodule.h: drop declaration of connect_work_tree_and_git_dir Stefan Beller
@ 2018-03-28 17:24         ` Stefan Beller
  2018-03-28 17:24         ` [PATCH 3/6] submodule-config: add repository argument to submodule_from_{name, path} Stefan Beller
                           ` (4 subsequent siblings)
  6 siblings, 0 replies; 36+ messages in thread
From: Stefan Beller @ 2018-03-28 17:24 UTC (permalink / raw)
  To: sbeller, gitster; +Cc: bmwill, git, hvoigt, jonathantanmy, seanwbehan

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 <sbeller@google.com>
---
 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 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 789a89133a..8f04cde18e 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -651,7 +651,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(repo);
 			gitmodules_config_oid(&real_obj->oid);
 		}
 		if (grep_object(opt, pathspec, real_obj, list->objects[i].name, list->objects[i].path,
diff --git a/submodule-config.c b/submodule-config.c
index 602ba8ca8b..a3efff1a34 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 d5685891a5..05e5fa77eb 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);
 		}
-- 
2.17.0.rc1.321.gba9d0f2565-goog


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 3/6] submodule-config: add repository argument to submodule_from_{name, path}
  2018-03-28 17:24       ` [PATCHv2 0/6] Moving submodules with nested submodules Stefan Beller
  2018-03-28 17:24         ` [PATCH 1/6] submodule.h: drop declaration of connect_work_tree_and_git_dir Stefan Beller
  2018-03-28 17:24         ` [PATCH 2/6] submodule-config: allow submodule_free to handle arbitrary repositories Stefan Beller
@ 2018-03-28 17:24         ` Stefan Beller
  2018-03-28 17:24         ` [PATCH 4/6] submodule-config: remove submodule_from_cache Stefan Beller
                           ` (3 subsequent siblings)
  6 siblings, 0 replies; 36+ messages in thread
From: Stefan Beller @ 2018-03-28 17:24 UTC (permalink / raw)
  To: sbeller, gitster; +Cc: bmwill, git, hvoigt, jonathantanmy, seanwbehan

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 <jonathantanmy@google.com>
Signed-off-by: Stefan Beller <sbeller@google.com>
---
 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 ee020d4749..a921fbbf56 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -454,7 +454,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"),
@@ -621,7 +621,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);
 
@@ -741,7 +741,7 @@ static int module_name(int argc, const char **argv, const char *prefix)
 	if (argc != 2)
 		usage(_("git submodule--helper name <path>"));
 
-	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'"),
@@ -772,7 +772,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) ||
@@ -925,7 +925,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;
@@ -1367,7 +1367,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,
@@ -1650,7 +1650,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 a3efff1a34..4b7803e6ed 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 12a2503fda..e94b7f9acd 100644
--- a/submodule.c
+++ b/submodule.c
@@ -95,7 +95,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;
@@ -129,7 +129,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;
@@ -173,7 +173,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;
@@ -673,7 +674,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,
@@ -730,13 +731,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 "
@@ -944,7 +946,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
@@ -1112,7 +1114,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 */
@@ -1133,7 +1135,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
@@ -1161,7 +1163,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 */
@@ -1603,7 +1605,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);
@@ -1885,7 +1887,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);
 
@@ -1941,7 +1943,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,
@@ -2087,7 +2089,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.");
 
-- 
2.17.0.rc1.321.gba9d0f2565-goog


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 4/6] submodule-config: remove submodule_from_cache
  2018-03-28 17:24       ` [PATCHv2 0/6] Moving submodules with nested submodules Stefan Beller
                           ` (2 preceding siblings ...)
  2018-03-28 17:24         ` [PATCH 3/6] submodule-config: add repository argument to submodule_from_{name, path} Stefan Beller
@ 2018-03-28 17:24         ` Stefan Beller
  2018-03-28 17:24         ` [PATCH 5/6] submodule: fixup nested submodules after moving the submodule Stefan Beller
                           ` (2 subsequent siblings)
  6 siblings, 0 replies; 36+ messages in thread
From: Stefan Beller @ 2018-03-28 17:24 UTC (permalink / raw)
  To: sbeller, gitster; +Cc: bmwill, git, hvoigt, jonathantanmy, seanwbehan

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 <jonathantanmy@google.com>
Signed-off-by: Stefan Beller <sbeller@google.com>
---
 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 4ffbe9bc94..fa0a132e22 100644
--- a/repository.c
+++ b/repository.c
@@ -167,7 +167,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 4b7803e6ed..cb65354d4c 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 e94b7f9acd..89d0aee086 100644
--- a/submodule.c
+++ b/submodule.c
@@ -230,7 +230,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)
@@ -1235,7 +1235,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) {
-- 
2.17.0.rc1.321.gba9d0f2565-goog


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 5/6] submodule: fixup nested submodules after moving the submodule
  2018-03-28 17:24       ` [PATCHv2 0/6] Moving submodules with nested submodules Stefan Beller
                           ` (3 preceding siblings ...)
  2018-03-28 17:24         ` [PATCH 4/6] submodule-config: remove submodule_from_cache Stefan Beller
@ 2018-03-28 17:24         ` Stefan Beller
  2018-03-28 17:35           ` Brandon Williams
  2018-03-28 17:46           ` Jonathan Tan
  2018-03-28 17:24         ` [PATCH 6/6] grep: remove "repo" arg from non-supporting funcs Stefan Beller
  2018-03-28 17:54         ` [PATCHv2 0/6] Moving submodules with nested submodules Jonathan Tan
  6 siblings, 2 replies; 36+ messages in thread
From: Stefan Beller @ 2018-03-28 17:24 UTC (permalink / raw)
  To: sbeller, gitster; +Cc: bmwill, git, hvoigt, jonathantanmy, seanwbehan

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 <sbeller@google.com>
---
 builtin/mv.c                |  6 ++--
 builtin/submodule--helper.c |  3 +-
 dir.c                       | 63 +++++++++++++++++++++++++++++++++++--
 dir.h                       | 12 ++++++-
 submodule.c                 |  6 ++--
 t/t7001-mv.sh               |  2 +-
 6 files changed, 80 insertions(+), 12 deletions(-)

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 a921fbbf56..05fd657f99 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -1259,8 +1259,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 dedbf5d476..71947c0ef3 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,60 @@ 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 (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)
+			/* submodule not checked out? */
+			continue;
+
+		if (is_submodule_active(&subrepo, ce->name)) {
+			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, 0);
+			connect_wt_gitdir_in_nested(sub_wt.buf, sub_gd.buf);
+
+			strbuf_reset(&sub_wt);
+			strbuf_reset(&sub_gd);
+		}
+	}
+	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 +3094,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 +3111,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/submodule.c b/submodule.c
index 89d0aee086..c2dac6c00f 100644
--- a/submodule.c
+++ b/submodule.c
@@ -1624,7 +1624,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 */
@@ -1634,7 +1634,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);
 		}
 	}
@@ -1947,7 +1947,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 d4e6485a26..ff70244620 100755
--- a/t/t7001-mv.sh
+++ b/t/t7001-mv.sh
@@ -497,7 +497,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 &&
-- 
2.17.0.rc1.321.gba9d0f2565-goog


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 6/6] grep: remove "repo" arg from non-supporting funcs
  2018-03-28 17:24       ` [PATCHv2 0/6] Moving submodules with nested submodules Stefan Beller
                           ` (4 preceding siblings ...)
  2018-03-28 17:24         ` [PATCH 5/6] submodule: fixup nested submodules after moving the submodule Stefan Beller
@ 2018-03-28 17:24         ` Stefan Beller
  2018-03-28 17:54         ` [PATCHv2 0/6] Moving submodules with nested submodules Jonathan Tan
  6 siblings, 0 replies; 36+ messages in thread
From: Stefan Beller @ 2018-03-28 17:24 UTC (permalink / raw)
  To: sbeller, gitster; +Cc: bmwill, git, hvoigt, jonathantanmy, seanwbehan

From: Jonathan Tan <jonathantanmy@google.com>

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 <jonathantanmy@google.com>
Signed-off-by: Stefan Beller <sbeller@google.com>
---
 builtin/grep.c | 14 ++++++--------
 1 file changed, 6 insertions(+), 8 deletions(-)

diff --git a/builtin/grep.c b/builtin/grep.c
index 8f04cde18e..091b3f4cc7 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -601,8 +601,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);
@@ -629,7 +628,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;
@@ -638,7 +637,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;
@@ -651,11 +649,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(repo);
+			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;
@@ -1107,7 +1105,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)
-- 
2.17.0.rc1.321.gba9d0f2565-goog


^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 5/6] submodule: fixup nested submodules after moving the submodule
  2018-03-28 17:24         ` [PATCH 5/6] submodule: fixup nested submodules after moving the submodule Stefan Beller
@ 2018-03-28 17:35           ` Brandon Williams
  2018-03-28 19:08             ` Stefan Beller
  2018-03-28 17:46           ` Jonathan Tan
  1 sibling, 1 reply; 36+ messages in thread
From: Brandon Williams @ 2018-03-28 17:35 UTC (permalink / raw)
  To: Stefan Beller; +Cc: gitster, git, hvoigt, jonathantanmy, seanwbehan

On 03/28, Stefan Beller wrote:
> 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 <sbeller@google.com>
> ---
>  builtin/mv.c                |  6 ++--
>  builtin/submodule--helper.c |  3 +-
>  dir.c                       | 63 +++++++++++++++++++++++++++++++++++--
>  dir.h                       | 12 ++++++-
>  submodule.c                 |  6 ++--
>  t/t7001-mv.sh               |  2 +-
>  6 files changed, 80 insertions(+), 12 deletions(-)
> 
> 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 a921fbbf56..05fd657f99 100644
> --- a/builtin/submodule--helper.c
> +++ b/builtin/submodule--helper.c
> @@ -1259,8 +1259,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 dedbf5d476..71947c0ef3 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,60 @@ 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 (repo_init(&subrepo, sub_gitdir, sub_worktree))
> +		return;

Note that in Duy's object-store series he made this function private
(IIRC) so this will result in some clash of the two series.

> +
> +	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)
> +			/* submodule not checked out? */
> +			continue;
> +
> +		if (is_submodule_active(&subrepo, ce->name)) {
> +			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, 0);
> +			connect_wt_gitdir_in_nested(sub_wt.buf, sub_gd.buf);
> +
> +			strbuf_reset(&sub_wt);
> +			strbuf_reset(&sub_gd);
> +		}
> +	}
> +	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 +3094,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 +3111,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/submodule.c b/submodule.c
> index 89d0aee086..c2dac6c00f 100644
> --- a/submodule.c
> +++ b/submodule.c
> @@ -1624,7 +1624,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 */
> @@ -1634,7 +1634,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);
>  		}
>  	}
> @@ -1947,7 +1947,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 d4e6485a26..ff70244620 100755
> --- a/t/t7001-mv.sh
> +++ b/t/t7001-mv.sh
> @@ -497,7 +497,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 &&
> -- 
> 2.17.0.rc1.321.gba9d0f2565-goog
> 

-- 
Brandon Williams

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 5/6] submodule: fixup nested submodules after moving the submodule
  2018-03-28 17:24         ` [PATCH 5/6] submodule: fixup nested submodules after moving the submodule Stefan Beller
  2018-03-28 17:35           ` Brandon Williams
@ 2018-03-28 17:46           ` Jonathan Tan
  1 sibling, 0 replies; 36+ messages in thread
From: Jonathan Tan @ 2018-03-28 17:46 UTC (permalink / raw)
  To: Stefan Beller; +Cc: gitster, bmwill, git, hvoigt, seanwbehan

On Wed, 28 Mar 2018 10:24:48 -0700
Stefan Beller <sbeller@google.com> wrote:

> +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 (repo_init(&subrepo, sub_gitdir, sub_worktree))
> +		return;

If repo_init() fails, is it because the working tree doesn't exist on
disk, so we don't need to perform any connections on submodules? I think
a comment should be added to describe this.

> +
> +	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)
> +			/* submodule not checked out? */
> +			continue;
> +
> +		if (is_submodule_active(&subrepo, ce->name)) {

Optional: This could be combined with the previous "if" block, so that
the following lines don't need to be indented.

> +			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, 0);
> +			connect_wt_gitdir_in_nested(sub_wt.buf, sub_gd.buf);

What's the difference between having this call to
connect_wt_gitdir_in_nested() and just passing 1 instead of 0 to
connect_work_tree_and_git_dir()? I see that the latter uses absolute
paths, but that would seem to have the same effect. (If not, I think a
comment is warranted.)

> +
> +			strbuf_reset(&sub_wt);
> +			strbuf_reset(&sub_gd);

I think we normally write the resets before the strbuf_addf(), so that
it's clearer that sub_wt and sub_gd are meant to start from scratch in
every iteration.

Overall, this version of the patch is clearer - thanks.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCHv2 0/6] Moving submodules with nested submodules
  2018-03-28 17:24       ` [PATCHv2 0/6] Moving submodules with nested submodules Stefan Beller
                           ` (5 preceding siblings ...)
  2018-03-28 17:24         ` [PATCH 6/6] grep: remove "repo" arg from non-supporting funcs Stefan Beller
@ 2018-03-28 17:54         ` Jonathan Tan
  2018-03-28 22:35           ` [PATCHv3 " Stefan Beller
  6 siblings, 1 reply; 36+ messages in thread
From: Jonathan Tan @ 2018-03-28 17:54 UTC (permalink / raw)
  To: Stefan Beller; +Cc: gitster, bmwill, git, hvoigt, seanwbehan

On Wed, 28 Mar 2018 10:24:43 -0700
Stefan Beller <sbeller@google.com> wrote:

> * picked up Jonathans patch and added it as a nice finish of the series.
>   I did not see the need or aesthetic desire to put that patch earlier
>   in the series.

Thanks for picking up my patch. The aesthetic desire is to avoid what's
currently happening in PATCH 2/6 version 2, where we still have the
potentially confusing submodule_free() -> submodule_free(repo)
conversion, which is also later redone in PATCH 6/6 version 2
(submodule_free(repo) -> submodule_free(the_repository)). But I'll leave
the final decision to you.

Other than that, besides PATCH 5/6 (which I have already commented on),
everything looks good.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 5/6] submodule: fixup nested submodules after moving the submodule
  2018-03-28 17:35           ` Brandon Williams
@ 2018-03-28 19:08             ` Stefan Beller
  0 siblings, 0 replies; 36+ messages in thread
From: Stefan Beller @ 2018-03-28 19:08 UTC (permalink / raw)
  To: Brandon Williams
  Cc: Junio C Hamano, git, Heiko Voigt, Jonathan Tan, seanwbehan

>> +     if (repo_init(&subrepo, sub_gitdir, sub_worktree))
>> +             return;
>
> Note that in Duy's object-store series he made this function private
> (IIRC) so this will result in some clash of the two series.
>

Yes, that is the case.
I wonder if I'd rather revert to v1 where we only use the
submodule repo init, or if we revert b2f0eceecf (repository:
initialize the_repository in main(), 2018-03-03) partially to
have repo_init available.

I would think the approach with submodule init is a bit cleaner
though has some more lines of code, using just repo_init
seems easier, but we really have no use case for a separate
repo_init unless they are submodules. And here we ought to
check for the repo being a submodule.

Not yet sure which path to take.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCHv3 0/6] Moving submodules with nested submodules
  2018-03-28 17:54         ` [PATCHv2 0/6] Moving submodules with nested submodules Jonathan Tan
@ 2018-03-28 22:35           ` Stefan Beller
  2018-03-28 22:35             ` [PATCHv3 1/6] submodule.h: drop declaration of connect_work_tree_and_git_dir Stefan Beller
                               ` (6 more replies)
  0 siblings, 7 replies; 36+ messages in thread
From: Stefan Beller @ 2018-03-28 22:35 UTC (permalink / raw)
  To: jonathantanmy; +Cc: bmwill, git, gitster, hvoigt, sbeller, seanwbehan

v3:
* reordered patches to have Jonathans patch before submodule_free
* addressed Jonathans comments on patch 5.
* rebased on origin/sb/object-store to resolve a visibility conflict
  about repo_init being exposed outside of repository.c

v2:
* addressed memleaks and messy code in patch 5
* removed the extern keyword where applicable
* extended the commit message, stating we want to rename submodule_free
  in the future.
* picked up Jonathans patch and added it as a nice finish of the series.
  I did not see the need or aesthetic desire to put that patch earlier
  in the series.
  
Thanks,
Stefan

v1:

This fixes the bug reported in [1] ("Bug: moving submodules that have submodules
inside them causes a fatal error in git status")

[1] https://public-inbox.org/git/20180306192017.GA5797@riseup.net/

Thanks,
Stefan
Jonathan Tan (1):
  grep: remove "repo" arg from non-supporting funcs

Stefan Beller (5):
  submodule.h: drop declaration of connect_work_tree_and_git_dir
  submodule-config: allow submodule_free to handle arbitrary
    repositories
  submodule-config: add repository argument to submodule_from_{name,
    path}
  submodule-config: remove submodule_from_cache
  submodule: fixup nested submodules after moving the submodule

 .../technical/api-submodule-config.txt        |  2 +-
 builtin/grep.c                                | 14 ++---
 builtin/mv.c                                  |  6 +-
 builtin/submodule--helper.c                   | 17 +++---
 dir.c                                         | 60 ++++++++++++++++++-
 dir.h                                         | 12 +++-
 repository.c                                  |  8 +--
 repository.h                                  |  3 +
 submodule-config.c                            | 29 ++++-----
 submodule-config.h                            | 15 +++--
 submodule.c                                   | 40 +++++++------
 submodule.h                                   |  1 -
 t/helper/test-submodule-config.c              |  8 ++-
 t/t7001-mv.sh                                 |  2 +-
 unpack-trees.c                                |  2 +-
 15 files changed, 140 insertions(+), 79 deletions(-)

-- 
2.17.0.rc1.321.gba9d0f2565-goog


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCHv3 1/6] submodule.h: drop declaration of connect_work_tree_and_git_dir
  2018-03-28 22:35           ` [PATCHv3 " Stefan Beller
@ 2018-03-28 22:35             ` Stefan Beller
  2018-03-28 22:35             ` [PATCHv3 2/6] grep: remove "repo" arg from non-supporting funcs Stefan Beller
                               ` (5 subsequent siblings)
  6 siblings, 0 replies; 36+ messages in thread
From: Stefan Beller @ 2018-03-28 22:35 UTC (permalink / raw)
  To: jonathantanmy; +Cc: bmwill, git, gitster, hvoigt, sbeller, seanwbehan

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 <sbeller@google.com>
---
 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
-- 
2.17.0.rc1.321.gba9d0f2565-goog


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCHv3 2/6] grep: remove "repo" arg from non-supporting funcs
  2018-03-28 22:35           ` [PATCHv3 " Stefan Beller
  2018-03-28 22:35             ` [PATCHv3 1/6] submodule.h: drop declaration of connect_work_tree_and_git_dir Stefan Beller
@ 2018-03-28 22:35             ` Stefan Beller
  2018-03-28 22:35             ` [PATCHv3 3/6] submodule-config: allow submodule_free to handle arbitrary repositories Stefan Beller
                               ` (4 subsequent siblings)
  6 siblings, 0 replies; 36+ messages in thread
From: Stefan Beller @ 2018-03-28 22:35 UTC (permalink / raw)
  To: jonathantanmy; +Cc: bmwill, git, gitster, hvoigt, sbeller, seanwbehan

From: Jonathan Tan <jonathantanmy@google.com>

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 <jonathantanmy@google.com>
Signed-off-by: Stefan Beller <sbeller@google.com>
---
 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)
-- 
2.17.0.rc1.321.gba9d0f2565-goog


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCHv3 3/6] submodule-config: allow submodule_free to handle arbitrary repositories
  2018-03-28 22:35           ` [PATCHv3 " Stefan Beller
  2018-03-28 22:35             ` [PATCHv3 1/6] submodule.h: drop declaration of connect_work_tree_and_git_dir Stefan Beller
  2018-03-28 22:35             ` [PATCHv3 2/6] grep: remove "repo" arg from non-supporting funcs Stefan Beller
@ 2018-03-28 22:35             ` Stefan Beller
  2018-03-28 22:35             ` [PATCHv3 4/6] submodule-config: add repository argument to submodule_from_{name, path} Stefan Beller
                               ` (3 subsequent siblings)
  6 siblings, 0 replies; 36+ messages in thread
From: Stefan Beller @ 2018-03-28 22:35 UTC (permalink / raw)
  To: jonathantanmy; +Cc: bmwill, git, gitster, hvoigt, sbeller, seanwbehan

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 <sbeller@google.com>
---
 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);
 		}
-- 
2.17.0.rc1.321.gba9d0f2565-goog


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCHv3 4/6] submodule-config: add repository argument to submodule_from_{name, path}
  2018-03-28 22:35           ` [PATCHv3 " Stefan Beller
                               ` (2 preceding siblings ...)
  2018-03-28 22:35             ` [PATCHv3 3/6] submodule-config: allow submodule_free to handle arbitrary repositories Stefan Beller
@ 2018-03-28 22:35             ` Stefan Beller
  2018-03-28 22:35             ` [PATCHv3 5/6] submodule-config: remove submodule_from_cache Stefan Beller
                               ` (2 subsequent siblings)
  6 siblings, 0 replies; 36+ messages in thread
From: Stefan Beller @ 2018-03-28 22:35 UTC (permalink / raw)
  To: jonathantanmy; +Cc: bmwill, git, gitster, hvoigt, sbeller, seanwbehan

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 <jonathantanmy@google.com>
Signed-off-by: Stefan Beller <sbeller@google.com>
---
 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 <path>"));
 
-	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 @@ 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;
@@ -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.");
 
-- 
2.17.0.rc1.321.gba9d0f2565-goog


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCHv3 5/6] submodule-config: remove submodule_from_cache
  2018-03-28 22:35           ` [PATCHv3 " Stefan Beller
                               ` (3 preceding siblings ...)
  2018-03-28 22:35             ` [PATCHv3 4/6] submodule-config: add repository argument to submodule_from_{name, path} Stefan Beller
@ 2018-03-28 22:35             ` Stefan Beller
  2018-03-28 22:35             ` [PATCHv3 6/6] submodule: fixup nested submodules after moving the submodule Stefan Beller
  2018-03-28 23:17             ` [PATCHv3 0/6] Moving submodules with nested submodules Jonathan Tan
  6 siblings, 0 replies; 36+ messages in thread
From: Stefan Beller @ 2018-03-28 22:35 UTC (permalink / raw)
  To: jonathantanmy; +Cc: bmwill, git, gitster, hvoigt, sbeller, seanwbehan

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 <jonathantanmy@google.com>
Signed-off-by: Stefan Beller <sbeller@google.com>
---
 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) {
-- 
2.17.0.rc1.321.gba9d0f2565-goog


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCHv3 6/6] submodule: fixup nested submodules after moving the submodule
  2018-03-28 22:35           ` [PATCHv3 " Stefan Beller
                               ` (4 preceding siblings ...)
  2018-03-28 22:35             ` [PATCHv3 5/6] submodule-config: remove submodule_from_cache Stefan Beller
@ 2018-03-28 22:35             ` Stefan Beller
  2018-03-28 23:17             ` [PATCHv3 0/6] Moving submodules with nested submodules Jonathan Tan
  6 siblings, 0 replies; 36+ messages in thread
From: Stefan Beller @ 2018-03-28 22:35 UTC (permalink / raw)
  To: jonathantanmy; +Cc: bmwill, git, gitster, hvoigt, sbeller, seanwbehan

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 <sbeller@google.com>
---
 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 &&
-- 
2.17.0.rc1.321.gba9d0f2565-goog


^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCHv3 0/6] Moving submodules with nested submodules
  2018-03-28 22:35           ` [PATCHv3 " Stefan Beller
                               ` (5 preceding siblings ...)
  2018-03-28 22:35             ` [PATCHv3 6/6] submodule: fixup nested submodules after moving the submodule Stefan Beller
@ 2018-03-28 23:17             ` Jonathan Tan
  6 siblings, 0 replies; 36+ messages in thread
From: Jonathan Tan @ 2018-03-28 23:17 UTC (permalink / raw)
  To: Stefan Beller; +Cc: bmwill, git, gitster, hvoigt, seanwbehan

On Wed, 28 Mar 2018 15:35:25 -0700
Stefan Beller <sbeller@google.com> wrote:

> v3:
> * reordered patches to have Jonathans patch before submodule_free
> * addressed Jonathans comments on patch 5.
> * rebased on origin/sb/object-store to resolve a visibility conflict
>   about repo_init being exposed outside of repository.c

All 6 patches look good to me, thanks.

Reviewed-by: Jonathan Tan <jonathantanmy@google.com>

^ permalink raw reply	[flat|nested] 36+ messages in thread

end of thread, other threads:[~2018-03-28 23:17 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-03-27 21:39 [PATCH 0/5] Moving submodules with nested submodules Stefan Beller
2018-03-27 21:39 ` [PATCH 1/5] submodule.h: drop declaration of connect_work_tree_and_git_dir Stefan Beller
2018-03-27 21:39 ` [PATCH 2/5] submodule-config: allow submodule_free to handle arbitrary repositories Stefan Beller
2018-03-27 22:57   ` Brandon Williams
2018-03-27 22:58   ` [PATCH] grep: remove "repo" arg from non-supporting funcs Jonathan Tan
2018-03-27 23:20     ` Stefan Beller
2018-03-28  0:24       ` Jonathan Tan
2018-03-28  0:35         ` Stefan Beller
2018-03-27 21:39 ` [PATCH 3/5] submodule-config: add repository argument to submodule_from_{name, path} Stefan Beller
2018-03-27 23:04   ` Jonathan Tan
2018-03-27 23:53     ` Stefan Beller
2018-03-27 21:39 ` [PATCH 4/5] submodule-config: remove submodule_from_cache Stefan Beller
2018-03-27 23:07   ` Jonathan Tan
2018-03-27 21:39 ` [PATCH 5/5] submodule: fixup nested submodules after moving the submodule Stefan Beller
2018-03-27 23:25   ` Brandon Williams
2018-03-28  0:07   ` Jonathan Tan
2018-03-28  0:42     ` Stefan Beller
2018-03-28 17:24       ` [PATCHv2 0/6] Moving submodules with nested submodules Stefan Beller
2018-03-28 17:24         ` [PATCH 1/6] submodule.h: drop declaration of connect_work_tree_and_git_dir Stefan Beller
2018-03-28 17:24         ` [PATCH 2/6] submodule-config: allow submodule_free to handle arbitrary repositories Stefan Beller
2018-03-28 17:24         ` [PATCH 3/6] submodule-config: add repository argument to submodule_from_{name, path} Stefan Beller
2018-03-28 17:24         ` [PATCH 4/6] submodule-config: remove submodule_from_cache Stefan Beller
2018-03-28 17:24         ` [PATCH 5/6] submodule: fixup nested submodules after moving the submodule Stefan Beller
2018-03-28 17:35           ` Brandon Williams
2018-03-28 19:08             ` Stefan Beller
2018-03-28 17:46           ` Jonathan Tan
2018-03-28 17:24         ` [PATCH 6/6] grep: remove "repo" arg from non-supporting funcs Stefan Beller
2018-03-28 17:54         ` [PATCHv2 0/6] Moving submodules with nested submodules Jonathan Tan
2018-03-28 22:35           ` [PATCHv3 " Stefan Beller
2018-03-28 22:35             ` [PATCHv3 1/6] submodule.h: drop declaration of connect_work_tree_and_git_dir Stefan Beller
2018-03-28 22:35             ` [PATCHv3 2/6] grep: remove "repo" arg from non-supporting funcs Stefan Beller
2018-03-28 22:35             ` [PATCHv3 3/6] submodule-config: allow submodule_free to handle arbitrary repositories Stefan Beller
2018-03-28 22:35             ` [PATCHv3 4/6] submodule-config: add repository argument to submodule_from_{name, path} Stefan Beller
2018-03-28 22:35             ` [PATCHv3 5/6] submodule-config: remove submodule_from_cache Stefan Beller
2018-03-28 22:35             ` [PATCHv3 6/6] submodule: fixup nested submodules after moving the submodule Stefan Beller
2018-03-28 23:17             ` [PATCHv3 0/6] Moving submodules with nested submodules Jonathan Tan

git@vger.kernel.org list mirror (unofficial, one of many)

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://public-inbox.org/git
	git clone --mirror http://ou63pmih66umazou.onion/git
	git clone --mirror http://czquwvybam4bgbro.onion/git
	git clone --mirror http://hjrcffqmbrq6wope.onion/git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V1 git git/ https://public-inbox.org/git \
		git@vger.kernel.org
	public-inbox-index git

Example config snippet for mirrors.
Newsgroups are available over NNTP:
	nntp://news.public-inbox.org/inbox.comp.version-control.git
	nntp://ou63pmih66umazou.onion/inbox.comp.version-control.git
	nntp://czquwvybam4bgbro.onion/inbox.comp.version-control.git
	nntp://hjrcffqmbrq6wope.onion/inbox.comp.version-control.git
	nntp://news.gmane.io/gmane.comp.version-control.git
 note: .onion URLs require Tor: https://www.torproject.org/

code repositories for the project(s) associated with this inbox:

	https://80x24.org/mirrors/git.git

AGPL code for this site: git clone https://public-inbox.org/public-inbox.git