threads / rfc / 26647

RFC patchinit, clone: support --real-git-dir for .git file

Subject: [PATCH/RFC] init, clone: support --real-git-dir for .git file

## tl;dr

15 messages between Mar 3, 2011 and Mar 4, 2011. Diffs are folded; open one to read it.

replies: 14people: 4as markdown or json

Nguyễn Thái Ngọc Duy· Mar 3, 2011, 12:43 UTC · lore

Instead of creating the repository at $GIT_DIR, --real-git-dir will tell git to put the repository there, then make $GIT_DIR a .git file that points to --real-git-dir.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 This makes '.git symbolic link' (what's its official name?) more
 convenient to use. Previously whenever I need to create a .git link,
 I need to open docs to see its format. Now all I need to do is
  git init --real-git-dir=/where/real/git/is
  git clone --real-git-dir=/where/real/git/is something
 I intend to make 'git init --real-git-dir' move current repo to
 somewhere else if called on existing repo.
 Long term I'd like to see a init/clone hook, where I can tell git
 "when I ask you to create a repo/worktree at foo, put the real repo
 at ~/git/foo"
 I could use a better option name too, any suggestions?
 builtin/clone.c   |    7 ++++++-
 builtin/init-db.c |   38 +++++++++++++++++++++++++++++++++++++-
 cache.h           |    1 +
 3 files changed, 44 insertions(+), 2 deletions(-)
Show changes to 3 files +44 −2

builtin/clone.c, builtin/init-db.c, cache.h

diff --git a/builtin/clone.c b/builtin/clone.c
index 60d9a64..74e487a 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -42,6 +42,7 @@ static int option_local, option_no_hardlinks, option_shared, option_recursive;
 static char *option_template, *option_reference, *option_depth;
 static char *option_origin = NULL;
 static char *option_branch = NULL;
+static const char *real_git_dir;
 static char *option_upload_pack = "git-upload-pack";
 static int option_verbosity;
 static int option_progress;
@@ -80,6 +81,8 @@ static struct option builtin_clone_options[] = {
 		   "path to git-upload-pack on the remote"),
 	OPT_STRING(0, "depth", &option_depth, "depth",
 		    "create a shallow clone of that depth"),
+	OPT_STRING(0, "real-git-dir", &real_git_dir, "git-dir",
+		   "directory where real repository is cloned to"),
 
 	OPT_END()
 };
@@ -466,7 +469,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 
 	if (safe_create_leading_directories_const(git_dir) < 0)
 		die("could not create leading directories of '%s'", git_dir);
-	set_git_dir(make_absolute_path(git_dir));
+	set_git_dir_init(git_dir, real_git_dir);
+	if (real_git_dir)
+		git_dir = real_git_dir;
 
 	if (0 <= option_verbosity)
 		printf("Cloning into %s%s...\n",
diff --git a/builtin/init-db.c b/builtin/init-db.c
index fbeb380..7a0fb50 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -21,6 +21,7 @@
 static int init_is_bare_repository = 0;
 static int init_shared_repository = -1;
 static const char *init_db_template_dir;
+static const char *git_link;
 
 static void safe_create_dir(const char *dir, int share)
 {
@@ -311,10 +312,42 @@ static void create_object_directory(void)
 	free(path);
 }
 
+int set_git_dir_init(const char *git_dir, const char *real_git_dir)
+{
+	if (real_git_dir) {
+		struct stat st;
+
+		if (!stat(git_dir, &st))
+			die("%s already exists", git_dir);
+		git_link = git_dir;
+	}
+	else {
+		real_git_dir = git_dir;
+		git_link = NULL;
+	}
+	set_git_dir(make_absolute_path(real_git_dir));
+	return 0;
+}
+
 int init_db(const char *template_dir, unsigned int flags)
 {
 	int reinit;
 
+	if (git_link) {
+		struct stat st;
+		FILE *fp;
+
+		/* TODO: allow --real-git-dir to move repo elsewhere */
+		if (!lstat(git_link, &st))
+			die("%s already exists", git_link);
+
+		fp = fopen(git_link, "w");
+		if (!fp)
+			die("Could not create git link %s", git_link);
+		fprintf(fp, "gitdir: %s\n", get_git_dir());
+		fclose(fp);
+	}
+
 	safe_create_dir(get_git_dir(), 0);
 
 	init_is_bare_repository = is_bare_repository();
@@ -414,6 +447,7 @@ static const char *const init_db_usage[] = {
 int cmd_init_db(int argc, const char **argv, const char *prefix)
 {
 	const char *git_dir;
+	const char *real_git_dir = NULL;
 	const char *work_tree;
 	const char *template_dir = NULL;
 	unsigned int flags = 0;
@@ -427,6 +461,8 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
 			"specify that the git repository is to be shared amongst several users",
 			PARSE_OPT_OPTARG | PARSE_OPT_NONEG, shared_callback, 0},
 		OPT_BIT('q', "quiet", &flags, "be quiet", INIT_DB_QUIET),
+		OPT_STRING(0, "real-git-dir", &real_git_dir, "git-dir",
+			   "directory where real .git is initialized"),
 		OPT_END()
 	};
 
@@ -522,7 +558,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
 			set_git_work_tree(make_absolute_path(work_tree));
 	}
 
-	set_git_dir(make_absolute_path(git_dir));
+	set_git_dir_init(git_dir, real_git_dir);
 
 	return init_db(template_dir, flags);
 }
