git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Global .git directory
@ 2010-04-27  5:14 Gerhard Wiesinger
  2010-04-27  9:59 ` Thomas Rast
  0 siblings, 1 reply; 17+ messages in thread
From: Gerhard Wiesinger @ 2010-04-27  5:14 UTC (permalink / raw)
  To: git

Hello,

I'm new to git and as far as I saw that feature is missing: Placing .git 
directory/repository on a central place for many git repositories. This 
feature ensures that data directories are kept clean from metadata of git.

I know the GIT_DIR environment variable but therefore environment has to 
be set for each repository which is IHMO not practicable. Therefore I 
suggest the following approach (which also overrides GIT_DIR when set):
#  Can be set globally for all users
export GIT_GLOBAL_DIR=$HOME/.git_global

When this environment variable is set git searches the repository in 
$HOME/.git_global/`pwd`
Example:
cd /home/gerhard/myproject
=> /home/gerhard/.git_global/home/gerhard/myproject/.git directory is used
cd /home/gerhard/myproject/subdir
=> /home/gerhard/.git_global/home/gerhard/myproject/.git directory is 
still used, base directory must also be searched for (algorithm must 
already be implemented)

I think this should be easy to implement on a centralized point.

Any feedback is welcome.

Thnx.

Ciao,
Gerhard

--
http://www.wiesinger.com/

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

* Re: Global .git directory
  2010-04-27  5:14 Global .git directory Gerhard Wiesinger
@ 2010-04-27  9:59 ` Thomas Rast
  2010-04-27 20:06   ` Gerhard Wiesinger
  0 siblings, 1 reply; 17+ messages in thread
From: Thomas Rast @ 2010-04-27  9:59 UTC (permalink / raw)
  To: Gerhard Wiesinger; +Cc: git

Gerhard Wiesinger wrote:
> Hello,
> 
> I'm new to git and as far as I saw that feature is missing: Placing .git 
> directory/repository on a central place for many git repositories. This 
> feature ensures that data directories are kept clean from metadata of git.
[...]
> I think this should be easy to implement on a centralized point.

What problem are you trying to solve, what solution are you
attempting, and why does the .git get in the way of your proposed
solution?

(In other words, please convince us that this is actually worth
having.)

-- 
Thomas Rast
trast@{inf,student}.ethz.ch

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

* Re: Global .git directory
  2010-04-27  9:59 ` Thomas Rast
