{"thread":{"id":"23615","subject":"Global .git directory","startedAt":"2010-04-27T05:14:13Z","lastAt":"2010-05-04T16:55:29Z","messageCount":17,"participants":["Gerhard Wiesinger","Thomas Rast","Erik Faye-Lund","Jacob Helwig","Tomas Carnecky","Alex Riesen","Andrew Ruder","Andreas Ericsson","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"140474","messageId":"alpine.LFD.2.00.1004270705280.15197@bbs.intern","threadId":"23615","inReplyTo":null,"subject":"Global .git directory","fromName":"Gerhard Wiesinger","fromEmail":"lists@wiesinger.com","sentAt":"2010-04-27T05:14:13Z","receivedAt":"2010-04-27T05:14:13Z","isPatch":false,"sender":{"key":"lists@wiesinger.com","avatar":null},"body":"Hello,\n\nI'm new to git and as far as I saw that feature is missing: Placing .git \ndirectory/repository on a central place for many git repositories. This \nfeature ensures that data directories are kept clean from metadata of git.\n\nI know the GIT_DIR environment variable but therefore environment has to \nbe set for each repository which is IHMO not practicable. Therefore I \nsuggest the following approach (which also overrides GIT_DIR when set):\n#  Can be set globally for all users\nexport GIT_GLOBAL_DIR=$HOME/.git_global\n\nWhen this environment variable is set git searches the repository in \n$HOME/.git_global/`pwd`\nExample:\ncd /home/gerhard/myproject\n=> /home/gerhard/.git_global/home/gerhard/myproject/.git directory is used\ncd /home/gerhard/myproject/subdir\n=> /home/gerhard/.git_global/home/gerhard/myproject/.git directory is \nstill used, base directory must also be searched for (algorithm must \nalready be implemented)\n\nI think this should be easy to implement on a centralized point.\n\nAny feedback is welcome.\n\nThnx.\n\nCiao,\nGerhard\n\n--\nhttp://www.wiesinger.com/\n"},{"id":"140488","messageId":"201004271159.34071.trast@student.ethz.ch","threadId":"23615","inReplyTo":"alpine.LFD.2.00.1004270705280.15197@bbs.intern","subject":"Re: Global .git directory","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2010-04-27T09:59:33Z","receivedAt":"2010-04-27T09:59:33Z","isPatch":false,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Gerhard Wiesinger wrote:\n> Hello,\n> \n> I'm new to git and as far as I saw that feature is missing: Placing .git \n> directory/repository on a central place for many git repositories. This \n> feature ensures that data directories are kept clean from metadata of git.\n[...]\n> I think this should be easy to implement on a centralized point.\n\nWhat problem are you trying to solve, what solution are you\nattempting, and why does the .git get in the way of your proposed\nsolution?\n\n(In other words, please convince us that this is actually worth\nhaving.)\n\n-- \nThomas Rast\ntrast@{inf,student}.ethz.ch\n"},{"id":"140538","messageId":"alpine.LFD.2.00.1004272144470.11216@bbs.intern","threadId":"23615","inReplyTo":"201004271159.34071.trast@student.ethz.ch","subject":"Re: Global .git directory","fromName":"Gerhard Wiesinger","fromEmail":"lists@wiesinger.com","sentAt":"2010-04-27T20:06:23Z","receivedAt":"2010-04-27T20:06:23Z","isPatch":false,"sender":{"key":"lists@wiesinger.com","avatar":null},"body":"On Tue, 27 Apr 2010, Thomas Rast wrote:\n\n> Gerhard Wiesinger wrote:\n>> Hello,\n>>\n>> I'm new to git and as far as I saw that feature is missing: Placing .git\n>> directory/repository on a central place for many git repositories. This\n>> feature ensures that data directories are kept clean from metadata of git.\n> [...]\n>> I think this should be easy to implement on a centralized point.\n>\n> What problem are you trying to solve, what solution are you\n> attempting, and why does the .git get in the way of your proposed\n> solution?\n\nI don't like metadata of the repository in MY file structure (e.g. .git in \ntop directory, .svn in every directory in subversion, .hg in top \ndirectory) for several reasons:\n1.) Searching might arise false results, longer output and takes longer \n(e.g. grep -ir string .)\n2.) Making tarballs, diffs, etc.: One has to make ugly --exclude or some \nother workarounds when directories are traversed.\n3.) From an archtectural point of view: It is not technically necessary to \nmix up user data with repository data.\n\n> (In other words, please convince us that this is actually worth\n> having.)\n\nOk, rather than convincing I've written a (fast) patch which works for \nme :-)\n\nAny comments? Any (further) changes needed? Will you include it in main \ngit?\n\nThnx.\n\nCiao,\nGerhard\n\n--\nhttp://www.wiesinger.com/\n\ndiff --git a/builtin/init-db.c b/builtin/init-db.c\nindex edc40ff..a91e762 100644\n--- a/builtin/init-db.c\n+++ b/builtin/init-db.c\n@@ -7,6 +7,7 @@\n #include \"builtin.h\"\n #include \"exec_cmd.h\"\n #include \"parse-options.h\"\n+#include \"environment.h\"\n \n #ifndef DEFAULT_GIT_TEMPLATE_DIR\n #define DEFAULT_GIT_TEMPLATE_DIR \"/usr/share/git-core/templates\"\n@@ -34,6 +35,27 @@ static void safe_create_dir(const char *dir, int share)\n \t\tdie(\"Could not make %s writable by group\", dir);\n }\n \n+static void mkdir_recusive(char *directory)\n+{\n+\tchar tmp[PATH_MAX+1];\n+\tchar *p = NULL;\n+\tsize_t len;\n+\n+\tsnprintf(tmp, sizeof(tmp), \"%s\", directory);\n+\tlen = strlen(tmp);\n+\tif(is_dir_sep(tmp[len - 1]))\n+\t\ttmp[len - 1] = 0;\n+\n+\tfor(p = tmp + 1; *p; p++)\n+\t\tif(is_dir_sep(*p)) {\n+\t\t\tchar c = *p;\n+\t\t\t*p = 0;\n+\t\t\tsafe_create_dir(tmp, 1);\n+\t\t\t*p = c;\n+\t\t}\n+\tsafe_create_dir(tmp,1);\n+}\n+\n static void copy_templates_1(char *path, int baselen,\n \t\t\t     char *template, int template_baselen,\n \t\t\t     DIR *dir)\n@@ -473,7 +495,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)\n \t * GIT_WORK_TREE makes sense only in conjunction with GIT_DIR\n \t * without --bare.  Catch the error early.\n \t */\n-\tgit_dir = getenv(GIT_DIR_ENVIRONMENT);\n+\tgit_dir = get_git_dir_from_environment();\n \tif ((!git_dir || is_bare_repository_cfg == 1)\n \t    && getenv(GIT_WORK_TREE_ENVIRONMENT))\n \t\tdie(\"%s (or --work-tree=<directory>) not allowed without \"\n@@ -490,7 +512,19 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)\n \tif (is_bare_repository_cfg < 0)\n \t\tis_bare_repository_cfg = guess_repository_type(git_dir);\n \n-\tif (!is_bare_repository_cfg) {\n+\tif (is_git_dir_global_environment()) {\n+\t\tchar *global_base_dir = get_git_dir_global_base_dir();\n+\t\tmkdir_recusive(global_base_dir);\n+\t\tif (!git_work_tree_cfg) {\n+\t\t\tgit_work_tree_cfg = xcalloc(PATH_MAX, 1);\n+\t\t\tstrncpy(git_work_tree_cfg, global_base_dir, PATH_MAX);\n+\t\t}\n+\t\tif (access(get_git_work_tree(), X_OK))\n+\t\t\tdie_errno (\"Cannot access work tree '%s'\",\n+\t\t\t\t   get_git_work_tree());\n+\t}\n+\t\t\n+\tif (!is_bare_repository_cfg && !is_git_dir_global_environment()) {\n \t\tif (git_dir) {\n \t\t\tconst char *git_dir_parent = strrchr(git_dir, '/');\n \t\t\tif (git_dir_parent) {\ndiff --git a/builtin/rev-parse.c b/builtin/rev-parse.c\nindex 8fbf9d0..b64260f 100644\n--- a/builtin/rev-parse.c\n+++ b/builtin/rev-parse.c\n@@ -9,6 +9,7 @@\n #include \"quote.h\"\n #include \"builtin.h\"\n #include \"parse-options.h\"\n+#include \"environment.h\"\n \n #define DO_REVS\t\t1\n #define DO_NOREV\t2\n@@ -642,7 +643,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t\tif (!strcmp(arg, \"--git-dir\")) {\n-\t\t\t\tconst char *gitdir = getenv(GIT_DIR_ENVIRONMENT);\n+\t\t\t\tconst char *gitdir = get_git_dir_from_environment();\n \t\t\t\tstatic char cwd[PATH_MAX];\n \t\t\t\tint len;\n \t\t\t\tif (gitdir) {\ndiff --git a/cache.h b/cache.h\nindex 5eb0573..57a647d 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -372,6 +372,8 @@ static inline enum object_type object_type(unsigned int mode)\n }\n \n #define GIT_DIR_ENVIRONMENT \"GIT_DIR\"\n+#define GIT_DIR_GLOBAL_ENVIRONMENT \"GIT_DIR_GLOBAL\"\n+#define GIT_DIR_GLOBAL_SPECIAL_ROOT_DIRECTORY \"/SPECIAL_ROOT_DIRECTORY\"\n #define GIT_WORK_TREE_ENVIRONMENT \"GIT_WORK_TREE\"\n #define DEFAULT_GIT_DIR_ENVIRONMENT \".git\"\n #define DB_ENVIRONMENT \"GIT_OBJECT_DIRECTORY\"\ndiff --git a/environment.c b/environment.c\nindex 876c5e5..d9768a9 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -8,6 +8,9 @@\n  * are.\n  */\n #include \"cache.h\"\n+#include \"setup.h\"\n+\n+#define DIR_SEPARATOR \"/\"\n \n char git_default_email[MAX_GITNAME];\n char git_default_name[MAX_GITNAME];\n@@ -80,9 +83,129 @@ const char * const local_repo_env[LOCAL_REPO_ENV_SIZE + 1] = {\n \tNULL\n };\n \n+char* path_shorten(char *path)\n+{\n+\tint index = strlen(path);\n+\n+\twhile (index > 0) {\n+\t\tindex--;\n+\t\tif (is_dir_sep(path[index])) {\n+\t\t\tpath[index] = 0;\n+\t\t\treturn path;\n+\t\t}\n+\t}\n+\n+\t// should never get here\n+\treturn \"\";\n+}\n+\n+static char *get_dir_global_environment(void)\n+{\n+\treturn getenv(GIT_DIR_GLOBAL_ENVIRONMENT);\n+}\n+\n+char *get_git_dir_global_base_dir(void)\n+{\n+\tstatic char cwd_buf[PATH_MAX+1];\n+\tstatic char dir_global_buf[PATH_MAX+1];\n+\tstatic char git_dir_buf[PATH_MAX+1];\n+\tint global_environment_len = 0;\n+\tchar *git_dir_global_environment = get_dir_global_environment();\n+\n+\tif (!getcwd(cwd_buf, sizeof(cwd_buf)-1))\n+\t\tdie_errno(\"Unable to read current working directory\");\n+\n+\tif (!is_absolute_path(git_dir_global_environment))\n+\t\tdie_errno(\"Global environment variable\" GIT_DIR_GLOBAL_ENVIRONMENT \" needs absolute path!\");\n+\n+\tstrncpy(dir_global_buf, git_dir_global_environment, sizeof(dir_global_buf));\n+\tglobal_environment_len = strlen(dir_global_buf);\n+\tif (is_dir_sep(dir_global_buf[global_environment_len]))\n+\t\tdir_global_buf[global_environment_len] = 0;\n+\n+\treturn mksnpath(git_dir_buf, sizeof(git_dir_buf), \"%s%s\", dir_global_buf, cwd_buf);\n+}\n+\n+char *get_git_dir_from_global_environment(char *git_dir_global_environment)\n+{\n+\tstatic char cwd_buf[PATH_MAX+1];\n+\tstatic char cwd_original_buf[PATH_MAX+1];\n+\tstatic char dir_global_buf[PATH_MAX+1];\n+\tstatic char git_dir_buf[PATH_MAX+1];\n+\tchar *cwd = cwd_buf;\n+\tchar *git_dir = git_dir_buf;\n+\tint found = 0;\n+\tint global_environment_len = 0;\n+\n+\tif (!getcwd(cwd_buf, sizeof(cwd_buf)-1))\n+\t\tdie_errno(\"Unable to read current working directory\");\n+\n+\tif (!is_absolute_path(git_dir_global_environment))\n+\t\tdie_errno(\"Global environment variable\" GIT_DIR_GLOBAL_ENVIRONMENT \" needs absolute path!\");\n+\n+\tstrncpy(dir_global_buf, git_dir_global_environment, sizeof(dir_global_buf));\n+\tglobal_environment_len = strlen(dir_global_buf);\n+\tif (is_dir_sep(dir_global_buf[global_environment_len]))\n+\t\tdir_global_buf[global_environment_len] = 0;\n+\n+\tif (strlen(cwd) == 1 && is_dir_sep(cwd[0]))\n+\t{\n+\t\t// special case for / git repository\n+\t\tgit_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);\n+\t\treturn git_dir;\n+\t}\n+\n+\tstrncpy(cwd_original_buf, cwd, sizeof(cwd_original_buf));\n+\n+\t/*\n+\t * Test in the following order (relative to the cwd):\n+\t * - .git (file containing \"gitdir: <path>\")\n+\t * - .git/\n+\t * - ./ (bare)\n+\t * - ../.git\n+\t * - ../.git/\n+\t * - ../ (bare)\n+\t * - ../../.git/\n+\t *   etc.\n+\t */\n+\tfor (;;) {\n+\t\tif (*cwd == '\\0') {\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tgit_dir = mksnpath(git_dir_buf, sizeof(git_dir_buf), \"%s%s\" DIR_SEPARATOR \"%s\", dir_global_buf, cwd, DEFAULT_GIT_DIR_ENVIRONMENT);\n+\t\tif (is_git_directory(git_dir)) {\n+\t\t\tfound = 1;\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tcwd = path_shorten(cwd);\n+\t}\n+\n+\tif (!found) {\n+\t\tgit_dir = mksnpath(git_dir_buf, sizeof(git_dir_buf), \"%s%s/%s\", dir_global_buf, cwd_original_buf, DEFAULT_GIT_DIR_ENVIRONMENT);\n+\t\treturn git_dir;\n+\t}\n+\n+\treturn git_dir;\n+}\n+\n+int is_git_dir_global_environment(void)\n+{\n+\treturn (get_dir_global_environment() != NULL);\n+}\n+\n+char *get_git_dir_from_environment(void)\n+{\n+\tchar *git_dir_global_environment = get_dir_global_environment();\n+\tif (git_dir_global_environment) return get_git_dir_from_global_environment(git_dir_global_environment);\n+\n+\treturn getenv(GIT_DIR_ENVIRONMENT);\n+}\n+\n static void setup_git_env(void)\n {\n-\tgit_dir = getenv(GIT_DIR_ENVIRONMENT);\n+\tgit_dir = get_git_dir_from_environment();\n \tif (!git_dir)\n \t\tgit_dir = read_gitfile_gently(DEFAULT_GIT_DIR_ENVIRONMENT);\n \tif (!git_dir)\ndiff --git a/setup.c b/setup.c\nindex 5716d90..6ee3a59 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -1,5 +1,6 @@\n #include \"cache.h\"\n #include \"dir.h\"\n+#include \"environment.h\"\n \n static int inside_git_dir = -1;\n static int inside_work_tree = -1;\n@@ -165,7 +166,7 @@ const char **get_pathspec(const char *prefix, const char **pathspec)\n  *    a proper \"ref:\", or a regular file HEAD that has a properly\n  *    formatted sha1 object name.\n  */\n-static int is_git_directory(const char *suspect)\n+int is_git_directory(const char *suspect)\n {\n \tchar path[PATH_MAX];\n \tsize_t len = strlen(suspect);\n@@ -337,7 +338,7 @@ const char *setup_git_directory_gently(int *nongit_ok)\n \t * to do any discovery, but we still do repository\n \t * validation.\n \t */\n-\tgitdirenv = getenv(GIT_DIR_ENVIRONMENT);\n+\tgitdirenv = get_git_dir_from_environment();\n \tif (gitdirenv) {\n \t\tif (PATH_MAX - 40 < strlen(gitdirenv))\n \t\t\tdie(\"'$%s' too big\", GIT_DIR_ENVIRONMENT);\n"},{"id":"140542","messageId":"s2y40aa078e1004271326u3fbbd46au30f187bc3ca9c8c8@mail.gmail.com","threadId":"23615","inReplyTo":"alpine.LFD.2.00.1004272144470.11216@bbs.intern","subject":"Re: Global .git directory","fromName":"Erik Faye-Lund","fromEmail":"kusmabite@googlemail.com","sentAt":"2010-04-27T20:26:30Z","receivedAt":"2010-04-27T20:26:30Z","isPatch":false,"sender":{"key":"kusmabite@gmail.com","avatar":"https://avatars.githubusercontent.com/u/47073?v=4"},"body":"On Tue, Apr 27, 2010 at 10:06 PM, Gerhard Wiesinger <lists@wiesinger.com> wrote:\n> On Tue, 27 Apr 2010, Thomas Rast wrote:\n>> (In other words, please convince us that this is actually worth\n>> having.)\n>\n> Ok, rather than convincing I've written a (fast) patch which works for me\n> :-)\n>\n> Any comments? Any (further) changes needed? Will you include it in main git?\n\nPlease see Documentation/SubmittingPatches. It's difficult to comment\non a non-inlined patch.\n\n-- \nErik \"kusma\" Faye-Lund\n"},{"id":"140545","messageId":"l2w8c9a061004271337v62c71145jec782712618e4655@mail.gmail.com","threadId":"23615","inReplyTo":"alpine.LFD.2.00.1004272144470.11216@bbs.intern","subject":"Re: Global .git directory","fromName":"Jacob Helwig","fromEmail":"jacob.helwig@gmail.com","sentAt":"2010-04-27T20:37:29Z","receivedAt":"2010-04-27T20:37:29Z","isPatch":false,"sender":{"key":"jacob.helwig@gmail.com","avatar":"https://avatars.githubusercontent.com/u/14557?v=4"},"body":"On Tue, Apr 27, 2010 at 13:06, Gerhard Wiesinger <lists@wiesinger.com> wrote:\n> I don't like metadata of the repository in MY file structure (e.g. .git in\n> top directory, .svn in every directory in subversion, .hg in top directory)\n> for several reasons:\n> 1.) Searching might arise false results, longer output and takes longer\n> (e.g. grep -ir string .)\n\nUsing ack, instead of grep is very handy here.  It'll automatically\nskip common revision control directories, and (by default) only\nsearches known text file formats.  There is also \"git grep\".\n\n> 2.) Making tarballs, diffs, etc.: One has to make ugly --exclude or some\n> other workarounds when directories are traversed.\n\nMaking tarballs: Is there a reason not to just use git-archive?  You\ndon't need to make any ugly --exclude rules there, unless you're\ntrying to exclude things that you track in revision control.\n\nDiffs: Is \"git diff\" not sufficient here?  If it's not, why isn't it?\n\n> 3.) From an archtectural point of view: It is not technically necessary to\n> mix up user data with repository data.\n>\n"},{"id":"140567","messageId":"alpine.LFD.2.00.1004280710380.27548@bbs.intern","threadId":"23615","inReplyTo":"s2y40aa078e1004271326u3fbbd46au30f187bc3ca9c8c8@mail.gmail.com","subject":"Re: Global .git directory","fromName":"Gerhard Wiesinger","fromEmail":"lists@wiesinger.com","sentAt":"2010-04-28T05:33:06Z","receivedAt":"2010-04-28T05:33:06Z","isPatch":false,"sender":{"key":"lists@wiesinger.com","avatar":null},"body":"On Tue, 27 Apr 2010, Erik Faye-Lund wrote:\n\n> On Tue, Apr 27, 2010 at 10:06 PM, Gerhard Wiesinger <lists@wiesinger.com> wrote:\n>> On Tue, 27 Apr 2010, Thomas Rast wrote:\n>>> (In other words, please convince us that this is actually worth\n>>> having.)\n>>\n>> Ok, rather than convincing I've written a (fast) patch which works for me\n>> :-)\n>>\n>> Any comments? Any (further) changes needed? Will you include it in main git?\n>\n> Please see Documentation/SubmittingPatches. It's difficult to comment\n> on a non-inlined patch.\n>\n\nPatch done on top of HEAD.\ngit format-patch -M origin/master\n0001-Added-global-git-directory-when-environment-variable.patch\n0002-Added-global-git-directory-when-environment-variable.patch\n0003-Updated-documentation-for-submitting-patches.patch\nAttached.\n\nBTW: The tutorial on http://git-scm.com/ is IHMO wrong:\ngit --version\ngit version 1.6.2.5\ngit commit -m 'Explain what I changed'\n=>\ngit commit -a -m 'Explain what I changed'\n=> Otherwise changed files are not committed, only added ones.\n=> Therefore that are 2 commit ...\n\nBTW2:\nWhy is it necessary to do:\n# Displays only changed files\ngit diff\n# Displays only added files\ngit diff --cached\n\nI would like to have a full diff of my changes:\ngit diff -a\n(or better \"git diff -a\" should be the default behaviour, I think \nthat's very confusing for new users)\n\nCiao,\nGerhard\n\n--\nhttp://www.wiesinger.com/\n\nFrom 87cc9d17ec52a6ff2b71b9851c5b61f9e1da72be Mon Sep 17 00:00:00 2001\nFrom: Gerhard Wiesinger <lists@wiesinger.com>\nDate: Wed, 28 Apr 2010 06:46:28 +0200\nSubject: [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\n\n---\n environment.h |    8 ++++++++\n setup.h       |    6 ++++++\n 2 files changed, 14 insertions(+), 0 deletions(-)\n create mode 100644 environment.h\n create mode 100644 setup.h\n\ndiff --git a/environment.h b/environment.h\nnew file mode 100644\nindex 0000000..fb6a368\n--- /dev/null\n+++ b/environment.h\n@@ -0,0 +1,8 @@\n+#ifndef ENVIRONMENT_H\n+#define ENVIRONMENT_H\n+\n+char *get_git_dir_global_base_dir(void);\n+char *get_git_dir_from_environment(void);\n+int is_git_dir_global_environment(void);\n+\n+#endif /* ENVIRONMENT_H */\ndiff --git a/setup.h b/setup.h\nnew file mode 100644\nindex 0000000..2047ba5\n--- /dev/null\n+++ b/setup.h\n@@ -0,0 +1,6 @@\n+#ifndef SETUP_H\n+#define SETUP_H\n+\n+int is_git_directory(const char *suspect);\n+\n+#endif /* SETUP_H */\n-- \n1.6.2.5\n\n\n\nFrom ac2dfd8fcbbafafa92e68b17cb9c419aad0134ed Mon Sep 17 00:00:00 2001\nFrom: Gerhard Wiesinger <lists@wiesinger.com>\nDate: Wed, 28 Apr 2010 07:13:09 +0200\nSubject: [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\n\n---\n builtin/init-db.c   |   38 +++++++++++++++-\n builtin/rev-parse.c |    3 +-\n cache.h             |    2 +\n environment.c       |  125 ++++++++++++++++++++++++++++++++++++++++++++++++++-\n setup.c             |    5 +-\n 5 files changed, 167 insertions(+), 6 deletions(-)\n\ndiff --git a/builtin/init-db.c b/builtin/init-db.c\nindex edc40ff..a91e762 100644\n--- a/builtin/init-db.c\n+++ b/builtin/init-db.c\n@@ -7,6 +7,7 @@\n #include \"builtin.h\"\n #include \"exec_cmd.h\"\n #include \"parse-options.h\"\n+#include \"environment.h\"\n \n #ifndef DEFAULT_GIT_TEMPLATE_DIR\n #define DEFAULT_GIT_TEMPLATE_DIR \"/usr/share/git-core/templates\"\n@@ -34,6 +35,27 @@ static void safe_create_dir(const char *dir, int share)\n \t\tdie(\"Could not make %s writable by group\", dir);\n }\n \n+static void mkdir_recusive(char *directory)\n+{\n+\tchar tmp[PATH_MAX+1];\n+\tchar *p = NULL;\n+\tsize_t len;\n+\n+\tsnprintf(tmp, sizeof(tmp), \"%s\", directory);\n+\tlen = strlen(tmp);\n+\tif(is_dir_sep(tmp[len - 1]))\n+\t\ttmp[len - 1] = 0;\n+\n+\tfor(p = tmp + 1; *p; p++)\n+\t\tif(is_dir_sep(*p)) {\n+\t\t\tchar c = *p;\n+\t\t\t*p = 0;\n+\t\t\tsafe_create_dir(tmp, 1);\n+\t\t\t*p = c;\n+\t\t}\n+\tsafe_create_dir(tmp,1);\n+}\n+\n static void copy_templates_1(char *path, int baselen,\n \t\t\t     char *template, int template_baselen,\n \t\t\t     DIR *dir)\n@@ -473,7 +495,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)\n \t * GIT_WORK_TREE makes sense only in conjunction with GIT_DIR\n \t * without --bare.  Catch the error early.\n \t */\n-\tgit_dir = getenv(GIT_DIR_ENVIRONMENT);\n+\tgit_dir = get_git_dir_from_environment();\n \tif ((!git_dir || is_bare_repository_cfg == 1)\n \t    && getenv(GIT_WORK_TREE_ENVIRONMENT))\n \t\tdie(\"%s (or --work-tree=<directory>) not allowed without \"\n@@ -490,7 +512,19 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)\n \tif (is_bare_repository_cfg < 0)\n \t\tis_bare_repository_cfg = guess_repository_type(git_dir);\n \n-\tif (!is_bare_repository_cfg) {\n+\tif (is_git_dir_global_environment()) {\n+\t\tchar *global_base_dir = get_git_dir_global_base_dir();\n+\t\tmkdir_recusive(global_base_dir);\n+\t\tif (!git_work_tree_cfg) {\n+\t\t\tgit_work_tree_cfg = xcalloc(PATH_MAX, 1);\n+\t\t\tstrncpy(git_work_tree_cfg, global_base_dir, PATH_MAX);\n+\t\t}\n+\t\tif (access(get_git_work_tree(), X_OK))\n+\t\t\tdie_errno (\"Cannot access work tree '%s'\",\n+\t\t\t\t   get_git_work_tree());\n+\t}\n+\t\t\n+\tif (!is_bare_repository_cfg && !is_git_dir_global_environment()) {\n \t\tif (git_dir) {\n \t\t\tconst char *git_dir_parent = strrchr(git_dir, '/');\n \t\t\tif (git_dir_parent) {\ndiff --git a/builtin/rev-parse.c b/builtin/rev-parse.c\nindex 8fbf9d0..b64260f 100644\n--- a/builtin/rev-parse.c\n+++ b/builtin/rev-parse.c\n@@ -9,6 +9,7 @@\n #include \"quote.h\"\n #include \"builtin.h\"\n #include \"parse-options.h\"\n+#include \"environment.h\"\n \n #define DO_REVS\t\t1\n #define DO_NOREV\t2\n@@ -642,7 +643,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t\tif (!strcmp(arg, \"--git-dir\")) {\n-\t\t\t\tconst char *gitdir = getenv(GIT_DIR_ENVIRONMENT);\n+\t\t\t\tconst char *gitdir = get_git_dir_from_environment();\n \t\t\t\tstatic char cwd[PATH_MAX];\n \t\t\t\tint len;\n \t\t\t\tif (gitdir) {\ndiff --git a/cache.h b/cache.h\nindex 5eb0573..57a647d 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -372,6 +372,8 @@ static inline enum object_type object_type(unsigned int mode)\n }\n \n #define GIT_DIR_ENVIRONMENT \"GIT_DIR\"\n+#define GIT_DIR_GLOBAL_ENVIRONMENT \"GIT_DIR_GLOBAL\"\n+#define GIT_DIR_GLOBAL_SPECIAL_ROOT_DIRECTORY \"/SPECIAL_ROOT_DIRECTORY\"\n #define GIT_WORK_TREE_ENVIRONMENT \"GIT_WORK_TREE\"\n #define DEFAULT_GIT_DIR_ENVIRONMENT \".git\"\n #define DB_ENVIRONMENT \"GIT_OBJECT_DIRECTORY\"\ndiff --git a/environment.c b/environment.c\nindex 876c5e5..d9768a9 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -8,6 +8,9 @@\n  * are.\n  */\n #include \"cache.h\"\n+#include \"setup.h\"\n+\n+#define DIR_SEPARATOR \"/\"\n \n char git_default_email[MAX_GITNAME];\n char git_default_name[MAX_GITNAME];\n@@ -80,9 +83,129 @@ const char * const local_repo_env[LOCAL_REPO_ENV_SIZE + 1] = {\n \tNULL\n };\n \n+char* path_shorten(char *path)\n+{\n+\tint index = strlen(path);\n+\n+\twhile (index > 0) {\n+\t\tindex--;\n+\t\tif (is_dir_sep(path[index])) {\n+\t\t\tpath[index] = 0;\n+\t\t\treturn path;\n+\t\t}\n+\t}\n+\n+\t// should never get here\n+\treturn \"\";\n+}\n+\n+static char *get_dir_global_environment(void)\n+{\n+\treturn getenv(GIT_DIR_GLOBAL_ENVIRONMENT);\n+}\n+\n+char *get_git_dir_global_base_dir(void)\n+{\n+\tstatic char cwd_buf[PATH_MAX+1];\n+\tstatic char dir_global_buf[PATH_MAX+1];\n+\tstatic char git_dir_buf[PATH_MAX+1];\n+\tint global_environment_len = 0;\n+\tchar *git_dir_global_environment = get_dir_global_environment();\n+\n+\tif (!getcwd(cwd_buf, sizeof(cwd_buf)-1))\n+\t\tdie_errno(\"Unable to read current working directory\");\n+\n+\tif (!is_absolute_path(git_dir_global_environment))\n+\t\tdie_errno(\"Global environment variable\" GIT_DIR_GLOBAL_ENVIRONMENT \" needs absolute path!\");\n+\n+\tstrncpy(dir_global_buf, git_dir_global_environment, sizeof(dir_global_buf));\n+\tglobal_environment_len = strlen(dir_global_buf);\n+\tif (is_dir_sep(dir_global_buf[global_environment_len]))\n+\t\tdir_global_buf[global_environment_len] = 0;\n+\n+\treturn mksnpath(git_dir_buf, sizeof(git_dir_buf), \"%s%s\", dir_global_buf, cwd_buf);\n+}\n+\n+char *get_git_dir_from_global_environment(char *git_dir_global_environment)\n+{\n+\tstatic char cwd_buf[PATH_MAX+1];\n+\tstatic char cwd_original_buf[PATH_MAX+1];\n+\tstatic char dir_global_buf[PATH_MAX+1];\n+\tstatic char git_dir_buf[PATH_MAX+1];\n+\tchar *cwd = cwd_buf;\n+\tchar *git_dir = git_dir_buf;\n+\tint found = 0;\n+\tint global_environment_len = 0;\n+\n+\tif (!getcwd(cwd_buf, sizeof(cwd_buf)-1))\n+\t\tdie_errno(\"Unable to read current working directory\");\n+\n+\tif (!is_absolute_path(git_dir_global_environment))\n+\t\tdie_errno(\"Global environment variable\" GIT_DIR_GLOBAL_ENVIRONMENT \" needs absolute path!\");\n+\n+\tstrncpy(dir_global_buf, git_dir_global_environment, sizeof(dir_global_buf));\n+\tglobal_environment_len = strlen(dir_global_buf);\n+\tif (is_dir_sep(dir_global_buf[global_environment_len]))\n+\t\tdir_global_buf[global_environment_len] = 0;\n+\n+\tif (strlen(cwd) == 1 && is_dir_sep(cwd[0]))\n+\t{\n+\t\t// special case for / git repository\n+\t\tgit_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);\n+\t\treturn git_dir;\n+\t}\n+\n+\tstrncpy(cwd_original_buf, cwd, sizeof(cwd_original_buf));\n+\n+\t/*\n+\t * Test in the following order (relative to the cwd):\n+\t * - .git (file containing \"gitdir: <path>\")\n+\t * - .git/\n+\t * - ./ (bare)\n+\t * - ../.git\n+\t * - ../.git/\n+\t * - ../ (bare)\n+\t * - ../../.git/\n+\t *   etc.\n+\t */\n+\tfor (;;) {\n+\t\tif (*cwd == '\\0') {\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tgit_dir = mksnpath(git_dir_buf, sizeof(git_dir_buf), \"%s%s\" DIR_SEPARATOR \"%s\", dir_global_buf, cwd, DEFAULT_GIT_DIR_ENVIRONMENT);\n+\t\tif (is_git_directory(git_dir)) {\n+\t\t\tfound = 1;\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tcwd = path_shorten(cwd);\n+\t}\n+\n+\tif (!found) {\n+\t\tgit_dir = mksnpath(git_dir_buf, sizeof(git_dir_buf), \"%s%s/%s\", dir_global_buf, cwd_original_buf, DEFAULT_GIT_DIR_ENVIRONMENT);\n+\t\treturn git_dir;\n+\t}\n+\n+\treturn git_dir;\n+}\n+\n+int is_git_dir_global_environment(void)\n+{\n+\treturn (get_dir_global_environment() != NULL);\n+}\n+\n+char *get_git_dir_from_environment(void)\n+{\n+\tchar *git_dir_global_environment = get_dir_global_environment();\n+\tif (git_dir_global_environment) return get_git_dir_from_global_environment(git_dir_global_environment);\n+\n+\treturn getenv(GIT_DIR_ENVIRONMENT);\n+}\n+\n static void setup_git_env(void)\n {\n-\tgit_dir = getenv(GIT_DIR_ENVIRONMENT);\n+\tgit_dir = get_git_dir_from_environment();\n \tif (!git_dir)\n \t\tgit_dir = read_gitfile_gently(DEFAULT_GIT_DIR_ENVIRONMENT);\n \tif (!git_dir)\ndiff --git a/setup.c b/setup.c\nindex 5716d90..6ee3a59 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -1,5 +1,6 @@\n #include \"cache.h\"\n #include \"dir.h\"\n+#include \"environment.h\"\n \n static int inside_git_dir = -1;\n static int inside_work_tree = -1;\n@@ -165,7 +166,7 @@ const char **get_pathspec(const char *prefix, const char **pathspec)\n  *    a proper \"ref:\", or a regular file HEAD that has a properly\n  *    formatted sha1 object name.\n  */\n-static int is_git_directory(const char *suspect)\n+int is_git_directory(const char *suspect)\n {\n \tchar path[PATH_MAX];\n \tsize_t len = strlen(suspect);\n@@ -337,7 +338,7 @@ const char *setup_git_directory_gently(int *nongit_ok)\n \t * to do any discovery, but we still do repository\n \t * validation.\n \t */\n-\tgitdirenv = getenv(GIT_DIR_ENVIRONMENT);\n+\tgitdirenv = get_git_dir_from_environment();\n \tif (gitdirenv) {\n \t\tif (PATH_MAX - 40 < strlen(gitdirenv))\n \t\t\tdie(\"'$%s' too big\", GIT_DIR_ENVIRONMENT);\n-- \n1.6.2.5\n\n\n\nFrom cca30ca806f9758bb0271f08808e2c830d9aba5e Mon Sep 17 00:00:00 2001\nFrom: Gerhard Wiesinger <lists@wiesinger.com>\nDate: Wed, 28 Apr 2010 07:30:01 +0200\nSubject: [PATCH 3/3] Updated documentation for submitting patches\n\n---\n Documentation/SubmittingPatches |    2 +-\n 1 files changed, 1 insertions(+), 1 deletions(-)\n\ndiff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches\nindex abc65de..e871032 100644\n--- a/Documentation/SubmittingPatches\n+++ b/Documentation/SubmittingPatches\n@@ -23,7 +23,7 @@ Checklist (and a short version for the impatient):\n \n \tPatch:\n \n-\t- use \"git format-patch -M\" to create the patch\n+\t- use \"git format-patch -M\" to create the patch (e.g. git format-patch -M origin/master)\n \t- do not PGP sign your patch\n \t- do not attach your patch, but read in the mail\n \t  body, unless you cannot teach your mailer to\n-- \n1.6.2.5\n\n"},{"id":"140568","messageId":"4BD7D412.5020603@dbservice.com","threadId":"23615","inReplyTo":"alpine.LFD.2.00.1004280710380.27548@bbs.intern","subject":"Re: Global .git directory","fromName":"Tomas Carnecky","fromEmail":"tom@dbservice.com","sentAt":"2010-04-28T06:22:10Z","receivedAt":"2010-04-28T06:22:10Z","isPatch":false,"sender":{"key":"tom@dbservice.com","avatar":"https://gravatar.com/avatar/900a300bdd1a8bbe086008ad78210bbee2ad2803b7d50a5cba04c1e9404bd6d2?d=mp&s=160"},"body":"On 4/28/10 7:33 AM, Gerhard Wiesinger wrote:\n> BTW: The tutorial on http://git-scm.com/ is IHMO wrong:\n> git --version\n> git version 1.6.2.5\n> git commit -m 'Explain what I changed'\n> =>\n> git commit -a -m 'Explain what I changed'\n> => Otherwise changed files are not committed, only added ones.\n> => Therefore that are 2 commit ...\n\nIf you mean the snippets right on the front page, it assumes that you \nadd all edited files.\n\n> BTW2:\n> Why is it necessary to do:\n> # Displays only changed files\n> git diff\n> # Displays only added files\n> git diff --cached\n>\n> I would like to have a full diff of my changes:\n> git diff -a\n> (or better \"git diff -a\" should be the default behaviour, I think that's\n> very confusing for new users)\n\nWhat are 'your' changes? Between HEAD and the working tree (aka. git \ndiff HEAD)?\n\ntom\n"},{"id":"140569","messageId":"l2i81b0412b1004280101ga2335a58z37d97295ab6c88e7@mail.gmail.com","threadId":"23615","inReplyTo":"alpine.LFD.2.00.1004280710380.27548@bbs.intern","subject":"Re: Global .git directory","fromName":"Alex Riesen","fromEmail":"raa.lkml@gmail.com","sentAt":"2010-04-28T08:01:58Z","receivedAt":"2010-04-28T08:01:58Z","isPatch":false,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":"On Wed, Apr 28, 2010 at 07:33, Gerhard Wiesinger <lists@wiesinger.com> wrote:\n> On Tue, 27 Apr 2010, Erik Faye-Lund wrote:\n>> Please see Documentation/SubmittingPatches. It's difficult to\n>> comment on a non-inlined patch.\n>\n> Patch done on top of HEAD.\n\nThe patches \"done on top of HEAD\" are usually useless for\neveryone, including the submitter. HEAD changes over time.\nfor instance I wont be able to apply your patches on my HEAD,\nas I have a lot of changes in my Git repo.\n\nIf you about to share your modifications, you better base your\nchanges on stable points in history, like releases (marked by\nrelease tags, like \"v1.7.1\").\n\n> BTW2:\n> Why is it necessary to do:\n\nIt is so you can distinguish between the changes in progress and\nthe changes ready to be submitted (prepared for commit).\n\n> # Displays only changed files\n> git diff\n\nTo be exact: the changes not yet staged for commit.\n\n> # Displays only added files\n> git diff --cached\n\nNo, it displays the changes ready to be committed (staged).\n\n> I would like to have a full diff of my changes:\n> git diff -a\n\nYou wouldn't use it. It is very useful to separate the phases of workflow.\n\nBTW, try using \"git status\". It'll show you both lists of changed files.\nAlso \"git gui\", and \"gitk\" make the lists visible (\"git gui\" is more like\n\"git status\", and you can commit from it).\n\n> (or better \"git diff -a\" should be the default behaviour, I think that's\n> very confusing for new users)\n\nOnly to unwilling to learn. You'd be probably the first to suggest\nto combine the two stages of change. Usually people understand\n(or get a feeling of understanding) the index even before they send\nfirst mail to the mailing list.\n"},{"id":"140590","messageId":"q2k40aa078e1004280550o322dc5b8jca74d401a5eb1abe@mail.gmail.com","threadId":"23615","inReplyTo":"alpine.LFD.2.00.1004280710380.27548@bbs.intern","subject":"Re: Global .git directory","fromName":"Erik Faye-Lund","fromEmail":"kusmabite@googlemail.com","sentAt":"2010-04-28T12:50:46Z","receivedAt":"2010-04-28T12:50:46Z","isPatch":false,"sender":{"key":"kusmabite@gmail.com","avatar":"https://avatars.githubusercontent.com/u/47073?v=4"},"body":"On Wed, Apr 28, 2010 at 7:33 AM, Gerhard Wiesinger <lists@wiesinger.com> wrote:\n> On Tue, 27 Apr 2010, Erik Faye-Lund wrote:\n>\n>> On Tue, Apr 27, 2010 at 10:06 PM, Gerhard Wiesinger <lists@wiesinger.com>\n>> wrote:\n>>>\n>>> On Tue, 27 Apr 2010, Thomas Rast wrote:\n>>>>\n>>>> (In other words, please convince us that this is actually worth\n>>>> having.)\n>>>\n>>> Ok, rather than convincing I've written a (fast) patch which works for me\n>>> :-)\n>>>\n>>> Any comments? Any (further) changes needed? Will you include it in main\n>>> git?\n>>\n>> Please see Documentation/SubmittingPatches. It's difficult to comment\n>> on a non-inlined patch.\n>>\n>\n> Patch done on top of HEAD.\n> git format-patch -M origin/master\n> 0001-Added-global-git-directory-when-environment-variable.patch\n> 0002-Added-global-git-directory-when-environment-variable.patch\n> 0003-Updated-documentation-for-submitting-patches.patch\n> Attached.\n>\n\nI was referring to that you sent the patch attached instead of inlined\n(as Documentation/SubmittingPatches suggests).\n\nBy attaching patches you force everyone who wants to review the patch\nto have to copy and manually quote the parts of the patch that they\nhave comments about instead of automatic quoting like all decent\ne-mail clients do. That way you get less people interested in the\npatch.\n\nI sent this reply because you did the right thing of cooking up a\npatch in the first place (as opposed to just arguing - very good), so\nI think you deserve a chance of getting the patch reviewed (and\npossibly included... if people agree with you, that is).\n\n-- \nErik \"kusma\" Faye-Lund\n"},{"id":"140606","messageId":"alpine.LFD.2.00.1004282148310.26569@bbs.intern","threadId":"23615","inReplyTo":"4BD7D412.5020603@dbservice.com","subject":"Re: Global .git directory","fromName":"Gerhard Wiesinger","fromEmail":"lists@wiesinger.com","sentAt":"2010-04-28T20:03:20Z","receivedAt":"2010-04-28T20:03:20Z","isPatch":false,"sender":{"key":"lists@wiesinger.com","avatar":null},"body":"\n\n\n--\nhttp://www.wiesinger.com/\n\n\nOn Wed, 28 Apr 2010, Tomas Carnecky wrote:\n\n> On 4/28/10 7:33 AM, Gerhard Wiesinger wrote:\n>> BTW: The tutorial on http://git-scm.com/ is IHMO wrong:\n>> git --version\n>> git version 1.6.2.5\n>> git commit -m 'Explain what I changed'\n>> =>\n>> git commit -a -m 'Explain what I changed'\n>> => Otherwise changed files are not committed, only added ones.\n>> => Therefore that are 2 commit ...\n>\n> If you mean the snippets right on the front page, it assumes that you add all \n> edited files.\n\nOK, I assumed that the tutorial at\nhttp://git.or.cz/course/svn.html\nwhen switching from svn to git is correct, but it isn't. I unterstand now, \nthat git is basically a patch management system where you add or remove \n(rm) files to a patch/commit set (adding in svn means adding or removing \na file). So this is very different from svn and other SCM systems.\n\nHomepage:\ngit add (files)\n=>\ngit add (all edited and added files)\nwould clarify this, too.\n\n>> BTW2:\n>> Why is it necessary to do:\n>> # Displays only changed files\n>> git diff\n>> # Displays only added files\n>> git diff --cached\n>> \n>> I would like to have a full diff of my changes:\n>> git diff -a\n>> (or better \"git diff -a\" should be the default behaviour, I think that's\n>> very confusing for new users)\n>\n> What are 'your' changes? Between HEAD and the working tree (aka. git diff \n> HEAD)?\n\ngit diff HEAD\n# no output.\n\nCiao,\nGerhard\n"},{"id":"140608","messageId":"alpine.LFD.2.00.1004282204430.29101@bbs.intern","threadId":"23615","inReplyTo":"l2i81b0412b1004280101ga2335a58z37d97295ab6c88e7@mail.gmail.com","subject":"Re: Global .git directory","fromName":"Gerhard Wiesinger","fromEmail":"lists@wiesinger.com","sentAt":"2010-04-28T20:10:03Z","receivedAt":"2010-04-28T20:10:03Z","isPatch":false,"sender":{"key":"lists@wiesinger.com","avatar":null},"body":"On Wed, 28 Apr 2010, Alex Riesen wrote:\n\n> On Wed, Apr 28, 2010 at 07:33, Gerhard Wiesinger <lists@wiesinger.com> wrote:\n>> On Tue, 27 Apr 2010, Erik Faye-Lund wrote:\n>>> Please see Documentation/SubmittingPatches. It's difficult to\n>>> comment on a non-inlined patch.\n>>\n>> Patch done on top of HEAD.\n>\n> The patches \"done on top of HEAD\" are usually useless for\n> everyone, including the submitter. HEAD changes over time.\n> for instance I wont be able to apply your patches on my HEAD,\n> as I have a lot of changes in my Git repo.\n>\n> If you about to share your modifications, you better base your\n> changes on stable points in history, like releases (marked by\n> release tags, like \"v1.7.1\").\n>\n\nPatch is made on top of v1.7.1 (it was HEAD at the time of the last pull) \naccording to git log.\n\n>> BTW2:\n>> Why is it necessary to do:\n>\n> It is so you can distinguish between the changes in progress and\n> the changes ready to be submitted (prepared for commit).\n>\n>> # Displays only changed files\n>> git diff\n>\n> To be exact: the changes not yet staged for commit.\n>\n>> # Displays only added files\n>> git diff --cached\n>\n> No, it displays the changes ready to be committed (staged).\n>\n>> I would like to have a full diff of my changes:\n>> git diff -a\n>\n> You wouldn't use it. It is very useful to separate the phases of workflow.\n>\n> BTW, try using \"git status\". It'll show you both lists of changed files.\n> Also \"git gui\", and \"gitk\" make the lists visible (\"git gui\" is more like\n> \"git status\", and you can commit from it).\n>\n>> (or better \"git diff -a\" should be the default behaviour, I think that's\n>> very confusing for new users)\n>\n> Only to unwilling to learn. You'd be probably the first to suggest\n> to combine the two stages of change. Usually people understand\n> (or get a feeling of understanding) the index even before they send\n> first mail to the mailing list.\n\nOk, as explained in previous mail, confusion was introduced from the \ntutorial at: http://git.or.cz/course/svn.html\n\nThnx for explaination so far.\n\nCiao,\nGerhard\n\n--\nhttp://www.wiesinger.com/\n"},{"id":"140609","messageId":"alpine.LFD.2.00.1004282211431.29101@bbs.intern","threadId":"23615","inReplyTo":"q2k40aa078e1004280550o322dc5b8jca74d401a5eb1abe@mail.gmail.com","subject":"Re: Global .git directory","fromName":"Gerhard Wiesinger","fromEmail":"lists@wiesinger.com","sentAt":"2010-04-28T20:22:49Z","receivedAt":"2010-04-28T20:22:49Z","isPatch":false,"sender":{"key":"lists@wiesinger.com","avatar":null},"body":"On Wed, 28 Apr 2010, Erik Faye-Lund wrote:\n\n> On Wed, Apr 28, 2010 at 7:33 AM, Gerhard Wiesinger <lists@wiesinger.com> wrote:\n>> On Tue, 27 Apr 2010, Erik Faye-Lund wrote:\n>>\n>>> On Tue, Apr 27, 2010 at 10:06 PM, Gerhard Wiesinger <lists@wiesinger.com>\n>>> wrote:\n>>>>\n>>>> On Tue, 27 Apr 2010, Thomas Rast wrote:\n>>>>>\n>>>> Ok, rather than convincing I've written a (fast) patch which works for me\n>>>> :-)\n>>>>\n>>>> Any comments? Any (further) changes needed? Will you include it in main\n>>>> git?\n>>>\n> I was referring to that you sent the patch attached instead of inlined\n> (as Documentation/SubmittingPatches suggests).\n>\n> By attaching patches you force everyone who wants to review the patch\n> to have to copy and manually quote the parts of the patch that they\n> have comments about instead of automatic quoting like all decent\n> e-mail clients do. That way you get less people interested in the\n> patch.\n>\n> I sent this reply because you did the right thing of cooking up a\n> patch in the first place (as opposed to just arguing - very good), so\n> I think you deserve a chance of getting the patch reviewed (and\n> possibly included... if people agree with you, that is).\n\nSorry, was in a hurry, and just wanted to get the patch \"out there\". No\nproblem, patch is inline now and hopefully in the right format.\n\nPatch is done after V1.7.1.\n\n>From 87cc9d17ec52a6ff2b71b9851c5b61f9e1da72be Mon Sep 17 00:00:00 2001\nFrom: Gerhard Wiesinger <lists@wiesinger.com>\nDate: Wed, 28 Apr 2010 06:46:28 +0200\nSubject: [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\n\n---\n  environment.h |    8 ++++++++\n  setup.h       |    6 ++++++\n  2 files changed, 14 insertions(+), 0 deletions(-)\n  create mode 100644 environment.h\n  create mode 100644 setup.h\n\ndiff --git a/environment.h b/environment.h\nnew file mode 100644\nindex 0000000..fb6a368\n--- /dev/null\n+++ b/environment.h\n@@ -0,0 +1,8 @@\n+#ifndef ENVIRONMENT_H\n+#define ENVIRONMENT_H\n+\n+char *get_git_dir_global_base_dir(void);\n+char *get_git_dir_from_environment(void);\n+int is_git_dir_global_environment(void);\n+\n+#endif /* ENVIRONMENT_H */\ndiff --git a/setup.h b/setup.h\nnew file mode 100644\nindex 0000000..2047ba5\n--- /dev/null\n+++ b/setup.h\n@@ -0,0 +1,6 @@\n+#ifndef SETUP_H\n+#define SETUP_H\n+\n+int is_git_directory(const char *suspect);\n+\n+#endif /* SETUP_H */\n-- \n1.6.2.5\n\n>From ac2dfd8fcbbafafa92e68b17cb9c419aad0134ed Mon Sep 17 00:00:00 2001\nFrom: Gerhard Wiesinger <lists@wiesinger.com>\nDate: Wed, 28 Apr 2010 07:13:09 +0200\nSubject: [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\n\n---\n  builtin/init-db.c   |   38 +++++++++++++++-\n  builtin/rev-parse.c |    3 +-\n  cache.h             |    2 +\n  environment.c       |  125 ++++++++++++++++++++++++++++++++++++++++++++++++++-\n  setup.c             |    5 +-\n  5 files changed, 167 insertions(+), 6 deletions(-)\n\ndiff --git a/builtin/init-db.c b/builtin/init-db.c\nindex edc40ff..a91e762 100644\n--- a/builtin/init-db.c\n+++ b/builtin/init-db.c\n@@ -7,6 +7,7 @@\n  #include \"builtin.h\"\n  #include \"exec_cmd.h\"\n  #include \"parse-options.h\"\n+#include \"environment.h\"\n\n  #ifndef DEFAULT_GIT_TEMPLATE_DIR\n  #define DEFAULT_GIT_TEMPLATE_DIR \"/usr/share/git-core/templates\"\n@@ -34,6 +35,27 @@ static void safe_create_dir(const char *dir, int share)\n  \t\tdie(\"Could not make %s writable by group\", dir);\n  }\n\n+static void mkdir_recusive(char *directory)\n+{\n+\tchar tmp[PATH_MAX+1];\n+\tchar *p = NULL;\n+\tsize_t len;\n+\n+\tsnprintf(tmp, sizeof(tmp), \"%s\", directory);\n+\tlen = strlen(tmp);\n+\tif(is_dir_sep(tmp[len - 1]))\n+\t\ttmp[len - 1] = 0;\n+\n+\tfor(p = tmp + 1; *p; p++)\n+\t\tif(is_dir_sep(*p)) {\n+\t\t\tchar c = *p;\n+\t\t\t*p = 0;\n+\t\t\tsafe_create_dir(tmp, 1);\n+\t\t\t*p = c;\n+\t\t}\n+\tsafe_create_dir(tmp,1);\n+}\n+\n  static void copy_templates_1(char *path, int baselen,\n  \t\t\t     char *template, int template_baselen,\n  \t\t\t     DIR *dir)\n@@ -473,7 +495,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)\n  \t * GIT_WORK_TREE makes sense only in conjunction with GIT_DIR\n  \t * without --bare.  Catch the error early.\n  \t */\n-\tgit_dir = getenv(GIT_DIR_ENVIRONMENT);\n+\tgit_dir = get_git_dir_from_environment();\n  \tif ((!git_dir || is_bare_repository_cfg == 1)\n  \t    && getenv(GIT_WORK_TREE_ENVIRONMENT))\n  \t\tdie(\"%s (or --work-tree=<directory>) not allowed without \"\n@@ -490,7 +512,19 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)\n  \tif (is_bare_repository_cfg < 0)\n  \t\tis_bare_repository_cfg = guess_repository_type(git_dir);\n\n-\tif (!is_bare_repository_cfg) {\n+\tif (is_git_dir_global_environment()) {\n+\t\tchar *global_base_dir = get_git_dir_global_base_dir();\n+\t\tmkdir_recusive(global_base_dir);\n+\t\tif (!git_work_tree_cfg) {\n+\t\t\tgit_work_tree_cfg = xcalloc(PATH_MAX, 1);\n+\t\t\tstrncpy(git_work_tree_cfg, global_base_dir, PATH_MAX);\n+\t\t}\n+\t\tif (access(get_git_work_tree(), X_OK))\n+\t\t\tdie_errno (\"Cannot access work tree '%s'\",\n+\t\t\t\t   get_git_work_tree());\n+\t}\n+ \n+\tif (!is_bare_repository_cfg && !is_git_dir_global_environment()) {\n  \t\tif (git_dir) {\n  \t\t\tconst char *git_dir_parent = strrchr(git_dir, '/');\n  \t\t\tif (git_dir_parent) {\ndiff --git a/builtin/rev-parse.c b/builtin/rev-parse.c\nindex 8fbf9d0..b64260f 100644\n--- a/builtin/rev-parse.c\n+++ b/builtin/rev-parse.c\n@@ -9,6 +9,7 @@\n  #include \"quote.h\"\n  #include \"builtin.h\"\n  #include \"parse-options.h\"\n+#include \"environment.h\"\n\n  #define DO_REVS\t\t1\n  #define DO_NOREV\t2\n@@ -642,7 +643,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)\n  \t\t\t\tcontinue;\n  \t\t\t}\n  \t\t\tif (!strcmp(arg, \"--git-dir\")) {\n-\t\t\t\tconst char *gitdir = getenv(GIT_DIR_ENVIRONMENT);\n+\t\t\t\tconst char *gitdir = get_git_dir_from_environment();\n  \t\t\t\tstatic char cwd[PATH_MAX];\n  \t\t\t\tint len;\n  \t\t\t\tif (gitdir) {\ndiff --git a/cache.h b/cache.h\nindex 5eb0573..57a647d 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -372,6 +372,8 @@ static inline enum object_type object_type(unsigned int mode)\n  }\n\n  #define GIT_DIR_ENVIRONMENT \"GIT_DIR\"\n+#define GIT_DIR_GLOBAL_ENVIRONMENT \"GIT_DIR_GLOBAL\"\n+#define GIT_DIR_GLOBAL_SPECIAL_ROOT_DIRECTORY \"/SPECIAL_ROOT_DIRECTORY\"\n  #define GIT_WORK_TREE_ENVIRONMENT \"GIT_WORK_TREE\"\n  #define DEFAULT_GIT_DIR_ENVIRONMENT \".git\"\n  #define DB_ENVIRONMENT \"GIT_OBJECT_DIRECTORY\"\ndiff --git a/environment.c b/environment.c\nindex 876c5e5..d9768a9 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -8,6 +8,9 @@\n   * are.\n   */\n  #include \"cache.h\"\n+#include \"setup.h\"\n+\n+#define DIR_SEPARATOR \"/\"\n\n  char git_default_email[MAX_GITNAME];\n  char git_default_name[MAX_GITNAME];\n@@ -80,9 +83,129 @@ const char * const local_repo_env[LOCAL_REPO_ENV_SIZE + 1] = {\n  \tNULL\n  };\n\n+char* path_shorten(char *path)\n+{\n+\tint index = strlen(path);\n+\n+\twhile (index > 0) {\n+\t\tindex--;\n+\t\tif (is_dir_sep(path[index])) {\n+\t\t\tpath[index] = 0;\n+\t\t\treturn path;\n+\t\t}\n+\t}\n+\n+\t// should never get here\n+\treturn \"\";\n+}\n+\n+static char *get_dir_global_environment(void)\n+{\n+\treturn getenv(GIT_DIR_GLOBAL_ENVIRONMENT);\n+}\n+\n+char *get_git_dir_global_base_dir(void)\n+{\n+\tstatic char cwd_buf[PATH_MAX+1];\n+\tstatic char dir_global_buf[PATH_MAX+1];\n+\tstatic char git_dir_buf[PATH_MAX+1];\n+\tint global_environment_len = 0;\n+\tchar *git_dir_global_environment = get_dir_global_environment();\n+\n+\tif (!getcwd(cwd_buf, sizeof(cwd_buf)-1))\n+\t\tdie_errno(\"Unable to read current working directory\");\n+\n+\tif (!is_absolute_path(git_dir_global_environment))\n+\t\tdie_errno(\"Global environment variable\" GIT_DIR_GLOBAL_ENVIRONMENT \" needs absolute path!\");\n+\n+\tstrncpy(dir_global_buf, git_dir_global_environment, sizeof(dir_global_buf));\n+\tglobal_environment_len = strlen(dir_global_buf);\n+\tif (is_dir_sep(dir_global_buf[global_environment_len]))\n+\t\tdir_global_buf[global_environment_len] = 0;\n+\n+\treturn mksnpath(git_dir_buf, sizeof(git_dir_buf), \"%s%s\", dir_global_buf, cwd_buf);\n+}\n+\n+char *get_git_dir_from_global_environment(char *git_dir_global_environment)\n+{\n+\tstatic char cwd_buf[PATH_MAX+1];\n+\tstatic char cwd_original_buf[PATH_MAX+1];\n+\tstatic char dir_global_buf[PATH_MAX+1];\n+\tstatic char git_dir_buf[PATH_MAX+1];\n+\tchar *cwd = cwd_buf;\n+\tchar *git_dir = git_dir_buf;\n+\tint found = 0;\n+\tint global_environment_len = 0;\n+\n+\tif (!getcwd(cwd_buf, sizeof(cwd_buf)-1))\n+\t\tdie_errno(\"Unable to read current working directory\");\n+\n+\tif (!is_absolute_path(git_dir_global_environment))\n+\t\tdie_errno(\"Global environment variable\" GIT_DIR_GLOBAL_ENVIRONMENT \" needs absolute path!\");\n+\n+\tstrncpy(dir_global_buf, git_dir_global_environment, sizeof(dir_global_buf));\n+\tglobal_environment_len = strlen(dir_global_buf);\n+\tif (is_dir_sep(dir_global_buf[global_environment_len]))\n+\t\tdir_global_buf[global_environment_len] = 0;\n+\n+\tif (strlen(cwd) == 1 && is_dir_sep(cwd[0]))\n+\t{\n+\t\t// special case for / git repository\n+\t\tgit_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);\n+\t\treturn git_dir;\n+\t}\n+\n+\tstrncpy(cwd_original_buf, cwd, sizeof(cwd_original_buf));\n+\n+\t/*\n+\t * Test in the following order (relative to the cwd):\n+\t * - .git (file containing \"gitdir: <path>\")\n+\t * - .git/\n+\t * - ./ (bare)\n+\t * - ../.git\n+\t * - ../.git/\n+\t * - ../ (bare)\n+\t * - ../../.git/\n+\t *   etc.\n+\t */\n+\tfor (;;) {\n+\t\tif (*cwd == '\\0') {\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tgit_dir = mksnpath(git_dir_buf, sizeof(git_dir_buf), \"%s%s\" DIR_SEPARATOR \"%s\", dir_global_buf, cwd, DEFAULT_GIT_DIR_ENVIRONMENT);\n+\t\tif (is_git_directory(git_dir)) {\n+\t\t\tfound = 1;\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tcwd = path_shorten(cwd);\n+\t}\n+\n+\tif (!found) {\n+\t\tgit_dir = mksnpath(git_dir_buf, sizeof(git_dir_buf), \"%s%s/%s\", dir_global_buf, cwd_original_buf, DEFAULT_GIT_DIR_ENVIRONMENT);\n+\t\treturn git_dir;\n+\t}\n+\n+\treturn git_dir;\n+}\n+\n+int is_git_dir_global_environment(void)\n+{\n+\treturn (get_dir_global_environment() != NULL);\n+}\n+\n+char *get_git_dir_from_environment(void)\n+{\n+\tchar *git_dir_global_environment = get_dir_global_environment();\n+\tif (git_dir_global_environment) return get_git_dir_from_global_environment(git_dir_global_environment);\n+\n+\treturn getenv(GIT_DIR_ENVIRONMENT);\n+}\n+\n  static void setup_git_env(void)\n  {\n-\tgit_dir = getenv(GIT_DIR_ENVIRONMENT);\n+\tgit_dir = get_git_dir_from_environment();\n  \tif (!git_dir)\n  \t\tgit_dir = read_gitfile_gently(DEFAULT_GIT_DIR_ENVIRONMENT);\n  \tif (!git_dir)\ndiff --git a/setup.c b/setup.c\nindex 5716d90..6ee3a59 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -1,5 +1,6 @@\n  #include \"cache.h\"\n  #include \"dir.h\"\n+#include \"environment.h\"\n\n  static int inside_git_dir = -1;\n  static int inside_work_tree = -1;\n@@ -165,7 +166,7 @@ const char **get_pathspec(const char *prefix, const char **pathspec)\n   *    a proper \"ref:\", or a regular file HEAD that has a properly\n   *    formatted sha1 object name.\n   */\n-static int is_git_directory(const char *suspect)\n+int is_git_directory(const char *suspect)\n  {\n  \tchar path[PATH_MAX];\n  \tsize_t len = strlen(suspect);\n@@ -337,7 +338,7 @@ const char *setup_git_directory_gently(int *nongit_ok)\n  \t * to do any discovery, but we still do repository\n  \t * validation.\n  \t */\n-\tgitdirenv = getenv(GIT_DIR_ENVIRONMENT);\n+\tgitdirenv = get_git_dir_from_environment();\n  \tif (gitdirenv) {\n  \t\tif (PATH_MAX - 40 < strlen(gitdirenv))\n  \t\t\tdie(\"'$%s' too big\", GIT_DIR_ENVIRONMENT);\n-- \n1.6.2.5\n\n>From cca30ca806f9758bb0271f08808e2c830d9aba5e Mon Sep 17 00:00:00 2001\nFrom: Gerhard Wiesinger <lists@wiesinger.com>\nDate: Wed, 28 Apr 2010 07:30:01 +0200\nSubject: [PATCH 3/3] Updated documentation for submitting patches\n\n---\n  Documentation/SubmittingPatches |    2 +-\n  1 files changed, 1 insertions(+), 1 deletions(-)\n\ndiff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches\nindex abc65de..e871032 100644\n--- a/Documentation/SubmittingPatches\n+++ b/Documentation/SubmittingPatches\n@@ -23,7 +23,7 @@ Checklist (and a short version for the impatient):\n\n  \tPatch:\n\n-\t- use \"git format-patch -M\" to create the patch\n+\t- use \"git format-patch -M\" to create the patch (e.g. git format-patch -M origin/master)\n  \t- do not PGP sign your patch\n  \t- do not attach your patch, but read in the mail\n  \t  body, unless you cannot teach your mailer to\n-- \n1.6.2.5\n\n\nCiao,\nGerhard\n\n--\nhttp://www.wiesinger.com/\n"},{"id":"140884","messageId":"alpine.LFD.2.00.1005040705470.4835@bbs.intern","threadId":"23615","inReplyTo":"alpine.LFD.2.00.1004282211431.29101@bbs.intern","subject":"Re: Global .git directory","fromName":"Gerhard Wiesinger","fromEmail":"lists@wiesinger.com","sentAt":"2010-05-04T05:07:08Z","receivedAt":"2010-05-04T05:07:08Z","isPatch":false,"sender":{"key":"lists@wiesinger.com","avatar":null},"body":"On Wed, 28 Apr 2010, Gerhard Wiesinger wrote:\n> Sorry, was in a hurry, and just wanted to get the patch \"out there\". No\n> problem, patch is inline now and hopefully in the right format.\n>\n> Patch is done after V1.7.1.\n>\n\nStill got no feedback ...\n\nCiao,\nGerhard\n\n--\nhttp://www.wiesinger.com/\n"},{"id":"140885","messageId":"20100504054040.GC13139@goomba","threadId":"23615","inReplyTo":"alpine.LFD.2.00.1005040705470.4835@bbs.intern","subject":"Re: Global .git directory","fromName":"Andrew Ruder","fromEmail":"andy@aeruder.net","sentAt":"2010-05-04T05:40:40Z","receivedAt":"2010-05-04T05:40:40Z","isPatch":false,"sender":{"key":"andy@aeruder.net","avatar":"https://gravatar.com/avatar/cd5239f6d3c9acac61e817de7f7d497e518415e23720f170a10e0663a7981963?d=mp&s=160"},"body":"On Tue, May 04, 2010 at 07:07:08AM +0200, Gerhard Wiesinger wrote:\n> Still got no feedback ...\n\nI'm not really a person that will be doing the reviewing but as a\nfrequent lurker on the list, I'm going to try to help you out some.\nI'll bite, but I think the lack of response is still due to a major case\nof RTFM.  Here's the things from SubmittingPatches that appear to still\nbe wrong and are most likely keeping your patch from being properly\nreviewed:\n\n>\tCommits:\n>\n>\t- make commits of logical units\n\nYour patches aren't really in logical units.  Patch 1/2 makes changes to\na header file and creates several function declarations which don't even\nexist until 2/2.  So in this case you really would just want one patch\nthere.\n\nOr even better, perhaps separate the EXISTING functionality into the API\nyou are eventually shooting for and then add your feature into the next\npatch.  I'm sure if done cleanly, some of the changes like\nget_git_dir_from_environment() could be done entirely separately from\nyour feature.  Once everybody agrees that it looks good and works the\nsame as it always has, it makes the task of reviewing your feature patch\neven easier as it will be simply adding a feature and not adding a\nfeature AND adding a new GIT_DIR API simultaneously.\n\n\n>\t- the first line of the commit message should be a short\n>\t  description and should skip the full stop\n>\t- the body should provide a meaningful commit message, which:\n>\t\t- uses the imperative, present tense: \"change\",\n>\t\t  not \"changed\" or \"changes\".\n>\t\t- includes motivation for the change, and contrasts\n>\t\t  its implementation with previous behaviour\n\nYour commit messages are very under-detailed.  At the very least you\nshould include at least as much detail as you did in your original\ne-mail to the list!  Look through git log some, you'll see that it isn't\nuncommon for patches to actually end up much shorter than the patch\nitself.  At the very least, the \"Subject\" of your patch should be much\nshorter.\n\n>\t- if you want your work included in git.git, add a\n>\t  \"Signed-off-by: Your Name <you@example.com>\" line to the\n>\t  commit message (or just use the option \"-s\" when\n>\t  committing) to confirm that you agree to the Developer's\n>\t  Certificate of Origin\n\ngit takes this one pretty seriously.  Put this in your patches now to\navoid headaches down the line.\n\n>\t- make sure that you have tests for the bug you are fixing\n\nWhile you're not exactly fixing a bug, this would benefit from a\ntestcase.\n\n>\tPatch:\n>\n>\t- use \"git format-patch -M\" to create the patch\n\nYou did this, but typically patches are one per e-mail, the subject\nbeing the [PATCH ...] line and the body being the rest rather than\nmultiple patches all just copy-pasted inline.\n\n>\t- if you change, add, or remove a command line option or\n>\t  make some other user interface change, the associated\n>\t  documentation should be updated as well.\n\nAs the person who added the above to the documentation, it sure is nice\nwhen people edit the appropriate manpages with their proposed changes\n:).\n\nI know it all seems nit-picky, but if you want to see your changes make\nit into git.git you're best off making it as EASY AS POSSIBLE for the\nreviewer to take your patch and apply it and be done with it.  This just\nisn't possible without testcases, documentation updates, etc..\nEspecially for feature additions (vs bug fixes) you really have to make\nlife as simple (and normal) as possible for reviewers, maintainers,\netc.. After all, it is a lot easier living without a feature than it is\na documented bug-fix!\n\nJust a random lurker trying to help you out here!\n\nCheers,\nAndy\n\nP.S. I'd also double-check the patch, typos (like mkdir_recusive) make\nthings look sloppy and can turn people off from reviewing (especially\nwhen it is almost the first line of the patch!)\n\n-- \nAndrew Ruder <andy@aeruder.net>\nhttp://www.aeruder.net\n"},{"id":"140886","messageId":"4BDFB87F.9070103@op5.se","threadId":"23615","inReplyTo":"20100504054040.GC13139@goomba","subject":"Re: Global .git directory","fromName":"Andreas Ericsson","fromEmail":"ae@op5.se","sentAt":"2010-05-04T06:02:39Z","receivedAt":"2010-05-04T06:02:39Z","isPatch":false,"sender":{"key":"ae@op5.se","avatar":"https://gravatar.com/avatar/426e89595c75a8f5252dd0c989e5fabe5bcac616e68557427ad9aef6b0ca342a?d=mp&s=160"},"body":"On 05/04/2010 07:40 AM, Andrew Ruder wrote:\n\n[ an exemplary breakdown of why the patch hasn't been reviewed ]\n\nI'll stash this for use in other projects. Thanks a lot Andrew :)\n\nCc-list culled a bit.\n\n-- \nAndreas Ericsson                   andreas.ericsson@op5.se\nOP5 AB                             www.op5.se\nTel: +46 8-230225                  Fax: +46 8-230231\n\nConsidering the successes of the wars on alcohol, poverty, drugs and\nterror, I think we should give some serious thought to declaring war\non peace.\n"},{"id":"140888","messageId":"alpine.LFD.2.00.1005040755360.12746@bbs.intern","threadId":"23615","inReplyTo":"20100504054040.GC13139@goomba","subject":"Re: Global .git directory","fromName":"Gerhard Wiesinger","fromEmail":"lists@wiesinger.com","sentAt":"2010-05-04T06:07:01Z","receivedAt":"2010-05-04T06:07:01Z","isPatch":false,"sender":{"key":"lists@wiesinger.com","avatar":null},"body":"On Mon, 3 May 2010, Andrew Ruder wrote:\n> On Tue, May 04, 2010 at 07:07:08AM +0200, Gerhard Wiesinger wrote:\n> I know it all seems nit-picky, but if you want to see your changes make\n> it into git.git you're best off making it as EASY AS POSSIBLE for the\n> reviewer to take your patch and apply it and be done with it.  This just\n> isn't possible without testcases, documentation updates, etc..\n> Especially for feature additions (vs bug fixes) you really have to make\n> life as simple (and normal) as possible for reviewers, maintainers,\n> etc.. After all, it is a lot easier living without a feature than it is\n> a documented bug-fix!\n>\n> Just a random lurker trying to help you out here!\n\nThnx for your feedback. Will rework some of the parts you mentioned.\n\nI think such a strict process should be valid for final commits to the git \nrepository. But for a first patch ready for discussion I think one \nshouldn't make such strict process rules. I think we are at the state \nwhether such a patch *might* be accepted and reviewers should look at the \ncontent first to have a decision for digging further (e.g. rework some \nparts of the patch) or for \"ok this makes no sense at all\". I think this \nsaves time of the reviewers and also my time (I could now make all the \nformal stuff of the patch you mentioned but when there is something \nfundamental wrong there e.g in concept all the work was useless when not \naccepted. I think there should be agreement of the roadmap of a feature \nand then a focus on formalism to finally commit a pathc. So I'm a fan of \ndiscussion and incremental work to minimise useless and typically \nfrustrating effort.)\n\nCiao,\nGerhard\n\n--\nhttp://www.wiesinger.com/\n"},{"id":"140920","messageId":"7vsk67mwse.fsf@alter.siamese.dyndns.org","threadId":"23615","inReplyTo":"20100504054040.GC13139@goomba","subject":"Re: Global .git directory","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-05-04T16:55:29Z","receivedAt":"2010-05-04T16:55:29Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Andrew Ruder <andy@aeruder.net> writes:\n\n> I'm not really a person that will be doing the reviewing but as a\n> frequent lurker on the list, I'm going to try to help you out some.\n\nThanks.\n\n> While you're not exactly fixing a bug, this would benefit from a\n> testcase.\n\nJust so that people do not misunderstand.  A test is _not_ about proving\nthat your patch fixed a bug.  It instead is to protect your change from\nfuture breakages by _other people_.\n\nHaving a test that would fail if careless others muck with related\ncodepath in the future without taking your change into account is a good\nway to make sure your new feature or your good change of behaviour keep\nworking (the alternative is for you as the author of such a valuable\nchange to stay on the list 24/7, audit all the patches that may negatively\naffect your change and veto them before they are applied, which is\nimpractical for most people).\n"}]}