diff --git a/cache.h b/cache.h
index 08a9022..0b006b8 100644
--- a/cache.h
+++ b/cache.h
@@ -436,6 +436,7 @@ extern void verify_non_filename(const char *prefix, const char *name);
 
 #define INIT_DB_QUIET 0x0001
 
+extern int set_git_dir_init(const char *git_dir, const char *real_git_dir);
 extern int init_db(const char *template_dir, unsigned int flags);
 
 #define alloc_nr(x) (((x)+16)*3/2)
-- 
1.7.4.74.g639db
Piotr Krukowiecki· Mar 3, 2011, 21:13 UTC · re: Nguyễn Thái Ngọc Duy · lore

Re: [PATCH/RFC] init, clone: support --real-git-dir for .git file

W dniu 03.03.2011 13:43, Nguyễn Thái Ngọc Duy pisze:
Show 9 quoted lines
> Instead of creating the repository at $GIT_DIR, --real-git-dir will
> tell git to put the repository there, then make $GIT_DIR a .git file
> that points to --real-git-dir.
> 
> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
> ---
>  This makes '.git symbolic link' (what's its official name?) more
>  convenient to use. Previously whenever I need to create a .git link,
>  I need to open docs to see its format. Now all I need to do is

Took me a while to find documentation for .git file format. Probably my fault, missed the gitrepository-layout link.

Anyway, tried following:
   $ echo path > .git
   $ git info
   fatal: Invalid gitfile format: .git
Maybe one solution is to improve the message - patch attached:
   $ git info
   fatal: Invalid gitfile format: .git
   Use gitdir: <PATH>
 
Show 9 quoted lines
>   git init --real-git-dir=/where/real/git/is
>   git clone --real-git-dir=/where/real/git/is something
> 
>  I intend to make 'git init --real-git-dir' move current repo to
>  somewhere else if called on existing repo.
> 
>  Long term I'd like to see a init/clone hook, where I can tell git
>  "when I ask you to create a repo/worktree at foo, put the real repo
>  at ~/git/foo"
Is this needed? As I understand
    git init --real-git-dir=/where/real/git/is
should do the same as
    git --git-dir=/where/real/git/is && \
    echo "gitdir: /where/real/git/is" > ${GIT_DIR:-.git} 
The other actions seems to be similarly simple.
>  I could use a better option name too, any suggestions?

I don't understand why is this needed. It's a bit complicated at first as well. Adds extra layer to already existing .gitdir/.gitfile/GIT_DIR/--git-dir

---8<---
From e83caf00dc007b9a2e515bb718f0d9ddb080891e Mon Sep 17 00:00:00 2001
From: Piotr Krukowiecki <piotr.krukowiecki@gmail.com>
Date: Thu, 3 Mar 2011 21:51:34 +0100
Subject: [PATCH] Improve error message when gitfile has wrong format
Add information what format of .git file is expected.
Signed-off-by: Piotr Krukowiecki <piotr.krukowiecki@gmail.com>
---
 setup.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
Show changes to setup.c +1 −1
diff --git a/setup.c b/setup.c
index 021d013..d2d9d0b 100644
--- a/setup.c
+++ b/setup.c
@@ -291,7 +291,7 @@ const char *read_gitfile_gently(const char *path)
 		die("Error reading %s", path);
 	buf[len] = '\0';
 	if (prefixcmp(buf, "gitdir: "))
-		die("Invalid gitfile format: %s", path);
+		die("Invalid gitfile format: %s\nUse gitdir: <PATH>", path);
 	while (buf[len - 1] == '\n' || buf[len - 1] == '\r')
 		len--;
 	if (len < 9)
-- 
1.7.1


-- 
Piotr Krukowiecki
Junio C Hamano· Mar 3, 2011, 23:31 UTC · re: Piotr Krukowiecki · lore

Re: [PATCH/RFC] init, clone: support --real-git-dir for .git file

Piotr Krukowiecki <piotr.krukowiecki@gmail.com> writes:
Show 5 quoted lines
> From: Piotr Krukowiecki <piotr.krukowiecki@gmail.com>
> Date: Thu, 3 Mar 2011 21:51:34 +0100
> Subject: [PATCH] Improve error message when gitfile has wrong format
>
> Add information what format of .git file is expected.

Don't do this. We don't want to _add_ places that needs to be updated when we need to update our internal implementation.

Piotr Krukowiecki· Mar 4, 2011, 07:41 UTC · re: Junio C Hamano · lore

Re: [PATCH/RFC] init, clone: support --real-git-dir for .git file

2011/3/4 Junio C Hamano <gitster@pobox.com>:
Show 10 quoted lines
> Piotr Krukowiecki <piotr.krukowiecki@gmail.com> writes:
>
>> From: Piotr Krukowiecki <piotr.krukowiecki@gmail.com>
>> Date: Thu, 3 Mar 2011 21:51:34 +0100
>> Subject: [PATCH] Improve error message when gitfile has wrong format
>>
>> Add information what format of .git file is expected.
>
> Don't do this.  We don't want to _add_ places that needs to be updated
> when we need to update our internal implementation.
I thought it was user-level file, like $GIT_DIR

I'm not into data duplication, but in this case the message is next to the previous use:

       if (prefixcmp(buf, "gitdir: "))
               die("Invalid gitfile format: %s\nUse gitdir: <PATH>", path);

BTW I think it might be enough to have just path in the .git file. If .git has path to a correct git repo then chances it's coincidence are quite low. (The format does not matter if it's internal file of course)