@ 2010-04-27 20:06   ` Gerhard Wiesinger
  2010-04-27 20:26     ` Erik Faye-Lund
  2010-04-27 20:37     ` Jacob Helwig
  0 siblings, 2 replies; 17+ messages in thread
From: Gerhard Wiesinger @ 2010-04-27 20:06 UTC (permalink / raw)
  To: Thomas Rast; +Cc: git

[-- Attachment #1: Type: TEXT/PLAIN, Size: 1330 bytes --]

On Tue, 27 Apr 2010, Thomas Rast wrote:

> Gerhard Wiesinger wrote:
>> Hello,
>>
>> I'm new to git and as far as I saw that feature is missing: Placing .git
>> directory/repository on a central place for many git repositories. This
>> feature ensures that data directories are kept clean from metadata of git.
> [...]
>> I think this should be easy to implement on a centralized point.
>
> What problem are you trying to solve, what solution are you
> attempting, and why does the .git get in the way of your proposed
> solution?

I don't like metadata of the repository in MY file structure (e.g. .git in 
top directory, .svn in every directory in subversion, .hg in top 
directory) for several reasons:
1.) Searching might arise false results, longer output and takes longer 
(e.g. grep -ir string .)
2.) Making tarballs, diffs, etc.: One has to make ugly --exclude or some 
other workarounds when directories are traversed.
3.) From an archtectural point of view: It is not technically necessary to 
mix up user data with repository data.

> (In other words, please convince us that this is actually worth
> having.)

Ok, rather than convincing I've written a (fast) patch which works for 
me :-)

Any comments? Any (further) changes needed? Will you include it in main 
git?

Thnx.

Ciao,
Gerhard

--
http://www.wiesinger.com/

[-- Attachment #2: Type: TEXT/PLAIN, Size: 8545 bytes --]

diff --git a/builtin/init-db.c b/builtin/init-db.c
index edc40ff..a91e762 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -7,6 +7,7 @@
 #include "builtin.h"
 #include "exec_cmd.h"
 #include "parse-options.h"
+#include "environment.h"
 
 #ifndef DEFAULT_GIT_TEMPLATE_DIR
 #define DEFAULT_GIT_TEMPLATE_DIR "/usr/share/git-core/templates"
@@ -34,6 +35,27 @@ static void safe_create_dir(const char *dir, int share)
 		die("Could not make %s writable by group", dir);
 }
 
+static void mkdir_recusive(char *directory)
+{
+	char tmp[PATH_MAX+1];
+	char *p = NULL;
+	size_t len;
+
+	snprintf(tmp, sizeof(tmp), "%s", directory);
+	len = strlen(tmp);
+	if(is_dir_sep(tmp[len - 1]))
+		tmp[len - 1] = 0;
+
+	for(p = tmp + 1; *p; p++)
+		if(is_dir_sep(*p)) {
+			char c = *p;
+			*p = 0;
+			safe_create_dir(tmp, 1);
+			*p = c;
+		}
+	safe_create_dir(tmp,1);
+}
+
 static void copy_templates_1(char *path, int baselen,
 			     char *template, int template_baselen,
 			     DIR *dir)
@@ -473,7 +495,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
 	 * GIT_WORK_TREE makes sense only in conjunction with GIT_DIR
 	 * without --bare.  Catch the error early.
 	 */
-	git_dir = getenv(GIT_DIR_ENVIRONMENT);
+	git_dir = get_git_dir_from_environment();
 	if ((!git_dir || is_bare_repository_cfg == 1)
 	    && getenv(GIT_WORK_TREE_ENVIRONMENT))
 		die("%s (or --work-tree=<directory>) not allowed without "
@@ -490,7 +512,19 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
 	if (is_bare_repository_cfg < 0)
 		is_bare_repository_cfg = guess_repository_type(git_dir);
 
-	if (!is_bare_repository_cfg) {
+	if (is_git_dir_global_environment()) {
+		char *global_base_dir = get_git_dir_global_base_dir();
+		mkdir_recusive(global_base_dir);
+		if (!git_work_tree_cfg) {
+			git_work_tree_cfg = xcalloc(PATH_MAX, 1);
+			strncpy(git_work_tree_cfg, global_base_dir, PATH_MAX);
+		}
+		if (access(get_git_work_tree(), X_OK))
+			die_errno ("Cannot access work tree '%s'",
+				   get_git_work_tree());
+	}
+		
+	if (!is_bare_repository_cfg && !is_git_dir_global_environment()) {
 		if (git_dir) {
 			const char *git_dir_parent = strrchr(git_dir, '/');
 			if (git_dir_parent) {
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index 8fbf9d0..b64260f 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -9,6 +9,7 @@
 #include "quote.h"
 #include "builtin.h"
 #include "parse-options.h"
+#include "environment.h"
 
 #define DO_REVS		1
 #define DO_NOREV	2
@@ -642,7 +643,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
 				continue;
 			}
 			if (!strcmp(arg, "--git-dir")) {
-				const char *gitdir = getenv(GIT_DIR_ENVIRONMENT);
+				const char *gitdir = get_git_dir_from_environment();
 				static char cwd[PATH_MAX];
 				int len;
 				if (gitdir) {
diff --git a/cache.h b/cache.h
index 5eb0573..57a647d 100644
--- a/cache.h
+++ b/cache.h
@@ -372,6 +372,8 @@ static inline enum object_type object_type(unsigned int mode)
 }
 
 #define GIT_DIR_ENVIRONMENT "GIT_DIR"
+#define GIT_DIR_GLOBAL_ENVIRONMENT "GIT_DIR_GLOBAL"
+#define GIT_DIR_GLOBAL_SPECIAL_ROOT_DIRECTORY "/SPECIAL_ROOT_DIRECTORY"
 #define GIT_WORK_TREE_ENVIRONMENT "GIT_WORK_TREE"
 #define DEFAULT_GIT_DIR_ENVIRONMENT ".git"
 #define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY"
diff --git a/environment.c b/environment.c
index 876c5e5..d9768a9 100644
--- a/environment.c
+++ b/environment.c
@@ -8,6 +8,9 @@
  * are.
  */
 #include "cache.h"
+#include "setup.h"
+
+#define DIR_SEPARATOR "/"
 
 char git_default_email[MAX_GITNAME];
 char git_default_name[MAX_GITNAME];
@@ -80,9 +83,129 @@ const char * const local_repo_env[LOCAL_REPO_ENV_SIZE + 1] = {
 	NULL
 };
 
+char* path_shorten(char *path)
+{
+	int index = strlen(path);
+
+	while (index > 0) {
+		index--;
+		if (is_dir_sep(path[index])) {
+			path[index] = 0;
+			return path;
+		}
+	}
+
+	// should never get here
+	return "";
+}
+
+static char *get_dir_global_environment(void)
+{
+	return getenv(GIT_DIR_GLOBAL_ENVIRONMENT);
+}
+
+char *get_git_dir_global_base_dir(void)
+{
+	static char cwd_buf[PATH_MAX+1];
+	static char dir_global_buf[PATH_MAX+1];
+	static char git_dir_buf[PATH_MAX+1];
+	int global_environment_len = 0;
+	char *git_dir_global_environment = get_dir_global_environment();
+
+	if (!getcwd(cwd_buf, sizeof(cwd_buf)-1))
+		die_errno("Unable to read current working directory");
+
+	if (!is_absolute_path(git_dir_global_environment))
+		die_errno("Global environment variable" GIT_DIR_GLOBAL_ENVIRONMENT " needs absolute path!");
+
+	strncpy(dir_global_buf, git_dir_global_environment, sizeof(dir_global_buf));
+	global_environment_len = strlen(dir_global_buf);
+	if (is_dir_sep(dir_global_buf[global_environment_len]))
+		dir_global_buf[global_environment_len] = 0;
+
+	return mksnpath(git_dir_buf, sizeof(git_dir_buf), "%s%s", dir_global_buf, cwd_buf);
+}
+
+char *get_git_dir_from_global_environment(char *git_dir_global_environment)
+{
+	static char cwd_buf[PATH_MAX+1];
+	static char cwd_original_buf[PATH_MAX+1];
+	static char dir_global_buf[PATH_MAX+1];
+	static char git_dir_buf[PATH_MAX+1];
+	char *cwd = cwd_buf;
+	char *git_dir = git_dir_buf;
+	int found = 0;
+	int global_environment_len = 0;
+
+	if (!getcwd(cwd_buf, sizeof(cwd_buf)-1))
+		die_errno("Unable to read current working directory");
+
+	if (!is_absolute_path(git_dir_global_environment))
+		die_errno("Global environment variable" GIT_DIR_GLOBAL_ENVIRONMENT " needs absolute path!");
+
+	strncpy(dir_global_buf, git_dir_global_environment, sizeof(dir_global_buf));
+	global_environment_len = strlen(dir_global_buf);
+	if (is_dir_sep(dir_global_buf[global_environment_len]))
+		dir_global_buf[global_environment_len] = 0;
+
+	if (strlen(cwd) == 1 && is_dir_sep(cwd[0]))
+	{
+		// special case for / git repository
+		git_dir = mksnpath(git_dir_buf, sizeof(git_dir_buf), "%s%s" DIR_SEPARATOR "%s", dir_global_buf, GIT_DIR_GLOBAL_SPECIAL_ROOT_DIRECTORY, DEFAULT_GIT_DIR_ENVIRONMENT);
+		return git_dir;
+	}
+
+	strncpy(cwd_original_buf, cwd, sizeof(cwd_original_buf));
+
+	/*
+	 * Test in the following order (relative to the cwd):
+	 * - .git (file containing "gitdir: <path>")
+	 * - .git/
+	 * - ./ (bare)
+	 * - ../.git
+	 * - ../.git/
+	 * - ../ (bare)
+	 * - ../../.git/
+	 *   etc.
+	 */
+	for (;;) {
+		if (*cwd == '\0') {
+			break;
+		}
+
+		git_dir = mksnpath(git_dir_buf, sizeof(git_dir_buf), "%s%s" DIR_SEPARATOR "%s", dir_global_buf, cwd, DEFAULT_GIT_DIR_ENVIRONMENT);
+		if (is_git_directory(git_dir)) {
+			found = 1;
+			break;
+		}
+
+		cwd = path_shorten(cwd);
+	}
+
+	if (!found) {
+		git_dir = mksnpath(git_dir_buf, sizeof(git_dir_buf), "%s%s/%s", dir_global_buf, cwd_original_buf, DEFAULT_GIT_DIR_ENVIRONMENT);
+		return git_dir;
+	}
+
+	return git_dir;
+}
+
+int is_git_dir_global_environment(void)
+{
+	return (get_dir_global_environment() != NULL);
+}
+
+char *get_git_dir_from_environment(void)
+{
+	char *git_dir_global_environment = get_dir_global_environment();
+	if (git_dir_global_environment) return get_git_dir_from_global_environment(git_dir_global_environment);
+
+	return getenv(GIT_DIR_ENVIRONMENT);
+}
+
 static void setup_git_env(void)
 {
-	git_dir = getenv(GIT_DIR_ENVIRONMENT);
+	git_dir = get_git_dir_from_environment();
 	if (!git_dir)
 		git_dir = read_gitfile_gently(DEFAULT_GIT_DIR_ENVIRONMENT);
 	if (!git_dir)
diff --git a/setup.c b/setup.c
index 5716d90..6ee3a59 100644
--- a/setup.c
+++ b/setup.c
@@ -1,5 +1,6 @@
 #include "cache.h"
 #include "dir.h"
+#include "environment.h"
 
 static int inside_git_dir = -1;
 static int inside_work_tree = -1;
@@ -165,7 +166,7 @@ const char **get_pathspec(const char *prefix, const char **pathspec)
  *    a proper "ref:", or a regular file HEAD that has a properly
  *    formatted sha1 object name.
  */
-static int is_git_directory(const char *suspect)
+int is_git_directory(const char *suspect)
 {
 	char path[PATH_MAX];
 	size_t len = strlen(suspect);
@@ -337,7 +338,7 @@ const char *setup_git_directory_gently(int *nongit_ok)
 	 * to do any discovery, but we still do repository
 	 * validation.
 	 */
-	gitdirenv = getenv(GIT_DIR_ENVIRONMENT);
+	gitdirenv = get_git_dir_from_environment();
 	if (gitdirenv) {
 		if (PATH_MAX - 40 < strlen(gitdirenv))
 			die("'$%s' too big", GIT_DIR_ENVIRONMENT);

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

* Re: Global .git directory
  2010-04-27 20:06   ` Gerhard Wiesinger
@ 2010-04-27 20:26     ` Erik Faye-Lund
  2010-04-28  5:33       ` Gerhard Wiesinger
  2010-04-27 20:37     ` Jacob Helwig
  1 sibling, 1 reply; 17+ messages in thread
From: Erik Faye-Lund @ 2010-04-27 20:26 UTC (permalink / raw)
  To: Gerhard Wiesinger; +Cc: Thomas Rast, git

On Tue, Apr 27, 2010 at 10:06 PM, Gerhard Wiesinger <lists@wiesinger.com> wrote:
> On Tue, 27 Apr 2010, Thomas Rast wrote:
>> (In other words, please convince us that this is actually worth
>> having.)
>
> Ok, rather than convincing I've written a (fast) patch which works for me
> :-)
>
> Any comments? Any (further) changes needed? Will you include it in main git?

Please see Documentation/SubmittingPatches. It's difficult to comment
on a non-inlined patch.

-- 
Erik "kusma" Faye-Lund

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

* Re: Global .git directory
  2010-04-27 20:06   ` Gerhard Wiesinger
  2010-04-27 20:26     ` Erik Faye-Lund
@ 2010-04-27 20:37     ` Jacob Helwig
  1 sibling, 0 replies; 17+ messages in thread
From: Jacob Helwig @ 2010-04-27 20:37 UTC (permalink / raw)
  To: Gerhard Wiesinger; +Cc: Thomas Rast, git

On Tue, Apr 27, 2010 at 13:06, Gerhard Wiesinger <lists@wiesinger.com> wrote:
> I don't like metadata of the repository in MY file structure (e.g. .git in
> top directory, .svn in every directory in subversion, .hg in top directory)
> for several reasons:
> 1.) Searching might arise false results, longer output and takes longer
> (e.g. grep -ir string .)

Using ack, instead of grep is very handy here.  It'll automatically
skip common revision control directories, and (by default) only
searches known text file formats.  There is also "git grep".

> 2.) Making tarballs, diffs, etc.: One has to make ugly --exclude or some
> other workarounds when directories are traversed.

Making tarballs: Is there a reason not to just use git-archive?  You
don't need to make any ugly --exclude rules there, unless you're
trying to exclude things that you track in revision control.

Diffs: Is "git diff" not sufficient here?  If it's not, why isn't it?

