From: Ramkumar Ramachandra <artagnon@gmail.com>
To: Git List <git@vger.kernel.org>
Cc: Duy Nguyen <pclouds@gmail.com>, Jeff King <peff@peff.net>,
Junio C Hamano <gitster@pobox.com>
Subject: [RFC/PATCH] clone: introduce clone.submoduleGitDir to relocate $GITDIR
Date: Sun, 14 Apr 2013 00:53:27 +0530 [thread overview]
Message-ID: <1365881007-25731-1-git-send-email-artagnon@gmail.com> (raw)
This configuration variable comes into effect when 'git clone' is
invoked inside an existing git repository's worktree. When set,
instead of cloning the given repository as-is, it relocates the gitdir
of the repository to the path specified by this variable. This
setting is especially useful when working with submodules.
Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com>
---
Okay, so this is part of my evil plan to make 'git add' DTRT wrt
submodules, and deprecate 'git submodule add' (I have some code
written down, but this is a prerequisite: I don't like the
.git/modules nonsense).
Unfortunately, this patch is in pathetic shape and is an RFC for
three reasons:
1. I've used setup_git_directory_gently() at the start of
builtin/clone.c to check if I'm inside a git directory. This
breaks a lot of existing tests (I'm yet to understand these
failures fully).
2. setup_git_directory_gently() has the side-effect of changing the
current directory and calling set_git_work_tree(), both of which
must be done away with if we want the rest of clone.c to work.
I've hacked around the issue in a very dirty manner. What is the
solution to this?
3. I don't know how to test the case "clone.submoduleGitDir has no
effect outside a git repository", because our entire test
environment is a git repository. Even if I remove the .git
directory, we're still inside the soure tree's git repository.
What do I do about this? Even if we decide that this patch is
fundamentally unworkable, we should try to fix this issue so that
we can verify that a plain 'git clone' works outside a git
repository.
Thanks for reading. And I'm truly sorry for making you read through
such ugly code.
Documentation/config.txt | 11 +++++++++++
builtin/clone.c | 33 ++++++++++++++++++++++++++++++++-
environment.c | 11 -----------
t/t5702-clone-options.sh | 41 +++++++++++++++++++++++++++++++++++++++++
4 files changed, 84 insertions(+), 12 deletions(-)
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 3d750e0..aac26c3 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -798,6 +798,17 @@ clean.requireForce::
A boolean to make git-clean do nothing unless given -f
or -n. Defaults to true.
+clone.submoduleGitDir::
+ An absolute path on the filesystem where gitdirs of submodules
+ should be stored away safely. When not set, a 'git clone'
+ executed inside a git repository will do exactly what it does
+ outside a git repository. When set, a 'git clone' executed
+ inside a git repository will create the worktree in place of
+ the full repository, and put the object store in a
+ subdirectory of clone.submoduleGitDir, choosing the name to be
+ the "humanish" part of the source repository (`repo.git` for
+ `/path/to/repo.git` and `foo.git` for `host.xz:foo/.git`).
+
color.branch::
A boolean to enable/disable color in the output of
linkgit:git-branch[1]. May be set to `always`,
diff --git a/builtin/clone.c b/builtin/clone.c
index f9c380e..4a845a4 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -44,6 +44,7 @@ static char *option_template, *option_depth;
static char *option_origin = NULL;
static char *option_branch = NULL;
static const char *real_git_dir;
+static const char *submodule_gitdir;
static char *option_upload_pack = "git-upload-pack";
static int option_verbosity;
static int option_progress = -1;
@@ -707,12 +708,22 @@ static void write_refspec_config(const char* src_ref_prefix,
strbuf_release(&value);
}
+static int git_clone_config(const char *var, const char *value, void *cb)
+{
+ if (!strcmp(var, "clone.submodulegitdir")) {
+ git_config_string(&submodule_gitdir, var, value);
+ return 0;
+ }
+ return git_default_config(var, value, cb);
+}
+
int cmd_clone(int argc, const char **argv, const char *prefix)
{
int is_bundle = 0, is_local;
struct stat buf;
const char *repo_name, *repo, *work_tree, *git_dir;
- char *path, *dir;
+ char *path, *dir, *dest_git_dir;
+ char cwd[PATH_MAX];
int dest_exists;
const struct ref *refs, *remote_head;
const struct ref *remote_head_points_at;
@@ -725,6 +736,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
const char *src_ref_prefix = "refs/heads/";
struct remote *remote;
int err = 0, complete_refs_before_fetch = 1;
+ int nongit = 1;
struct refspec *refspec;
const char *fetch_pattern;
@@ -732,6 +744,14 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
junk_pid = getpid();
packet_trace_identity("clone");
+
+ /* setup_git_directory_gently without changing directories */
+ getcwd(cwd, sizeof(cwd) - 1);
+ setup_git_directory_gently(&nongit);
+ chdir(cwd);
+
+ git_config(git_clone_config, NULL);
+
argc = parse_options(argc, argv, prefix, builtin_clone_options,
builtin_clone_usage, 0);
@@ -785,6 +805,17 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
die(_("destination path '%s' already exists and is not "
"an empty directory."), dir);
+ if (!nongit && submodule_gitdir) {
+ char *user_path = expand_user_path(submodule_gitdir);
+ if (!user_path)
+ die(_("Unable to expand path in clone.submoduleGitDir: %s"), submodule_gitdir);
+ dest_git_dir = mkpathdup("%s/%s.git", user_path, dir);
+ if (!stat(dest_git_dir, &buf) && !is_empty_dir(dest_git_dir))
+ die(_("destination path '%s' already exists and is not "
+ "an empty directory."), dest_git_dir);
+ real_git_dir = dest_git_dir;
+ }
+
strbuf_addf(&reflog_msg, "clone: from %s", repo);
if (option_bare)
diff --git a/environment.c b/environment.c
index e2e75c1..9dce4c7 100644
--- a/environment.c
+++ b/environment.c
@@ -182,8 +182,6 @@ const char *strip_namespace(const char *namespaced_ref)
return namespaced_ref + namespace_len;
}
-static int git_work_tree_initialized;
-
/*
* Note. This works only before you used a work tree. This was added
* primarily to support git-clone to work in a new repository it just
@@ -191,15 +189,6 @@ static int git_work_tree_initialized;
*/
void set_git_work_tree(const char *new_work_tree)
{
- if (git_work_tree_initialized) {
- new_work_tree = real_path(new_work_tree);
- if (strcmp(new_work_tree, work_tree))
- die("internal error: work tree has already been set\n"
- "Current worktree: %s\nNew worktree: %s",
- work_tree, new_work_tree);
- return;
- }
- git_work_tree_initialized = 1;
work_tree = xstrdup(real_path(new_work_tree));
}
diff --git a/t/t5702-clone-options.sh b/t/t5702-clone-options.sh
index 02cb024..9b845d8 100755
--- a/t/t5702-clone-options.sh
+++ b/t/t5702-clone-options.sh
@@ -33,4 +33,45 @@ test_expect_success 'redirected clone -v' '
'
+test_expect_success 'clone.submoduleGitDir takes effect in a git repository' '
+ cd ~ &&
+ rm -rf bare newrepo superproject &&
+ mkdir bare &&
+ bare_path="$(pwd)/bare" &&
+ git init newrepo &&
+ (
+ cd newrepo &&
+ echo quux >foo &&
+ git add foo &&
+ git commit -m "Add foo"
+ ) &&
+ git init superproject &&
+ cd superproject &&
+ test_config clone.submoduleGitDir "$bare_path" &&
+ git clone ../newrepo &&
+ test_path_is_file newrepo/.git &&
+ cd ../bare/newrepo.git &&
+ git rev-parse --is-bare-repository
+'
+
+test_expect_success 'clone.submoduleGitDir path get tilde-expansion' '
+ cd ~ &&
+ rm -rf bare newrepo superproject &&
+ mkdir bare &&
+ git init newrepo &&
+ (
+ cd newrepo &&
+ echo quux >foo &&
+ git add foo &&
+ git commit -m "Add foo"
+ ) &&
+ git init superproject &&
+ cd superproject &&
+ test_config clone.submoduleGitDir ~/bare &&
+ git clone ../newrepo &&
+ test_path_is_file newrepo/.git &&
+ cd ../bare/newrepo.git &&
+ git rev-parse --is-bare-repository
+'
+
test_done
--
1.8.2.1.389.gcaa7d79.dirty
next reply other threads:[~2013-04-13 19:24 UTC|newest]
Thread overview: 41+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-04-13 19:23 Ramkumar Ramachandra [this message]
2013-04-15 1:28 ` [RFC/PATCH] clone: introduce clone.submoduleGitDir to relocate $GITDIR Junio C Hamano
2013-04-15 2:48 ` Junio C Hamano
2013-04-15 8:08 ` Ramkumar Ramachandra
2013-04-15 10:14 ` Junio C Hamano
2013-04-15 11:35 ` Ramkumar Ramachandra
2013-04-15 7:59 ` Ramkumar Ramachandra
2013-04-15 8:19 ` Ramkumar Ramachandra
2013-04-15 9:25 ` Duy Nguyen
2013-04-15 9:47 ` Ramkumar Ramachandra
2013-04-15 9:45 ` Junio C Hamano
2013-04-15 11:48 ` Ramkumar Ramachandra
2013-04-15 15:50 ` Marc Branchaud
2013-04-15 17:50 ` Junio C Hamano
2013-04-15 18:00 ` Ramkumar Ramachandra
2013-04-15 18:43 ` Jeff King
2013-04-15 20:52 ` Junio C Hamano
2013-04-16 8:13 ` Ramkumar Ramachandra
2013-04-16 15:39 ` Marc Branchaud
2013-04-15 18:50 ` Marc Branchaud
2013-04-16 8:17 ` Ramkumar Ramachandra
2013-04-16 15:46 ` Marc Branchaud
2013-04-15 18:43 ` Marc Branchaud
2013-04-15 18:50 ` Junio C Hamano
2013-04-15 20:32 ` Marc Branchaud
2013-04-15 20:56 ` Junio C Hamano
2013-04-16 8:21 ` Ramkumar Ramachandra
2013-04-16 15:46 ` Marc Branchaud
2013-04-15 17:50 ` Ramkumar Ramachandra
2013-04-16 2:58 ` Jonathan Nieder
2013-04-16 8:36 ` Ramkumar Ramachandra
2013-04-16 17:28 ` Junio C Hamano
2013-04-17 15:48 ` Jonathan Nieder
2013-04-17 10:22 ` Duy Nguyen
2013-04-17 10:53 ` Ramkumar Ramachandra
2013-04-17 10:59 ` Duy Nguyen
2013-04-17 11:13 ` Ramkumar Ramachandra
2013-04-17 11:36 ` Duy Nguyen
2013-04-17 15:02 ` Ramkumar Ramachandra
2013-04-17 23:01 ` Duy Nguyen
2013-04-17 17:18 ` Junio C Hamano
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1365881007-25731-1-git-send-email-artagnon@gmail.com \
--to=artagnon@gmail.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=pclouds@gmail.com \
--cc=peff@peff.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).