Re: [PATCHv6 7/7] submodule: add absorb-git-dir function

2016-12-08 Thread Duy Nguyen
On Thu, Dec 8, 2016 at 8:46 AM, Stefan Beller  wrote:
> diff --git a/dir.c b/dir.c
> index 8b74997c66..cc5729f733 100644
> --- a/dir.c
> +++ b/dir.c
> @@ -2774,3 +2774,15 @@ void connect_work_tree_and_git_dir(const char 
> *work_tree, const char *git_dir)
> free(real_work_tree);
> free(real_git_dir);
>  }
> +
> +/*
> + * Migrate the git directory of the given path from old_git_dir to 
> new_git_dir.
> + */
> +void relocate_gitdir(const char *path, const char *old_git_dir, const char 
> *new_git_dir)
> +{
> +   if (rename(old_git_dir, new_git_dir) < 0)
> +   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);
> +}

Thank you!
-- 
Duy


[PATCHv6 7/7] submodule: add absorb-git-dir function

2016-12-07 Thread Stefan Beller
When a submodule has its git dir inside the working dir, the submodule
support for checkout that we plan to add in a later patch will fail.

Add functionality to migrate the git directory to be absorbed
into the superprojects git directory.

The newly added code in this patch is structured such that other areas of
Git can also make use of it. The code in the submodule--helper is a mere
wrapper and option parser for the function
`absorb_git_dir_into_superproject`, that takes care of embedding the
submodules git directory into the superprojects git dir. That function
makes use of the more abstract function for this use case
`relocate_gitdir`, which can be used by e.g. the worktree code eventually
to move around a git directory.

Signed-off-by: Stefan Beller 
---
 Documentation/git-submodule.txt|  15 ++
 builtin/submodule--helper.c|  38 ++
 dir.c  |  12 +
 dir.h  |   3 ++
 git-submodule.sh   |   7 ++-
 submodule.c| 103 +
 submodule.h|   4 ++
 t/t7412-submodule-absorbgitdirs.sh | 101 
 8 files changed, 282 insertions(+), 1 deletion(-)
 create mode 100755 t/t7412-submodule-absorbgitdirs.sh

diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt
index d841573475..918bd1d1bd 100644
--- a/Documentation/git-submodule.txt
+++ b/Documentation/git-submodule.txt
@@ -22,6 +22,7 @@ SYNOPSIS
  [commit] [--] [...]
 'git submodule' [--quiet] foreach [--recursive] 
 'git submodule' [--quiet] sync [--recursive] [--] [...]
+'git submodule' [--quiet] absorbgitdirs [--] [...]
 
 
 DESCRIPTION
@@ -245,6 +246,20 @@ sync::
 If `--recursive` is specified, this command will recurse into the
 registered submodules, and sync any nested submodules within.
 
+absorbgitdirs::
+   If a git directory of a submodule is inside the submodule,
+   move the git directory of the submodule into its superprojects
+   `$GIT_DIR/modules` path and then connect the git directory and
+   its working directory by setting the `core.worktree` and adding
+   a .git file pointing to the git directory embedded in the
+   superprojects git directory.
++
+A repository that was cloned independently and later added as a submodule or
+old setups have the submodules git directory inside the submodule instead of
+embedded into the superprojects git directory.
++
+This command is recursive by default.
+
 OPTIONS
 ---
 -q::
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 33676a57cf..0108afac93 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -1076,6 +1076,43 @@ static int resolve_remote_submodule_branch(int argc, 
const char **argv,
return 0;
 }
 
+static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
+{
+   int i;
+   struct pathspec pathspec;
+   struct module_list list = MODULE_LIST_INIT;
+   unsigned flags = ABSORB_GITDIR_RECURSE_SUBMODULES;
+
+   struct option embed_gitdir_options[] = {
+   OPT_STRING(0, "prefix", ,
+  N_("path"),
+  N_("path into the working tree")),
+   OPT_BIT(0, "--recursive", , N_("recurse into submodules"),
+   ABSORB_GITDIR_RECURSE_SUBMODULES),
+   OPT_END()
+   };
+
+   const char *const git_submodule_helper_usage[] = {
+   N_("git submodule--helper embed-git-dir [...]"),
+   NULL
+   };
+
+   argc = parse_options(argc, argv, prefix, embed_gitdir_options,
+git_submodule_helper_usage, 0);
+
+   gitmodules_config();
+   git_config(submodule_config, NULL);
+
+   if (module_list_compute(argc, argv, prefix, , ) < 0)
+   return 1;
+
+   for (i = 0; i < list.nr; i++)
+   absorb_git_dir_into_superproject(prefix,
+   list.entries[i]->name, flags);
+
+   return 0;
+}
+
 #define SUPPORT_SUPER_PREFIX (1<<0)
 
 struct cmd_struct {
@@ -1094,6 +1131,7 @@ static struct cmd_struct commands[] = {
{"resolve-relative-url-test", resolve_relative_url_test, 0},
{"init", module_init, 0},
{"remote-branch", resolve_remote_submodule_branch, 0},
+   {"absorb-git-dirs", absorb_git_dirs, SUPPORT_SUPER_PREFIX},
 };
 
 int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
diff --git a/dir.c b/dir.c
index 8b74997c66..cc5729f733 100644
--- a/dir.c
+++ b/dir.c
@@ -2774,3 +2774,15 @@ void connect_work_tree_and_git_dir(const char 
*work_tree, const char *git_dir)
free(real_work_tree);
free(real_git_dir);
 }
+
+/*
+ * Migrate the git directory of the given path from old_git_dir to new_git_dir.
+ */
+void relocate_gitdir(const char *path, const char *old_git_dir,