> 3.) From an archtectural point of view: It is not technically necessary to
> mix up user data with repository data.
>

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

* Re: Global .git directory
  2010-04-27 20:26     ` Erik Faye-Lund
@ 2010-04-28  5:33       ` Gerhard Wiesinger
  2010-04-28  6:22         ` Tomas Carnecky
                           ` (2 more replies)
  0 siblings, 3 replies; 17+ messages in thread
From: Gerhard Wiesinger @ 2010-04-28  5:33 UTC (permalink / raw)
  To: kusmabite; +Cc: Thomas Rast, git

[-- Attachment #1: Type: TEXT/PLAIN, Size: 1380 bytes --]

On Tue, 27 Apr 2010, Erik Faye-Lund wrote:

> On Tue, Apr 27, 2010 at 10:06 PM, Gerhard Wiesinger <lists@wiesinger.com> wrote:
>> On Tue, 27 Apr 2010, Thomas Rast wrote:
>>> (In other words, please convince us that this is actually worth
>>> having.)
>>
>> Ok, rather than convincing I've written a (fast) patch which works for me
>> :-)
>>
>> Any comments? Any (further) changes needed? Will you include it in main git?
>
> Please see Documentation/SubmittingPatches. It's difficult to comment
> on a non-inlined patch.
>

Patch done on top of HEAD.
git format-patch -M origin/master
0001-Added-global-git-directory-when-environment-variable.patch
0002-Added-global-git-directory-when-environment-variable.patch
0003-Updated-documentation-for-submitting-patches.patch
Attached.

BTW: The tutorial on http://git-scm.com/ is IHMO wrong:
git --version
git version 1.6.2.5
git commit -m 'Explain what I changed'
=>
git commit -a -m 'Explain what I changed'
=> Otherwise changed files are not committed, only added ones.
=> Therefore that are 2 commit ...

BTW2:
Why is it necessary to do:
# Displays only changed files
git diff
# Displays only added files
git diff --cached