-- 
Piotrek
Nguyen Thai Ngoc Duy· Mar 4, 2011, 12:26 UTC · re: Piotr Krukowiecki · lore

Re: [PATCH/RFC] init, clone: support --real-git-dir for .git file

2011/3/4 Piotr Krukowiecki <piotr.krukowiecki@gmail.com>:
Show 13 quoted lines
> I thought it was user-level file, like $GIT_DIR
>
> I'm not into data duplication, but in this case the message is next to the
> previous use:
>
>       if (prefixcmp(buf, "gitdir: "))
>               die("Invalid gitfile format: %s\nUse gitdir: <PATH>", path);
>
>
> BTW I think it might be enough to have just path in the .git file. If
> .git has path
> to a correct git repo then chances it's coincidence are quite low.
> (The format does not matter if it's internal file of course)

It's actually good that path is prefixed by gitdir. I imagine once superproject is supported, .git file in subprojects will have another line

supergitdir: /path/to/superproject
-- 
Duy
Piotr Krukowiecki· Mar 4, 2011, 18:09 UTC · re: Nguyen Thai Ngoc Duy · lore

Re: [PATCH/RFC] init, clone: support --real-git-dir for .git file

On Fri, Mar 4, 2011 at 1:26 PM, Nguyen Thai Ngoc Duy <pclouds@gmail.com> wrote:
Show 20 quoted lines
> 2011/3/4 Piotr Krukowiecki <piotr.krukowiecki@gmail.com>:
>> I thought it was user-level file, like $GIT_DIR
>>
>> I'm not into data duplication, but in this case the message is next to the
>> previous use:
>>
>>       if (prefixcmp(buf, "gitdir: "))
>>               die("Invalid gitfile format: %s\nUse gitdir: <PATH>", path);
>>
>>
>> BTW I think it might be enough to have just path in the .git file. If
>> .git has path
>> to a correct git repo then chances it's coincidence are quite low.
>> (The format does not matter if it's internal file of course)
>
> It's actually good that path is prefixed by gitdir. I imagine once
> superproject is supported, .git file in subprojects will have another
> line
>
> supergitdir: /path/to/superproject

Why would it be better than keeping this information under .git/, in config or other specific file?

-- 
Piotrek
Junio C Hamano· Mar 4, 2011, 18:41 UTC · re: Nguyen Thai Ngoc Duy · lore

Re: [PATCH/RFC] init, clone: support --real-git-dir for .git file

Nguyen Thai Ngoc Duy <pclouds@gmail.com> writes:
Show 5 quoted lines
> It's actually good that path is prefixed by gitdir. I imagine once
> superproject is supported, .git file in subprojects will have another
> line
>
> supergitdir: /path/to/superproject

No. On a platform with usable symbolic links, you should also be able to solve "this version of the superproject has the submodule, but that version does not, and we checkout the other version" with symlinking .git without using a gitdir file at all, just like we can use .git/HEAD symlink to denote the current branch.

Also, gitdir file is not for sole consumption of the submodule feature. Keep separate things separate, and don't try to tie unrelated concepts together.

Nguyen Thai Ngoc Duy· Mar 4, 2011, 04:19 UTC · re: Piotr Krukowiecki · lore

Re: [PATCH/RFC] init, clone: support --real-git-dir for .git file

2011/3/4 Piotr Krukowiecki <piotr.krukowiecki@gmail.com>:
Show 6 quoted lines
>>  This makes '.git symbolic link' (what's its official name?) more
>>  convenient to use. Previously whenever I need to create a .git link,
>>  I need to open docs to see its format. Now all I need to do is
>
> Took me a while to find documentation for .git file format. Probably my
> fault, missed the gitrepository-layout link.

Exactly why I wrote this patch. I do remember there is a prefix before the path, but what is it? gitdir: or git-dir: or dir:? No I don't want to look at the document every time I need to create a link. Trial and error is not preferred either. Also manual manipulation on repos should be avoided if possible.

-- 
Duy
Junio C Hamano· Mar 4, 2011, 00:08 UTC · re: Nguyễn Thái Ngọc Duy · lore

Re: [PATCH/RFC] init, clone: support --real-git-dir for .git file

Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:
> Instead of creating the repository at $GIT_DIR, --real-git-dir will
> tell git to put the repository there, then make $GIT_DIR a .git file
> that points to --real-git-dir.

Just like you, I am also bad at naming things, so I cannot offhand suggest a better name, even though I _know_ --real-git-dir sounds horrible.

The naming aside, the feature is what we have wanted to have for a long time and is way overdue. Thanks for showing how small-impact the necessary changes are.

"submodule init subpro" should be able to use this to clone a submodule with:

	git clone --xxx=.git/modules/subpro.git subpro

When we need to switch to a revision without that submodule, after making sure that there is no precious file in subpro/ directory, we would:

	rm -rf subpro/

Now, what do we need to switch back to a revision with that submodule? It would involve something like this:

	... after checking if we already have .git/modules/subpro.git
        ... and seeing that we do ...
	mkdir subpro
	commit=$(git rev-parse :subpro)
        echo 'gitdir: ../.git/modules/subpro.git' >subpro/.git
	cd subpro && git checkout $commit^0

The above four lines packaged for "git submodule" script would be a useful thing to have, especially because then nobody has to write the "echo" part.

>  I intend to make 'git init --real-git-dir' move current repo to
>  somewhere else if called on existing repo.

I don't know if that is useful in real life. Do you have a concrete use case (like the one I showed an example above) in mind?

Miles Bader· Mar 4, 2011, 04:13 UTC · re: Junio C Hamano · lore

Re: [PATCH/RFC] init, clone: support --real-git-dir for .git file

Junio C Hamano <gitster@pobox.com> writes:
Show 6 quoted lines
>> Instead of creating the repository at $GIT_DIR, --real-git-dir will
>> tell git to put the repository there, then make $GIT_DIR a .git file
>> that points to --real-git-dir.
>
> Just like you, I am also bad at naming things, so I cannot offhand suggest
> a better name, even though I _know_ --real-git-dir sounds horrible.
--separate-git-dir  ?

[Terms like "separate source dir" and "separate build dir" seems to be common when talking about build systems, and it seems a somewhat similar situation -- separation of usually co-located information.]

-miles
-- 
It wasn't the Exxon Valdez captain's driving that caused the Alaskan oil spill.
It was yours.  [Greenpeace advertisement, New York Times, 25 February 1990]
Nguyen Thai Ngoc Duy· Mar 4, 2011, 04:33 UTC · re: Miles Bader · lore

Re: [PATCH/RFC] init, clone: support --real-git-dir for .git file

2011/3/4 Miles Bader <miles@gnu.org>:
Show 13 quoted lines
> Junio C Hamano <gitster@pobox.com> writes:
>>> Instead of creating the repository at $GIT_DIR, --real-git-dir will
>>> tell git to put the repository there, then make $GIT_DIR a .git file
>>> that points to --real-git-dir.
>>
>> Just like you, I am also bad at naming things, so I cannot offhand suggest
>> a better name, even though I _know_ --real-git-dir sounds horrible.
>
> --separate-git-dir  ?
>
> [Terms like "separate source dir" and "separate build dir" seems to be
> common when talking about build systems, and it seems a somewhat
> similar situation -- separation of usually co-located information.]
Sounds good.
-- 
Duy
Nguyen Thai Ngoc Duy· Mar 4, 2011, 04:23 UTC · re: Junio C Hamano · lore

Re: [PATCH/RFC] init, clone: support --real-git-dir for .git file

2011/3/4 Junio C Hamano <gitster@pobox.com>:
Show 5 quoted lines
>>  I intend to make 'git init --real-git-dir' move current repo to
>>  somewhere else if called on existing repo.
>
> I don't know if that is useful in real life.  Do you have a concrete use
> case (like the one I showed an example above) in mind?
Moving .git away from existing repos/worktrees I have.
-- 
Duy
Junio C Hamano· Mar 4, 2011, 06:00 UTC · re: Nguyen Thai Ngoc Duy · lore

Re: [PATCH/RFC] init, clone: support --real-git-dir for .git file

Nguyen Thai Ngoc Duy <pclouds@gmail.com> writes:
> Moving .git away from existing repos/worktrees I have.

You are only saying you want to move it, not saying why you want to move it.

That is not an explanation _why_ it is useful to be able to do so.
Nguyen Thai Ngoc Duy· Mar 4, 2011, 06:39 UTC · re: Junio C Hamano · lore

Re: [PATCH/RFC] init, clone: support --real-git-dir for .git file

On Fri, Mar 4, 2011 at 1:00 PM, Junio C Hamano <gitster@pobox.com> wrote:
Show 8 quoted lines
> Nguyen Thai Ngoc Duy <pclouds@gmail.com> writes:
>
>> Moving .git away from existing repos/worktrees I have.
>
> You are only saying you want to move it, not saying why you want to move
> it.
>
> That is not an explanation _why_ it is useful to be able to do so.

The same reason why I don't want to place .git close to worktree in the first place (paranoid, throwaway worktree, disk constraint...). If I'm going to make a policy that "there must be no .git under ~/w", new repos with --real-git-dir are ok, but what about old repos?

-- 
Duy
Miles Bader· Mar 4, 2011, 06:57 UTC · re: Junio C Hamano · lore

Re: [PATCH/RFC] init, clone: support --real-git-dir for .git file

Junio C Hamano <gitster@pobox.com> writes:
> You are only saying you want to move it, not saying why you want to move
> it.
>
> That is not an explanation _why_ it is useful to be able to do so.

Hmm, one scenario would be when you want to "manage" a work tree using a relatively-passive tool that might barf over the contents (large, weird, files...) of a .git dir. E.g., eclipse or something (well I guess eclipse might actually have direct git support these days, but you get the idea).

-Miles
-- 
Politeness, n. The most acceptable hypocrisy.

← back to recent threads