I would like to have a full diff of my changes:
git diff -a
(or better "git diff -a" should be the default behaviour, I think 
that's very confusing for new users)

Ciao,
Gerhard

--
http://www.wiesinger.com/

[-- Attachment #2: Type: TEXT/PLAIN, Size: 1103 bytes --]

From 87cc9d17ec52a6ff2b71b9851c5b61f9e1da72be Mon Sep 17 00:00:00 2001
From: Gerhard Wiesinger <lists@wiesinger.com>
Date: Wed, 28 Apr 2010 06:46:28 +0200
Subject: [PATCH 1/2] Added global git directory when environment variable GIT_DIR_GLOBAL is set, e.g. export GIT_DIR_GLOBAL=/home/gerhard/.git_global

---
 environment.h |    8 ++++++++
 setup.h       |    6 ++++++
 2 files changed, 14 insertions(+), 0 deletions(-)
 create mode 100644 environment.h
 create mode 100644 setup.h

diff --git a/environment.h b/environment.h
new file mode 100644
index 0000000..fb6a368
--- /dev/null
+++ b/environment.h
@@ -0,0 +1,8 @@
+#ifndef ENVIRONMENT_H
+#define ENVIRONMENT_H
+
+char *get_git_dir_global_base_dir(void);
+char *get_git_dir_from_environment(void);
+int is_git_dir_global_environment(void);
+
+#endif /* ENVIRONMENT_H */
diff --git a/setup.h b/setup.h
new file mode 100644
index 0000000..2047ba5
--- /dev/null
+++ b/setup.h
@@ -0,0 +1,6 @@
+#ifndef SETUP_H
+#define SETUP_H
+
+int is_git_directory(const char *suspect);
+
+#endif /* SETUP_H */
-- 
1.6.2.5


[-- Attachment #3: Type: TEXT/PLAIN, Size: 9163 bytes --]

From ac2dfd8fcbbafafa92e68b17cb9c419aad0134ed Mon Sep 17 00:00:00 2001
From: Gerhard Wiesinger <lists@wiesinger.com>
Date: Wed, 28 Apr 2010 07:13:09 +0200
Subject: [PATCH 2/2] Added global git directory when environment variable GIT_DIR_GLOBAL is set, missing files, e.g. export GIT_DIR_GLOBAL=${HOME}/.git_global

---
 builtin/init-db.c   |   38 +++++++++++++++-
 builtin/rev-parse.c |    3 +-
 cache.h             |    2 +
 environment.c       |  125 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 setup.c             |    5 +-
 5 files changed, 167 insertions(+), 6 deletions(-)

diff --git a/builtin/init-db.c b/builtin/init-db.c
index edc40ff..a91e762 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -7,6 +7,7 @@
 #include "builtin.h"
 #include "exec_cmd.h"
 #include "parse-options.h"
+#include "environment.h"
 
 #ifndef DEFAULT_GIT_TEMPLATE_DIR
 #define DEFAULT_GIT_TEMPLATE_DIR "/usr/share/git-core/templates"
@@ -34,6 +35,27 @@ static void safe_create_dir(const char *dir, int share)
 		die("Could not make %s writable by group", dir);
 }
 
+static void mkdir_recusive(char *directory)
+{
+	char tmp[PATH_MAX+1];
+	char *p = NULL;
+	size_t len;
+
+	snprintf(tmp, sizeof(tmp), "%s", directory);
+	len = strlen(tmp);
+	if(is_dir_sep(tmp[len - 1]))
+		tmp[len - 1] = 0;
+
+	for(p = tmp + 1; *p; p++)
+		if(is_dir_sep(*p)) {
+			char c = *p;
+			*p = 0;
+			safe_create_dir(tmp, 1);
+			*p = c;
+		}
+	safe_create_dir(tmp,1);
+}
+
 static void copy_templates_1(char *path, int baselen,
 			     char *template, int template_baselen,
 			     DIR *dir)
@@ -473,7 +495,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
 	 * GIT_WORK_TREE makes sense only in conjunction with GIT_DIR
 	 * without --bare.  Catch the error early.
 	 */
-	git_dir = getenv(GIT_DIR_ENVIRONMENT);
+	git_dir = get_git_dir_from_environment();
 	if ((!git_dir || is_bare_repository_cfg == 1)
 	    && getenv(GIT_WORK_TREE_ENVIRONMENT))
 		die("%s (or --work-tree=<directory>) not allowed without "
@@ -490,7 +512,19 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
 	if (is_bare_repository_cfg < 0)
 		is_bare_repository_cfg = guess_repository_type(git_dir);
 
-	if (!is_bare_repository_cfg) {
+	if (is_git_dir_global_environment()) {
+		char *global_base_dir = get_git_dir_global_base_dir();
+		mkdir_recusive(global_base_dir);
+		if (!git_work_tree_cfg) {
+			git_work_tree_cfg = xcalloc(PATH_MAX, 1);
+			strncpy(git_work_tree_cfg, global_base_dir, PATH_MAX);
+		}
+		if (access(get_git_work_tree(), X_OK))
+			die_errno ("Cannot access work tree '%s'",
+				   get_git_work_tree());
+	}
+		
+	if (!is_bare_repository_cfg && !is_git_dir_global_environment()) {
 		if (git_dir) {
 			const char *git_dir_parent = strrchr(git_dir, '/');
 			if (git_dir_parent) {
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index 8fbf9d0..b64260f 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -9,6 +9,7 @@
 #include "quote.h"
 #include "builtin.h"
 #include "parse-options.h"
+#include "environment.h"
 
 #define DO_REVS		1
 #define DO_NOREV	2
@@ -642,7 +643,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
 				continue;
 			}
 			if (!strcmp(arg, "--git-dir")) {
-				const char *gitdir = getenv(GIT_DIR_ENVIRONMENT);
+				const char *gitdir = get_git_dir_from_environment();
 				static char cwd[PATH_MAX];
 				int len;
 				if (gitdir) {
diff --git a/cache.h b/cache.h
index 5eb0573..57a647d 100644
--- a/cache.h
+++ b/cache.h
@@ -372,6 +372,8 @@ static inline enum object_type object_type(unsigned int mode)
 }
 
 #define GIT_DIR_ENVIRONMENT "GIT_DIR"
+#define GIT_DIR_GLOBAL_ENVIRONMENT "GIT_DIR_GLOBAL"
+#define GIT_DIR_GLOBAL_SPECIAL_ROOT_DIRECTORY "/SPECIAL_ROOT_DIRECTORY"
 #define GIT_WORK_TREE_ENVIRONMENT "GIT_WORK_TREE"
 #define DEFAULT_GIT_DIR_ENVIRONMENT ".git"
 #define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY"
diff --git a/environment.c b/environment.c
index 876c5e5..d9768a9 100644
--- a/environment.c
+++ b/environment.c
@@ -8,6 +8,9 @@
  * are.
  */
 #include "cache.h"
+#include "setup.h"
+
+#define DIR_SEPARATOR "/"
 
 char git_default_email[MAX_GITNAME];
 char git_default_name[MAX_GITNAME];
@@ -80,9 +83,129 @@ const char * const local_repo_env[LOCAL_REPO_ENV_SIZE + 1] = {
 	NULL
 };
 
+char* path_shorten(char *path)
+{
+	int index = strlen(path);
+
+	while (index > 0) {
+		index--;
+		if (is_dir_sep(path[index])) {
+			path[index] = 0;
+			return path;
+		}
+	}
+
+	// should never get here
+	return "";
+}
+
+static char *get_dir_global_environment(void)
+{
+	return getenv(GIT_DIR_GLOBAL_ENVIRONMENT);
+}
+
+char *get_git_dir_global_base_dir(void)
+{
+	static char cwd_buf[PATH_MAX+1];
+	static char dir_global_buf[PATH_MAX+1];
+	static char git_dir_buf[PATH_MAX+1];
+	int global_environment_len = 0;
+	char *git_dir_global_environment = get_dir_global_environment();
+
+	if (!getcwd(cwd_buf, sizeof(cwd_buf)-1))
+		die_errno("Unable to read current working directory");
+
+	if (!is_absolute_path(git_dir_global_environment))
+		die_errno("Global environment variable" GIT_DIR_GLOBAL_ENVIRONMENT " needs absolute path!");
+
+	strncpy(dir_global_buf, git_dir_global_environment, sizeof(dir_global_buf));
+	global_environment_len = strlen(dir_global_buf);
+	if (is_dir_sep(dir_global_buf[global_environment_len]))
+		dir_global_buf[global_environment_len] = 0;
+
+	return mksnpath(git_dir_buf, sizeof(git_dir_buf), "%s%s", dir_global_buf, cwd_buf);
+}
+
+char *get_git_dir_from_global_environment(char *git_dir_global_environment)
+{
+	static char cwd_buf[PATH_MAX+1];
+	static char cwd_original_buf[PATH_MAX+1];
+	static char dir_global_buf[PATH_MAX+1];
+	static char git_dir_buf[PATH_MAX+1];
+	char *cwd = cwd_buf;
+	char *git_dir = git_dir_buf;
+	int found = 0;
+	int global_environment_len = 0;
+
+	if (!getcwd(cwd_buf, sizeof(cwd_buf)-1))
+		die_errno("Unable to read current working directory");
+
+	if (!is_absolute_path(git_dir_global_environment))
+		die_errno("Global environment variable" GIT_DIR_GLOBAL_ENVIRONMENT " needs absolute path!");
+
+	strncpy(dir_global_buf, git_dir_global_environment, sizeof(dir_global_buf));
+	global_environment_len = strlen(dir_global_buf);
+	if (is_dir_sep(dir_global_buf[global_environment_len]))
+		dir_global_buf[global_environment_len] = 0;
+
+	if (strlen(cwd) == 1 && is_dir_sep(cwd[0]))
+	{
+		// special case for / git repository
+		git_dir = mksnpath(git_dir_buf, sizeof(git_dir_buf), "%s%s" DIR_SEPARATOR "%s", dir_global_buf, GIT_DIR_GLOBAL_SPECIAL_ROOT_DIRECTORY, DEFAULT_GIT_DIR_ENVIRONMENT);
+		return git_dir;
+	}
+
+	strncpy(cwd_original_buf, cwd, sizeof(cwd_original_buf));
+
+	/*
+	 * Test in the following order (relative to the cwd):
+	 * - .git (file containing "gitdir: <path>")
+	 * - .git/
+	 * - ./ (bare)
+	 * - ../.git
+	 * - ../.git/
+	 * - ../ (bare)
+	 * - ../../.git/
+	 *   etc.
+	 */
+	for (;;) {
+		if (*cwd == '\0') {
+			break;
+		}
+
+		git_dir = mksnpath(git_dir_buf, sizeof(git_dir_buf), "%s%s" DIR_SEPARATOR "%s", dir_global_buf, cwd, DEFAULT_GIT_DIR_ENVIRONMENT);
+		if (is_git_directory(git_dir)) {
+			found = 1;
+			break;
+		}
+
+		cwd = path_shorten(cwd);
+	}
+
+	if (!found) {
+		git_dir = mksnpath(git_dir_buf, sizeof(git_dir_buf), "%s%s/%s", dir_global_buf, cwd_original_buf, DEFAULT_GIT_DIR_ENVIRONMENT);
+		return git_dir;
+	}
+
+	return git_dir;
+}
+
+int is_git_dir_global_environment(void)
+{
+	return (get_dir_global_environment() != NULL);
+}
+
+char *get_git_dir_from_environment(void)
+{
+	char *git_dir_global_environment = get_dir_global_environment();
+	if (git_dir_global_environment) return get_git_dir_from_global_environment(git_dir_global_environment);
+
+	return getenv(GIT_DIR_ENVIRONMENT);
+}
+
 static void setup_git_env(void)
 {
-	git_dir = getenv(GIT_DIR_ENVIRONMENT);
+	git_dir = get_git_dir_from_environment();
 	if (!git_dir)
 		git_dir = read_gitfile_gently(DEFAULT_GIT_DIR_ENVIRONMENT);
 	if (!git_dir)
diff --git a/setup.c b/setup.c
index 5716d90..6ee3a59 100644
--- a/setup.c
+++ b/setup.c
@@ -1,5 +1,6 @@
 #include "cache.h"
 #include "dir.h"
+#include "environment.h"
 
 static int inside_git_dir = -1;
 static int inside_work_tree = -1;
@@ -165,7 +166,7 @@ const char **get_pathspec(const char *prefix, const char **pathspec)
  *    a proper "ref:", or a regular file HEAD that has a properly
  *    formatted sha1 object name.
  */
-static int is_git_directory(const char *suspect)
+int is_git_directory(const char *suspect)
 {
 	char path[PATH_MAX];
 	size_t len = strlen(suspect);
@@ -337,7 +338,7 @@ const char *setup_git_directory_gently(int *nongit_ok)
 	 * to do any discovery, but we still do repository
 	 * validation.
 	 */
-	gitdirenv = getenv(GIT_DIR_ENVIRONMENT);
+	gitdirenv = get_git_dir_from_environment();
 	if (gitdirenv) {
 		if (PATH_MAX - 40 < strlen(gitdirenv))
 			die("'$%s' too big", GIT_DIR_ENVIRONMENT);
-- 
1.6.2.5


[-- Attachment #4: Type: TEXT/PLAIN, Size: 897 bytes --]

From cca30ca806f9758bb0271f08808e2c830d9aba5e Mon Sep 17 00:00:00 2001
From: Gerhard Wiesinger <lists@wiesinger.com>
Date: Wed, 28 Apr 2010 07:30:01 +0200
Subject: [PATCH 3/3] Updated documentation for submitting patches

---
 Documentation/SubmittingPatches |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
index abc65de..e871032 100644
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -23,7 +23,7 @@ Checklist (and a short version for the impatient):
 
 	Patch:
 
-	- use "git format-patch -M" to create the patch
+	- use "git format-patch -M" to create the patch (e.g. git format-patch -M origin/master)
 	- do not PGP sign your patch
 	- do not attach your patch, but read in the mail
 	  body, unless you cannot teach your mailer to
-- 
1.6.2.5


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

* Re: Global .git directory
  2010-04-28  5:33       ` Gerhard Wiesinger
@ 2010-04-28  6:22         ` Tomas Carnecky
  2010-04-28 20:03           ` Gerhard Wiesinger
  2010-04-28  8:01         ` Alex Riesen
  2010-04-28 12:50         ` Erik Faye-Lund
  2 siblings, 1 reply; 17+ messages in thread
From: Tomas Carnecky @ 2010-04-28  6:22 UTC (permalink / raw)
  To: Gerhard Wiesinger; +Cc: kusmabite, Thomas Rast, git

On 4/28/10 7:33 AM, Gerhard Wiesinger wrote:
> BTW: The tutorial on http://git-scm.com/ is IHMO wrong:
> git --version
> git version 1.6.2.5
> git commit -m 'Explain what I changed'
> =>
> git commit -a -m 'Explain what I changed'
> => Otherwise changed files are not committed, only added ones.
> => Therefore that are 2 commit ...

If you mean the snippets right on the front page, it assumes that you 
add all edited files.

> BTW2:
> Why is it necessary to do:
> # Displays only changed files
> git diff
> # Displays only added files
> git diff --cached
>
> I would like to have a full diff of my changes:
> git diff -a
> (or better "git diff -a" should be the default behaviour, I think that's
> very confusing for new users)

What are 'your' changes? Between HEAD and the working tree (aka. git 
diff HEAD)?

tom

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

* Re: Global .git directory
  2010-04-28  5:33       ` Gerhard Wiesinger
  2010-04-28  6:22         ` Tomas Carnecky
@ 2010-04-28  8:01         ` Alex Riesen
  2010-04-28 20:10           ` Gerhard Wiesinger
  2010-04-28 12:50         ` Erik Faye-Lund
  2 siblings, 1 reply; 17+ messages in thread
From: Alex Riesen @ 2010-04-28  8:01 UTC (permalink / raw)
  To: Gerhard Wiesinger; +Cc: kusmabite, Thomas Rast, git

On Wed, Apr 28, 2010 at 07:33, Gerhard Wiesinger <lists@wiesinger.com> wrote:
> On Tue, 27 Apr 2010, Erik Faye-Lund wrote:
>> Please see Documentation/SubmittingPatches. It's difficult to
>> comment on a non-inlined patch.
>
> Patch done on top of HEAD.

The patches "done on top of HEAD" are usually useless for
everyone, including the submitter. HEAD changes over time.
for instance I wont be able to apply your patches on my HEAD,
as I have a lot of changes in my Git repo.

If you about to share your modifications, you better base your
changes on stable points in history, like releases (marked by
release tags, like "v1.7.1").

> BTW2:
> Why is it necessary to do:

It is so you can distinguish between the changes in progress and
the changes ready to be submitted (prepared for commit).

> # Displays only changed files
> git diff

To be exact: the changes not yet staged for commit.

> # Displays only added files
> git diff --cached

No, it displays the changes ready to be committed (staged).

> I would like to have a full diff of my changes:
> git diff -a

You wouldn't use it. It is very useful to separate the phases of workflow.

BTW, try using "git status". It'll show you both lists of changed files.
Also "git gui", and "gitk" make the lists visible ("git gui" is more like
"git status", and you can commit from it).

> (or better "git diff -a" should be the default behaviour, I think that's
> very confusing for new users)

Only to unwilling to learn. You'd be probably the first to suggest
to combine the two stages of change. Usually people understand
(or get a feeling of understanding) the index even before they send
first mail to the mailing list.

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

* Re: Global .git directory
  2010-04-28  5:33       ` Gerhard Wiesinger
  2010-04-28  6:22         ` Tomas Carnecky
  2010-04-28  8:01         ` Alex Riesen
@ 2010-04-28 12:50         ` Erik Faye-Lund
  2010-04-28 20:22           ` Gerhard Wiesinger
  2 siblings, 1 reply; 17+ messages in thread
From: Erik Faye-Lund @ 2010-04-28 12:50 UTC (permalink / raw)
  To: Gerhard Wiesinger; +Cc: Thomas Rast, git

On Wed, Apr 28, 2010 at 7:33 AM, Gerhard Wiesinger <lists@wiesinger.com> wrote:
> On Tue, 27 Apr 2010, Erik Faye-Lund wrote:
>
>> On Tue, Apr 27, 2010 at 10:06 PM, Gerhard Wiesinger <lists@wiesinger.com>
>> wrote:
>>>
>>> On Tue, 27 Apr 2010, Thomas Rast wrote:
>>>>
>>>> (In other words, please convince us that this is actually worth
>>>> having.)
>>>
>>> Ok, rather than convincing I've written a (fast) patch which works for me
>>> :-)
>>>
>>> Any comments? Any (further) changes needed? Will you include it in main
>>> git?
>>
>> Please see Documentation/SubmittingPatches. It's difficult to comment
>> on a non-inlined patch.
>>
>
> Patch done on top of HEAD.
> git format-patch -M origin/master
> 0001-Added-global-git-directory-when-environment-variable.patch
> 0002-Added-global-git-directory-when-environment-variable.patch
> 0003-Updated-documentation-for-submitting-patches.patch
> Attached.
>

I was referring to that you sent the patch attached instead of inlined
(as Documentation/SubmittingPatches suggests).

By attaching patches you force everyone who wants to review the patch
to have to copy and manually quote the parts of the patch that they
have comments about instead of automatic quoting like all decent
e-mail clients do. That way you get less people interested in the
patch.

I sent this reply because you did the right thing of cooking up a
patch in the first place (as opposed to just arguing - very good), so
I think you deserve a chance of getting the patch reviewed (and
possibly included... if people agree with you, that is).

-- 
Erik "kusma" Faye-Lund

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

* Re: Global .git directory
  2010-04-28  6:22         ` Tomas Carnecky
@ 2010-04-28 20:03           ` Gerhard Wiesinger
  0 siblings, 0 replies; 17+ messages in thread
From: Gerhard Wiesinger @ 2010-04-28 20:03 UTC (permalink / raw)
  To: Tomas Carnecky; +Cc: kusmabite, Thomas Rast, git




--
http://www.wiesinger.com/


On Wed, 28 Apr 2010, Tomas Carnecky wrote:

> On 4/28/10 7:33 AM, Gerhard Wiesinger wrote:
>> BTW: The tutorial on http://git-scm.com/ is IHMO wrong:
>> git --version
>> git version 1.6.2.5
>> git commit -m 'Explain what I changed'
>> =>
>> git commit -a -m 'Explain what I changed'
>> => Otherwise changed files are not committed, only added ones.
>> => Therefore that are 2 commit ...
>
> If you mean the snippets right on the front page, it assumes that you add all 
> edited files.

OK, I assumed that the tutorial at
http://git.or.cz/course/svn.html
when switching from svn to git is correct, but it isn't. I unterstand now, 
that git is basically a patch management system where you add or remove 
(rm) files to a patch/commit set (adding in svn means adding or removing 
a file). So this is very different from svn and other SCM systems.

Homepage:
git add (files)
=>
git add (all edited and added files)
would clarify this, too.

>> BTW2:
>> Why is it necessary to do:
>> # Displays only changed files
>> git diff
>> # Displays only added files
>> git diff --cached
>> 
>> I would like to have a full diff of my changes:
>> git diff -a
>> (or better "git diff -a" should be the default behaviour, I think that's
>> very confusing for new users)
>
> What are 'your' changes? Between HEAD and the working tree (aka. git diff 
> HEAD)?

git diff HEAD
# no output.

Ciao,
Gerhard

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

* Re: Global .git directory
  2010-04-28  8:01         ` Alex Riesen
@ 2010-04-28 20:10           ` Gerhard Wiesinger
  0 siblings, 0 replies; 17+ messages in thread
From: Gerhard Wiesinger @ 2010-04-28 20:10 UTC (permalink / raw)
  To: Alex Riesen; +Cc: kusmabite, Thomas Rast, git

On Wed, 28 Apr 2010, Alex Riesen wrote:

> On Wed, Apr 28, 2010 at 07:33, Gerhard Wiesinger <lists@wiesinger.com> wrote:
>> On Tue, 27 Apr 2010, Erik Faye-Lund wrote:
>>> Please see Documentation/SubmittingPatches. It's difficult to
>>> comment on a non-inlined patch.
>>
>> Patch done on top of HEAD.
>
> The patches "done on top of HEAD" are usually useless for
> everyone, including the submitter. HEAD changes over time.
> for instance I wont be able to apply your patches on my HEAD,
> as I have a lot of changes in my Git repo.
>
> If you about to share your modifications, you better base your
> changes on stable points in history, like releases (marked by
> release tags, like "v1.7.1").
>

Patch is made on top of v1.7.1 (it was HEAD at the time of the last pull) 
according to git log.

>> BTW2:
>> Why is it necessary to do:
>
> It is so you can distinguish between the changes in progress and
> the changes ready to be submitted (prepared for commit).
>
>> # Displays only changed files
>> git diff
>
> To be exact: the changes not yet staged for commit.
>
>> # Displays only added files
>> git diff --cached
>
> No, it displays the changes ready to be committed (staged).
>
>> I would like to have a full diff of my changes:
>> git diff -a
>
> You wouldn't use it. It is very useful to separate the phases of workflow.
>
> BTW, try using "git status". It'll show you both lists of changed files.
> Also "git gui", and "gitk" make the lists visible ("git gui" is more like
> "git status", and you can commit from it).
>
>> (or better "git diff -a" should be the default behaviour, I think that's
>> very confusing for new users)
>
> Only to unwilling to learn. You'd be probably the first to suggest
> to combine the two stages of change. Usually people understand
> (or get a feeling of understanding) the index even before they send
> first mail to the mailing list.

Ok, as explained in previous mail, confusion was introduced from the 
tutorial at: http://git.or.cz/course/svn.html

Thnx for explaination so far.

Ciao,
Gerhard

--
http://www.wiesinger.com/

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

* Re: Global .git directory
  2010-04-28 12:50         ` Erik Faye-Lund
@ 2010-04-28 20:22           ` Gerhard Wiesinger
  2010-05-04  5:07             ` Gerhard Wiesinger
  0 siblings, 1 reply; 17+ messages in thread
From: Gerhard Wiesinger @ 2010-04-28 20:22 UTC (permalink / raw)
  To: kusmabite; +Cc: Thomas Rast, git

On Wed, 28 Apr 2010, Erik Faye-Lund wrote:

> On Wed, Apr 28, 2010 at 7:33 AM, Gerhard Wiesinger <lists@wiesinger.com> wrote:
>> On Tue, 27 Apr 2010, Erik Faye-Lund wrote:
>>
>>> On Tue, Apr 27, 2010 at 10:06 PM, Gerhard Wiesinger <lists@wiesinger.com>
>>> wrote:
>>>>
>>>> On Tue, 27 Apr 2010, Thomas Rast wrote:
>>>>>
>>>> Ok, rather than convincing I've written a (fast) patch which works for me
>>>> :-)
>>>>
>>>> Any comments? Any (further) changes needed? Will you include it in main
>>>> git?
>>>
> I was referring to that you sent the patch attached instead of inlined
> (as Documentation/SubmittingPatches suggests).
>
> By attaching patches you force everyone who wants to review the patch
> to have to copy and manually quote the parts of the patch that they
> have comments about instead of automatic quoting like all decent
> e-mail clients do. That way you get less people interested in the
> patch.
>
> I sent this reply because you did the right thing of cooking up a
> patch in the first place (as opposed to just arguing - very good), so
> I think you deserve a chance of getting the patch reviewed (and
> possibly included... if people agree with you, that is).

Sorry, was in a hurry, and just wanted to get the patch "out there". No
problem, patch is inline now and hopefully in the right format.

Patch is done after V1.7.1.

>From 87cc9d17ec52a6ff2b71b9851c5b61f9e1da72be Mon Sep 17 00:00:00 2001
From: Gerhard Wiesinger <lists@wiesinger.com>
Date: Wed, 28 Apr 2010 06:46:28 +0200
Subject: [PATCH 1/2] Added global git directory when environment variable GIT_DIR_GLOBAL is set, e.g. export GIT_DIR_GLOBAL=/home/gerhard/.git_global

---
  environment.h |    8 ++++++++
  setup.h       |    6 ++++++
  2 files changed, 14 insertions(+), 0 deletions(-)
  create mode 100644 environment.h
  create mode 100644 setup.h

diff --git a/environment.h b/environment.h
new file mode 100644
index 0000000..fb6a368
--- /dev/null
+++ b/environment.h
@@ -0,0 +1,8 @@
+#ifndef ENVIRONMENT_H
+#define ENVIRONMENT_H
+
+char *get_git_dir_global_base_dir(void);
+char *get_git_dir_from_environment(void);
+int is_git_dir_global_environment(void);
+
+#endif /* ENVIRONMENT_H */
diff --git a/setup.h b/setup.h
new file mode 100644
index 0000000..2047ba5
--- /dev/null
+++ b/setup.h
@@ -0,0 +1,6 @@
+#ifndef SETUP_H
+#define SETUP_H
+
+int is_git_directory(const char *suspect);
+
+#endif /* SETUP_H */
-- 
1.6.2.5

>From ac2dfd8fcbbafafa92e68b17cb9c419aad0134ed Mon Sep 17 00:00:00 2001
From: Gerhard Wiesinger <lists@wiesinger.com>
Date: Wed, 28 Apr 2010 07:13:09 +0200
Subject: [PATCH 2/2] Added global git directory when environment variable GIT_DIR_GLOBAL is set, missing files, e.g. export GIT_DIR_GLOBAL=${HOME}/.git_global

---
  builtin/init-db.c   |   38 +++++++++++++++-
  builtin/rev-parse.c |    3 +-
  cache.h             |    2 +
  environment.c       |  125 ++++++++++++++++++++++++++++++++++++++++++++++++++-
  setup.c             |    5 +-
  5 files changed, 167 insertions(+), 6 deletions(-)

diff --git a/builtin/init-db.c b/builtin/init-db.c
index edc40ff..a91e762 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -7,6 +7,7 @@
  #include "builtin.h"
  #include "exec_cmd.h"
  #include "parse-options.h"
+#include "environment.h"

  #ifndef DEFAULT_GIT_TEMPLATE_DIR
  #define DEFAULT_GIT_TEMPLATE_DIR "/usr/share/git-core/templates"
@@ -34,6 +35,27 @@ static void safe_create_dir(const char *dir, int share)
  		die("Could not make %s writable by group", dir);
  }

+static void mkdir_recusive(char *directory)
+{
+	char tmp[PATH_MAX+1];
+	char *p = NULL;
+	size_t len;
+
+	snprintf(tmp, sizeof(tmp), "%s", directory);
+	len = strlen(tmp);
+	if(is_dir_sep(tmp[len - 1]))
+		tmp[len - 1] = 0;
+
+	for(p = tmp + 1; *p; p++)
+		if(is_dir_sep(*p)) {
+			char c = *p;
+			*p = 0;
+			safe_create_dir(tmp, 1);
+			*p = c;
+		}
+	safe_create_dir(tmp,1);
+}
+
  static void copy_templates_1(char *path, int baselen,
  			     char *template, int template_baselen,
  			     DIR *dir)
@@ -473,7 +495,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
  	 * GIT_WORK_TREE makes sense only in conjunction with GIT_DIR
  	 * without --bare.  Catch the error early.
  	 */
-	git_dir = getenv(GIT_DIR_ENVIRONMENT);
+	git_dir = get_git_dir_from_environment();
  	if ((!git_dir || is_bare_repository_cfg == 1)
  	    && getenv(GIT_WORK_TREE_ENVIRONMENT))
  		die("%s (or --work-tree=<directory>) not allowed without "
@@ -490,7 +512,19 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
  	if (is_bare_repository_cfg < 0)
  		is_bare_repository_cfg = guess_repository_type(git_dir);

-	if (!is_bare_repository_cfg) {
+	if (is_git_dir_global_environment()) {
+		char *global_base_dir = get_git_dir_global_base_dir();
+		mkdir_recusive(global_base_dir);
+		if (!git_work_tree_cfg) {
+			git_work_tree_cfg = xcalloc(PATH_MAX, 1);
+			strncpy(git_work_tree_cfg, global_base_dir, PATH_MAX);
+		}
+		if (access(get_git_work_tree(), X_OK))
+			die_errno ("Cannot access work tree '%s'",
+				   get_git_work_tree());
+	}
+ 
+	if (!is_bare_repository_cfg && !is_git_dir_global_environment()) {
  		if (git_dir) {
  			const char *git_dir_parent = strrchr(git_dir, '/');
  			if (git_dir_parent) {
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index 8fbf9d0..b64260f 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -9,6 +9,7 @@
  #include "quote.h"
  #include "builtin.h"
  #include "parse-options.h"
+#include "environment.h"

  #define DO_REVS		1
  #define DO_NOREV	2
@@ -642,7 +643,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
  				continue;
  			}
  			if (!strcmp(arg, "--git-dir")) {
-				const char *gitdir = getenv(GIT_DIR_ENVIRONMENT);
+				const char *gitdir = get_git_dir_from_environment();
  				static char cwd[PATH_MAX];
  				int len;
  				if (gitdir) {
diff --git a/cache.h b/cache.h
index 5eb0573..57a647d 100644
--- a/cache.h
+++ b/cache.h
@@ -372,6 +372,8 @@ static inline enum object_type object_type(unsigned int mode)
  }

  #define GIT_DIR_ENVIRONMENT "GIT_DIR"
+#define GIT_DIR_GLOBAL_ENVIRONMENT "GIT_DIR_GLOBAL"
+#define GIT_DIR_GLOBAL_SPECIAL_ROOT_DIRECTORY "/SPECIAL_ROOT_DIRECTORY"
  #define GIT_WORK_TREE_ENVIRONMENT "GIT_WORK_TREE"
  #define DEFAULT_GIT_DIR_ENVIRONMENT ".git"
  #define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY"
diff --git a/environment.c b/environment.c
index 876c5e5..d9768a9 100644
--- a/environment.c
+++ b/environment.c
@@ -8,6 +8,9 @@
   * are.
   */
  #include "cache.h"
+#include "setup.h"
+
+#define DIR_SEPARATOR "/"

  char git_default_email[MAX_GITNAME];
  char git_default_name[MAX_GITNAME];
@@ -80,9 +83,129 @@ const char * const local_repo_env[LOCAL_REPO_ENV_SIZE + 1] = {
  	NULL
  };

+char* path_shorten(char *path)
+{
+	int index = strlen(path);
+
+	while (index > 0) {
+		index--;
+		if (is_dir_sep(path[index])) {
+			path[index] = 0;
+			return path;
+		}
+	}
+
+	// should never get here
+	return "";
+}
+
+static char *get_dir_global_environment(void)
+{
+	return getenv(GIT_DIR_GLOBAL_ENVIRONMENT);
+}
+
+char *get_git_dir_global_base_dir(void)
+{
+	static char cwd_buf[PATH_MAX+1];
+	static char dir_global_buf[PATH_MAX+1];
+	static char git_dir_buf[PATH_MAX+1];
+	int global_environment_len = 0;
+	char *git_dir_global_environment = get_dir_global_environment();
+
+	if (!getcwd(cwd_buf, sizeof(cwd_buf)-1))
+		die_errno("Unable to read current working directory");
+
+	if (!is_absolute_path(git_dir_global_environment))
+		die_errno("Global environment variable" GIT_DIR_GLOBAL_ENVIRONMENT " needs absolute path!");
+
+	strncpy(dir_global_buf, git_dir_global_environment, sizeof(dir_global_buf));
+	global_environment_len = strlen(dir_global_buf);
+	if (is_dir_sep(dir_global_buf[global_environment_len]))
+		dir_global_buf[global_environment_len] = 0;
+
+	return mksnpath(git_dir_buf, sizeof(git_dir_buf), "%s%s", dir_global_buf, cwd_buf);
+}
+
+char *get_git_dir_from_global_environment(char *git_dir_global_environment)
+{
+	static char cwd_buf[PATH_MAX+1];
+	static char cwd_original_buf[PATH_MAX+1];
+	static char dir_global_buf[PATH_MAX+1];
+	static char git_dir_buf[PATH_MAX+1];
+	char *cwd = cwd_buf;
+	char *git_dir = git_dir_buf;
+	int found = 0;
+	int global_environment_len = 0;
+
+	if (!getcwd(cwd_buf, sizeof(cwd_buf)-1))
+		die_errno("Unable to read current working directory");
+
+	if (!is_absolute_path(git_dir_global_environment))
+		die_errno("Global environment variable" GIT_DIR_GLOBAL_ENVIRONMENT " needs absolute path!");
+
+	strncpy(dir_global_buf, git_dir_global_environment, sizeof(dir_global_buf));
+	global_environment_len = strlen(dir_global_buf);
+	if (is_dir_sep(dir_global_buf[global_environment_len]))
+		dir_global_buf[global_environment_len] = 0;
+
+	if (strlen(cwd) == 1 && is_dir_sep(cwd[0]))
+	{
+		// special case for / git repository
+		git_dir = mksnpath(git_dir_buf, sizeof(git_dir_buf), "%s%s" DIR_SEPARATOR "%s", dir_global_buf, GIT_DIR_GLOBAL_SPECIAL_ROOT_DIRECTORY, DEFAULT_GIT_DIR_ENVIRONMENT);
+		return git_dir;
+	}
+
+	strncpy(cwd_original_buf, cwd, sizeof(cwd_original_buf));
+
+	/*
+	 * Test in the following order (relative to the cwd):
+	 * - .git (file containing "gitdir: <path>")
+	 * - .git/
+	 * - ./ (bare)
+	 * - ../.git
+	 * - ../.git/
+	 * - ../ (bare)
+	 * - ../../.git/
+	 *   etc.
+	 */
+	for (;;) {
+		if (*cwd == '\0') {
+			break;
+		}
+
+		git_dir = mksnpath(git_dir_buf, sizeof(git_dir_buf), "%s%s" DIR_SEPARATOR "%s", dir_global_buf, cwd, DEFAULT_GIT_DIR_ENVIRONMENT);
+		if (is_git_directory(git_dir)) {
+			found = 1;
+			break;
+		}
+
+		cwd = path_shorten(cwd);
+	}
+
+	if (!found) {
+		git_dir = mksnpath(git_dir_buf, sizeof(git_dir_buf), "%s%s/%s", dir_global_buf, cwd_original_buf, DEFAULT_GIT_DIR_ENVIRONMENT);
+		return git_dir;
+	}
+
+	return git_dir;
+}
+
+int is_git_dir_global_environment(void)
+{
+	return (get_dir_global_environment() != NULL);
+}
+
+char *get_git_dir_from_environment(void)
+{
+	char *git_dir_global_environment = get_dir_global_environment();
+	if (git_dir_global_environment) return get_git_dir_from_global_environment(git_dir_global_environment);
+
+	return getenv(GIT_DIR_ENVIRONMENT);
+}
+
  static void setup_git_env(void)
  {
-	git_dir = getenv(GIT_DIR_ENVIRONMENT);
+	git_dir = get_git_dir_from_environment();
  	if (!git_dir)
  		git_dir = read_gitfile_gently(DEFAULT_GIT_DIR_ENVIRONMENT);
  	if (!git_dir)
diff --git a/setup.c b/setup.c
index 5716d90..6ee3a59 100644
--- a/setup.c
+++ b/setup.c
@@ -1,5 +1,6 @@
  #include "cache.h"
  #include "dir.h"
+#include "environment.h"

  static int inside_git_dir = -1;
  static int inside_work_tree = -1;
@@ -165,7 +166,7 @@ const char **get_pathspec(const char *prefix, const char **pathspec)
   *    a proper "ref:", or a regular file HEAD that has a properly
   *    formatted sha1 object name.
   */
-static int is_git_directory(const char *suspect)
+int is_git_directory(const char *suspect)
  {
  	char path[PATH_MAX];
  	size_t len = strlen(suspect);
@@ -337,7 +338,7 @@ const char *setup_git_directory_gently(int *nongit_ok)
  	 * to do any discovery, but we still do repository
  	 * validation.
  	 */
-	gitdirenv = getenv(GIT_DIR_ENVIRONMENT);
+	gitdirenv = get_git_dir_from_environment();
  	if (gitdirenv) {
  		if (PATH_MAX - 40 < strlen(gitdirenv))
  			die("'$%s' too big", GIT_DIR_ENVIRONMENT);
-- 
1.6.2.5

>From cca30ca806f9758bb0271f08808e2c830d9aba5e Mon Sep 17 00:00:00 2001
From: Gerhard Wiesinger <lists@wiesinger.com>
Date: Wed, 28 Apr 2010 07:30:01 +0200
Subject: [PATCH 3/3] Updated documentation for submitting patches

---
  Documentation/SubmittingPatches |    2 +-
  1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
index abc65de..e871032 100644
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -23,7 +23,7 @@ Checklist (and a short version for the impatient):

  	Patch:

-	- use "git format-patch -M" to create the patch
+	- use "git format-patch -M" to create the patch (e.g. git format-patch -M origin/master)
  	- do not PGP sign your patch
  	- do not attach your patch, but read in the mail
  	  body, unless you cannot teach your mailer to
-- 
1.6.2.5


Ciao,
Gerhard

--
http://www.wiesinger.com/

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

* Re: Global .git directory
  2010-04-28 20:22           ` Gerhard Wiesinger
@ 2010-05-04  5:07             ` Gerhard Wiesinger
  2010-05-04  5:40               ` Andrew Ruder
  0 siblings, 1 reply; 17+ messages in thread
From: Gerhard Wiesinger @ 2010-05-04  5:07 UTC (permalink / raw)
  To: git; +Cc: kusmabite, Thomas Rast

On Wed, 28 Apr 2010, Gerhard Wiesinger wrote:
> Sorry, was in a hurry, and just wanted to get the patch "out there". No
> problem, patch is inline now and hopefully in the right format.
>
> Patch is done after V1.7.1.
>

Still got no feedback ...

Ciao,
Gerhard

--
http://www.wiesinger.com/

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

* Re: Global .git directory
  2010-05-04  5:07             ` Gerhard Wiesinger
@ 2010-05-04  5:40               ` Andrew Ruder
  2010-05-04  6:02                 ` Andreas Ericsson
                                   ` (2 more replies)
  0 siblings, 3 replies; 17+ messages in thread
From: Andrew Ruder @ 2010-05-04  5:40 UTC (permalink / raw)
  To: Gerhard Wiesinger; +Cc: git, kusmabite, Thomas Rast

On Tue, May 04, 2010 at 07:07:08AM +0200, Gerhard Wiesinger wrote:
> Still got no feedback ...

I'm not really a person that will be doing the reviewing but as a
frequent lurker on the list, I'm going to try to help you out some.
I'll bite, but I think the lack of response is still due to a major case
of RTFM.  Here's the things from SubmittingPatches that appear to still
be wrong and are most likely keeping your patch from being properly
reviewed:

>	Commits:
>
>	- make commits of logical units

Your patches aren't really in logical units.  Patch 1/2 makes changes to
a header file and creates several function declarations which don't even
exist until 2/2.  So in this case you really would just want one patch
there.

Or even better, perhaps separate the EXISTING functionality into the API
you are eventually shooting for and then add your feature into the next
patch.  I'm sure if done cleanly, some of the changes like
get_git_dir_from_environment() could be done entirely separately from
your feature.  Once everybody agrees that it looks good and works the
same as it always has, it makes the task of reviewing your feature patch
even easier as it will be simply adding a feature and not adding a
feature AND adding a new GIT_DIR API simultaneously.


>	- the first line of the commit message should be a short
>	  description and should skip the full stop
>	- the body should provide a meaningful commit message, which:
>		- uses the imperative, present tense: "change",
>		  not "changed" or "changes".
>		- includes motivation for the change, and contrasts
>		  its implementation with previous behaviour

Your commit messages are very under-detailed.  At the very least you
should include at least as much detail as you did in your original
e-mail to the list!  Look through git log some, you'll see that it isn't
uncommon for patches to actually end up much shorter than the patch
itself.  At the very least, the "Subject" of your patch should be much
shorter.

>	- if you want your work included in git.git, add a
>	  "Signed-off-by: Your Name <you@example.com>" line to the
>	  commit message (or just use the option "-s" when
>	  committing) to confirm that you agree to the Developer's
>	  Certificate of Origin

git takes this one pretty seriously.  Put this in your patches now to
avoid headaches down the line.

>	- make sure that you have tests for the bug you are fixing

While you're not exactly fixing a bug, this would benefit from a
testcase.

>	Patch:
>
>	- use "git format-patch -M" to create the patch

You did this, but typically patches are one per e-mail, the subject
being the [PATCH ...] line and the body being the rest rather than
multiple patches all just copy-pasted inline.

>	- if you change, add, or remove a command line option or
>	  make some other user interface change, the associated
>	  documentation should be updated as well.

As the person who added the above to the documentation, it sure is nice
when people edit the appropriate manpages with their proposed changes
:).

I know it all seems nit-picky, but if you want to see your changes make
it into git.git you're best off making it as EASY AS POSSIBLE for the
reviewer to take your patch and apply it and be done with it.  This just
isn't possible without testcases, documentation updates, etc..
Especially for feature additions (vs bug fixes) you really have to make
life as simple (and normal) as possible for reviewers, maintainers,
etc.. After all, it is a lot easier living without a feature than it is
a documented bug-fix!

Just a random lurker trying to help you out here!

Cheers,
Andy

P.S. I'd also double-check the patch, typos (like mkdir_recusive) make
things look sloppy and can turn people off from reviewing (especially
when it is almost the first line of the patch!)

-- 
Andrew Ruder <andy@aeruder.net>
http://www.aeruder.net

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

* Re: Global .git directory
  2010-05-04  5:40               ` Andrew Ruder
@ 2010-05-04  6:02                 ` Andreas Ericsson
  2010-05-04  6:07                 ` Gerhard Wiesinger
  2010-05-04 16:55                 ` Junio C Hamano
  2 siblings, 0 replies; 17+ messages in thread
From: Andreas Ericsson @ 2010-05-04  6:02 UTC (permalink / raw)
  To: git

On 05/04/2010 07:40 AM, Andrew Ruder wrote:

[ an exemplary breakdown of why the patch hasn't been reviewed ]

I'll stash this for use in other projects. Thanks a lot Andrew :)

Cc-list culled a bit.

-- 
Andreas Ericsson                   andreas.ericsson@op5.se
OP5 AB                             www.op5.se
Tel: +46 8-230225                  Fax: +46 8-230231

Considering the successes of the wars on alcohol, poverty, drugs and
terror, I think we should give some serious thought to declaring war
on peace.

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

* Re: Global .git directory
  2010-05-04  5:40               ` Andrew Ruder
  2010-05-04  6:02                 ` Andreas Ericsson
@ 2010-05-04  6:07                 ` Gerhard Wiesinger
  2010-05-04 16:55                 ` Junio C Hamano
  2 siblings, 0 replies; 17+ messages in thread
From: Gerhard Wiesinger @ 2010-05-04  6:07 UTC (permalink / raw)
  To: Andrew Ruder; +Cc: git, kusmabite, Thomas Rast

On Mon, 3 May 2010, Andrew Ruder wrote:
> On Tue, May 04, 2010 at 07:07:08AM +0200, Gerhard Wiesinger wrote:
> I know it all seems nit-picky, but if you want to see your changes make
> it into git.git you're best off making it as EASY AS POSSIBLE for the
> reviewer to take your patch and apply it and be done with it.  This just
> isn't possible without testcases, documentation updates, etc..
> Especially for feature additions (vs bug fixes) you really have to make
> life as simple (and normal) as possible for reviewers, maintainers,
> etc.. After all, it is a lot easier living without a feature than it is
> a documented bug-fix!
>
> Just a random lurker trying to help you out here!

Thnx for your feedback. Will rework some of the parts you mentioned.

I think such a strict process should be valid for final commits to the git 
repository. But for a first patch ready for discussion I think one 
shouldn't make such strict process rules. I think we are at the state 
whether such a patch *might* be accepted and reviewers should look at the 
content first to have a decision for digging further (e.g. rework some 
parts of the patch) or for "ok this makes no sense at all". I think this 
saves time of the reviewers and also my time (I could now make all the 
formal stuff of the patch you mentioned but when there is something 
fundamental wrong there e.g in concept all the work was useless when not 
accepted. I think there should be agreement of the roadmap of a feature 
and then a focus on formalism to finally commit a pathc. So I'm a fan of 
discussion and incremental work to minimise useless and typically 
frustrating effort.)

Ciao,
Gerhard

--
http://www.wiesinger.com/

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

* Re: Global .git directory
  2010-05-04  5:40               ` Andrew Ruder
  2010-05-04  6:02                 ` Andreas Ericsson
  2010-05-04  6:07                 ` Gerhard Wiesinger
@ 2010-05-04 16:55                 ` Junio C Hamano
  2 siblings, 0 replies; 17+ messages in thread
From: Junio C Hamano @ 2010-05-04 16:55 UTC (permalink / raw)
  To: Andrew Ruder; +Cc: Gerhard Wiesinger, git, kusmabite, Thomas Rast

Andrew Ruder <andy@aeruder.net> writes:

> I'm not really a person that will be doing the reviewing but as a
> frequent lurker on the list, I'm going to try to help you out some.

Thanks.

> While you're not exactly fixing a bug, this would benefit from a
> testcase.

Just so that people do not misunderstand.  A test is _not_ about proving
that your patch fixed a bug.  It instead is to protect your change from
future breakages by _other people_.

Having a test that would fail if careless others muck with related
codepath in the future without taking your change into account is a good
way to make sure your new feature or your good change of behaviour keep
working (the alternative is for you as the author of such a valuable
change to stay on the list 24/7, audit all the patches that may negatively
affect your change and veto them before they are applied, which is
impractical for most people).

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

end of thread, other threads:[~2010-05-04 16:55 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-04-27  5:14 Global .git directory Gerhard Wiesinger
2010-04-27  9:59 ` Thomas Rast
2010-04-27 20:06   ` Gerhard Wiesinger
2010-04-27 20:26     ` Erik Faye-Lund
2010-04-28  5:33       ` Gerhard Wiesinger
2010-04-28  6:22         ` Tomas Carnecky
2010-04-28 20:03           ` Gerhard Wiesinger
2010-04-28  8:01         ` Alex Riesen
2010-04-28 20:10           ` Gerhard Wiesinger
2010-04-28 12:50         ` Erik Faye-Lund
2010-04-28 20:22           ` Gerhard Wiesinger
2010-05-04  5:07             ` Gerhard Wiesinger
2010-05-04  5:40               ` Andrew Ruder
2010-05-04  6:02                 ` Andreas Ericsson
2010-05-04  6:07                 ` Gerhard Wiesinger
2010-05-04 16:55                 ` Junio C Hamano
2010-04-27 20:37     ` Jacob Helwig

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).