{"thread":{"id":"7282","subject":"[PATCH] git-init: set core.workdir when GIT_WORK_DIR is specified","startedAt":"2007-03-17T01:58:55Z","lastAt":"2007-03-27T22:07:21Z","messageCount":18,"participants":["Matthias Lederhofer","Junio C Hamano","Johannes Schindelin"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"37295","messageId":"20070317015855.GB19305@moooo.ath.cx","threadId":"7282","inReplyTo":null,"subject":"[PATCH] git-init: set core.workdir when GIT_WORK_DIR is specified","fromName":"Matthias Lederhofer","fromEmail":"matled@gmx.net","sentAt":"2007-03-17T01:58:55Z","receivedAt":"2007-03-17T01:58:55Z","isPatch":true,"sender":{"key":"matled@gmx.net","avatar":null},"body":"git init will die with an error message before doing anything if the\nvalue of GIT_WORK_DIR is no valid directory.  GIT_WORK_DIR is also\nexpanded to an absolute path for the config file and is shown to the\nuser (core.workdir = <path>).\n\nSigned-off-by: Matthias Lederhofer <matled@gmx.net>\n---\nThis patch is on top of the 'test GIT_WORK_DIR' patch, both are for\nthe ml/workdir branch which is merged in pu.\n\nThe test only tests if core.workdir is set and not if it is the\ncorrect directory.  Is there any nice way to do this?  `pwd` will keep\nsymlinks in the path but getcwd() wont, perhaps PWD= OLDPWD= sh -c pwd\ncould do it but I don't really like it.  Comparing stat -c %d.%i for\nthe two directories would work but this is not portable (e.g. for\nfreebsd this had to be stat -f %d.%i).\n---\n builtin-init-db.c  |   33 ++++++++++++++++++++++++++++++++-\n t/t9998-workdir.sh |   15 +++++++++++++++\n 2 files changed, 47 insertions(+), 1 deletions(-)\n\ndiff --git a/builtin-init-db.c b/builtin-init-db.c\nindex 4df9fd0..f0cedb5 100644\n--- a/builtin-init-db.c\n+++ b/builtin-init-db.c\n@@ -182,6 +182,7 @@ static int create_default_files(const char *git_dir, const char *template_path)\n \tchar repo_version_string[10];\n \tint reinit;\n \tint filemode;\n+\tconst char *git_work_dir = getenv(GIT_WORKING_DIR_ENVIRONMENT);\n \n \tif (len > sizeof(path)-50)\n \t\tdie(\"insane git directory %s\", git_dir);\n@@ -252,7 +253,7 @@ static int create_default_files(const char *git_dir, const char *template_path)\n \t}\n \tgit_config_set(\"core.filemode\", filemode ? \"true\" : \"false\");\n \n-\tif (is_bare_repository()) {\n+\tif (is_bare_repository() && !git_work_dir) {\n \t\tgit_config_set(\"core.bare\", \"true\");\n \t}\n \telse {\n@@ -260,6 +261,10 @@ static int create_default_files(const char *git_dir, const char *template_path)\n \t\t/* allow template config file to override the default */\n \t\tif (log_all_ref_updates == -1)\n \t\t    git_config_set(\"core.logallrefupdates\", \"true\");\n+\t\tif (git_work_dir) {\n+\t\t\tgit_config_set(\"core.workdir\", git_work_dir);\n+\t\t\tprintf(\"core.workdir = %s\\n\", git_work_dir);\n+\t\t}\n \t}\n \treturn reinit;\n }\n@@ -276,6 +281,7 @@ static const char init_db_usage[] =\n int cmd_init_db(int argc, const char **argv, const char *prefix)\n {\n \tconst char *git_dir;\n+\tconst char *git_work_dir;\n \tconst char *sha1_dir;\n \tconst char *template_dir = NULL;\n \tchar *path;\n@@ -294,6 +300,31 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)\n \t}\n \n \t/*\n+\t * check value of $GIT_WORK_DIR\n+\t * if it is set it has to be a valid directory\n+\t */\n+\tgit_work_dir = getenv(GIT_WORKING_DIR_ENVIRONMENT);\n+\tif (git_work_dir) {\n+\t\tchar cwd[PATH_MAX];\n+\n+\t\tif (!getcwd(cwd, sizeof(cwd)) || cwd[0] != '/')\n+\t\t\tdie(\"Unable to read current working directory\");\n+\t\tif (chdir(git_work_dir))\n+\t\t\tdie(\"chdir to specified working directory %s failed\",\n+\t\t\t\tgit_work_dir);\n+\t\t/* get absolute path */\n+\t\tif (git_work_dir[0] != '/') {\n+\t\t\tchar workdir[PATH_MAX];\n+\t\t\tif (!getcwd(workdir, sizeof(workdir)) ||\n+\t\t\t\tworkdir[0] != '/')\n+\t\t\t\tdie(\"Unable to read current working directory\");\n+\t\t\tsetenv(GIT_WORKING_DIR_ENVIRONMENT, workdir, 1);\n+\t\t}\n+\t\tif (chdir(cwd))\n+\t\t\tdie(\"Cannot come back to cwd\");\n+\t}\n+\n+\t/*\n \t * Set up the default .git directory contents\n \t */\n \tgit_dir = getenv(GIT_DIR_ENVIRONMENT);\ndiff --git a/t/t9998-workdir.sh b/t/t9998-workdir.sh\nindex 57a2235..940ad1d 100755\n--- a/t/t9998-workdir.sh\n+++ b/t/t9998-workdir.sh\n@@ -88,4 +88,19 @@ test_expect_success 'repository/workdir: --is-bare-repository' \\\n test_expect_success 'repository/workdir: --is-inside-git-dir' \\\n \t'test \"false\" = \"$(git rev-parse --is-inside-git-dir)\"'\n \n+# git init\n+cd \"$top\" || exit 1\n+export GIT_DIR=$(pwd)/repository2\n+test_expect_failure 'git --work-dir non-existent init' \\\n+\t'git --work-dir non-existent init'\n+test_expect_success 'git --work-dir working/directory init' \\\n+\t'git --work-dir working/directory init'\n+test_expect_success 'config knows core.workdir' \\\n+\t'git config core.workdir'\n+git config --unset core.workdir || exit 1\n+test_expect_success 'git --work-dir `pwd`/working init' \\\n+\t'git --work-dir \"$(pwd)\"/working init'\n+test_expect_success 'config knows core.workdir' \\\n+\t'git config core.workdir'\n+\n test_done\n-- \n1.5.0.4.408.g563e1\n"},{"id":"37305","messageId":"7vbqiss4yw.fsf@assigned-by-dhcp.cox.net","threadId":"7282","inReplyTo":"20070317015855.GB19305@moooo.ath.cx","subject":"Re: [PATCH] git-init: set core.workdir when GIT_WORK_DIR is specified","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2007-03-17T07:29:27Z","receivedAt":"2007-03-17T07:29:27Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Matthias Lederhofer <matled@gmx.net> writes:\n\n> git init will die with an error message before doing anything if the\n> value of GIT_WORK_DIR is no valid directory.  GIT_WORK_DIR is also\n> expanded to an absolute path for the config file and is shown to the\n> user (core.workdir = <path>).\n\nNo other configuration variable that is automatically set gives\nsuch an unwarranted noise to the standard output.\n\nApplied with printf() removed.  Will cook further in 'pu', as I\nam seeing some questionable things that are queued in there\nalready.\n\ndiff --git a/cache.h b/cache.h\nindex a4762ed..3bacc46 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -144,6 +144,7 @@ enum object_type {\n };\n \n #define GIT_DIR_ENVIRONMENT \"GIT_DIR\"\n+#define GIT_WORKING_DIR_ENVIRONMENT \"GIT_WORK_DIR\"\n #define DEFAULT_GIT_DIR_ENVIRONMENT \".git\"\n #define DB_ENVIRONMENT \"GIT_OBJECT_DIRECTORY\"\n #define INDEX_ENVIRONMENT \"GIT_INDEX_FILE\"\n@@ -164,6 +165,7 @@ extern char *get_graft_file(void);\n \n #define ALTERNATE_DB_ENVIRONMENT \"GIT_ALTERNATE_OBJECT_DIRECTORIES\"\n \n+extern int has_working_directory;\n extern const char **get_pathspec(const char *prefix, const char **pathspec);\n extern const char *setup_git_directory_gently(int *);\n extern const char *setup_git_directory(void);\n\nI think \"has_working_directory\" and \"GIT_WORK_DIR\" are a bit\nconfusing, as everybody knows what a working directory is, and\nit is returned by `pwd`.  But that is obviously not what you\nmean by these words.\n\nWe seem to use the word \"working tree\" in our documentation to\ndifferenciate the concept of \"directory that corresponds to the\ntoplevel of the tree structure represented by the index and a\ntree object\" from the UNIXy concept of the \"current working\ndirectory\".\n\nNo matter what that concept will end up being called, has_XXX\ndoes not sound right either.  Everybody has the working tree;\nthe new mechanism is about having the working tree in unusual\nlocation, different from the conventional \"attached directly\nabove the repository\" layout.  Perhaps \"separate_working_tree\"?\n\n\ndiff --git a/environment.c b/environment.c\nindex 0151ad0..7bf6a87 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -59,8 +59,15 @@ static void setup_git_env(void)\n int is_bare_repository(void)\n {\n \tconst char *dir, *s;\n-\tif (0 <= is_bare_repository_cfg)\n-\t\treturn is_bare_repository_cfg;\n+\t/* definitely bare */\n+\tif (is_bare_repository_cfg == 1)\n+\t\treturn 1;\n+\t/* GIT_WORK_DIR is set, bare if cwd is outside */\n+\tif (has_working_directory >= 0)\n+\t\treturn !has_working_directory;\n+\t/* configuration says it is not bare */\n+\tif (is_bare_repository_cfg == 0)\n+\t\treturn 0;\n\nThis feels convoluted.  Both of these variables stay -1\n(uninitialized) when unknown, set to 0 if definite negative and\nset to 1 if definite positive, so it is unclear why you are\nchecking only positive is_bare first, then the new setting and\nthen negative is_bare later.  Wouldn't it be easier to\nunderstand if it were written like this?\n\n\t/* if configuration says so, then we obey. */\n\tif (0 <= is_bare_repository_cfg)\n\t\treturn is_bare_repository_cfg;\n\n\t/*\n         * if separate working-tree is specified, then we _do_\n         * have the working tree and the repository is not bare.\n         */\n\tif (0 <= separate_working_tree_cfg)\n        \treturn !separate_working_tree_cfg;\n \n... especially since you updated git-init so that you can\ninstruct it not to set core.bare by having working tree location\nexplicitly specified with an environment variable.\n\ndiff --git a/setup.c b/setup.c\nindex a45ea83..208124f 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -192,28 +192,143 @@ int is_inside_git_dir(void)\n \treturn inside_git_dir;\n }\n \n+static int stat_git_work_dir(struct stat *st)\n+{\n+\tchar workdir[PATH_MAX], cwd[PATH_MAX];\n+\tconst char *gitdir = getenv(GIT_DIR_ENVIRONMENT);\n+\tconst char *gitwd = getenv(GIT_WORKING_DIR_ENVIRONMENT);\n+\n+\tif (gitwd) {\n+\t\tif (!stat(gitwd, st))\n+\t\t\treturn 1;\n+\t\tdie(\"Unable to stat git working directory '%s'\", gitwd);\n+\t}\n+\n+\t/* get workdir from config */\n+\tworkdir[0] = '\\0';\n+\tgit_work_dir = workdir;\n+\tgit_config(git_workdir_config);\n+\tgit_work_dir = NULL;\n+\tif (!workdir[0])\n+\t\treturn 0;\n+\n+\t/* relative path: change to gitdir for stat */\n+\tif (workdir[0] != '/') {\n+\t\tif (!getcwd(cwd, sizeof(cwd)) || cwd[0] != '/')\n+\t\t\tdie(\"Unable to read current working directory\");\n+\t\tif (chdir(gitdir))\n+\t\t\tdie(\"Cannot change directory to '%s'\", gitdir);\n+\t}\n+\n+\tif (stat(workdir, st))\n+\t\tdie(\"Unable to stat git working directory '%s'\", workdir);\n+\n+\tif (workdir[0] != '/' && chdir(cwd))\n+\t\tdie(\"Cannot come back to cwd\");\n+\n+\treturn 1;\n+}\n\nBlech.  stat_* that returns 1 for success, 0 for wtf (perhaps\nmeaning \"n/a\")?\n\nI think naming this function \"stat\" is exposing too much\nimplementation detail.  Can the name describe _why_ the caller\nmay want to call this function, iow, to achieve what goal?  For\nexample, \"check_separate_working_tree()\" that returns false when\nseparate-working-tree feature is not used is easier to\nunderstand, I would say.  And as a side effect of checking, you\nwould get stat info back that you can later use to dig into the\nworking tree, but that is an implementation detail.\n\n+int has_working_directory = -1;\n+\n const char *setup_git_directory_gently(int *nongit_ok)\n {\n \tstatic char cwd[PATH_MAX+1];\n \tconst char *gitdirenv;\n \tint len, offset;\n \n-\t/*\n-\t * If GIT_DIR is set explicitly, we're not going\n-\t * to do any discovery, but we still do repository\n-\t * validation.\n-\t */\n\nIsn't this comment still half-valid?  We never do \"discovery\";\nwe however now allow the working tree to be specified explicitly\nas an option.\n\n \tgitdirenv = getenv(GIT_DIR_ENVIRONMENT);\n \tif (gitdirenv) {\n+\t\tstruct stat st, st_work, st_git;\n+\t\tchar *prefix;\n+\t\tchar c;\n+\t\tint len;\n+\n \t\tif (PATH_MAX - 40 < strlen(gitdirenv))\n \t\t\tdie(\"'$%s' too big\", GIT_DIR_ENVIRONMENT);\n-\t\tif (is_git_directory(gitdirenv))\n-\t\t\treturn NULL;\n-\t\tif (nongit_ok) {\n-\t\t\t*nongit_ok = 1;\n+\t\tif (!is_git_directory(gitdirenv)) {\n+\t\t\tif (nongit_ok) {\n+\t\t\t\t*nongit_ok = 1;\n+\t\t\t\treturn NULL;\n+\t\t\t}\n+\t\t\tdie(\"Not a git repository: '%s'\", gitdirenv);\n+\t\t}\n\n... and this part is the \"validation\" part.\n\n+\n+\t\t/* check for working directory */\n+\t\tif (!stat_git_work_dir(&st_work))\n \t\t\treturn NULL;\n\n... and this return is \"is the separate, explicit working tree\nfeature is in use?\".  And the rest is the new codepath that can\nbe triggered with the optional stuff.\n\n+\t\tif (inside_git_dir == -1 && stat(gitdirenv, &st_git))\n+\t\t\tdie(\"Unable to stat git directory\");\n+\t\tif (!getcwd(cwd, sizeof(cwd)-1) || cwd[0] != '/')\n+\t\t\tdie(\"Unable to read current working directory\");\n+\t\tlen = strlen(cwd);\n+\n+\t\tprefix = cwd+len;\n+\t\tfor (;;) {\n+\t\t\tc = *prefix;\n+\t\t\t*prefix = '\\0';\n+\t\t\tif (stat(cwd, &st))\n+\t\t\t\tdie(\"Unable to stat '%s'\", cwd);\n+\t\t\tif (st_work.st_dev == st.st_dev &&\n+\t\t\t    st_work.st_ino == st.st_ino)\n+\t\t\t\tbreak;\n+\t\t\tif (inside_git_dir == -1 &&\n+\t\t\t    st_git.st_dev == st.st_dev &&\n+\t\t\t    st_git.st_ino == st.st_ino)\n+\t\t\t\tinside_git_dir = 1;\n+\t\t\t*prefix = c;\n+\n+\t\t\tif (prefix == cwd+1) {\n+\t\t\t\thas_working_directory = 0;\n+\t\t\t\treturn NULL;\n+\t\t\t}\n+\t\t\twhile (*(--prefix) != '/')\n+\t\t\t\t; /* do nothing */\n+\t\t\tif (prefix == cwd)\n+\t\t\t\tprefix++;\n \t\t}\n\nIs it safe to assume that we can rely on st_dev/st_ino\ncomparison?\n\nDo we really need to do this?  Unless symlinks and automounts\nare involved, shouldn't git_work_dir be a substring of cwd and\nin that case can't you simply find the prefix with prefixcmp()?\nI know doing that would not let you test the \"is this inside\ngit-dir\" condition when GIT_DIR is relative path, but I suspect\nthe user deserves it if he is dissociating the working tree from\nthe usual repository location with the new mechanism, specify\nGIT_DIR with relative path _and_ chdir around into GIT_DIR.  I\nknow you meant well, but the above feels rather scary code for\ndubious benefit.\n"},{"id":"37309","messageId":"20070317110112.GA31595@moooo.ath.cx","threadId":"7282","inReplyTo":"7vbqiss4yw.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] git-init: set core.workdir when GIT_WORK_DIR is specified","fromName":"Matthias Lederhofer","fromEmail":"matled@gmx.net","sentAt":"2007-03-17T11:01:12Z","receivedAt":"2007-03-17T11:01:12Z","isPatch":true,"sender":{"key":"matled@gmx.net","avatar":null},"body":"Junio C Hamano <junkio@cox.net> wrote:\n> Matthias Lederhofer <matled@gmx.net> writes:\n> > git init will die with an error message before doing anything if the\n> > value of GIT_WORK_DIR is no valid directory.  GIT_WORK_DIR is also\n> > expanded to an absolute path for the config file and is shown to the\n> > user (core.workdir = <path>).\n> \n> No other configuration variable that is automatically set gives\n> such an unwarranted noise to the standard output.\n> \n> Applied with printf() removed.  Will cook further in 'pu', as I\n> am seeing some questionable things that are queued in there\n> already.\n\nI did this because GIT_WORK_DIR is automatically expanded to an\nabsolute path if it is relative.  The user might do\n    \n    $ export GIT_DIR=/path/to/repo.git\n    $ git --work-dir ../workdir init\n\nbut core.workdir will be /path/to/workdir (if there aren't any\nsymlinks in the path).\n\n> diff --git a/cache.h b/cache.h\n> index a4762ed..3bacc46 100644\n> --- a/cache.h\n> +++ b/cache.h\n> @@ -144,6 +144,7 @@ enum object_type {\n>  };\n>  \n>  #define GIT_DIR_ENVIRONMENT \"GIT_DIR\"\n> +#define GIT_WORKING_DIR_ENVIRONMENT \"GIT_WORK_DIR\"\n>  #define DEFAULT_GIT_DIR_ENVIRONMENT \".git\"\n>  #define DB_ENVIRONMENT \"GIT_OBJECT_DIRECTORY\"\n>  #define INDEX_ENVIRONMENT \"GIT_INDEX_FILE\"\n> @@ -164,6 +165,7 @@ extern char *get_graft_file(void);\n>  \n>  #define ALTERNATE_DB_ENVIRONMENT \"GIT_ALTERNATE_OBJECT_DIRECTORIES\"\n>  \n> +extern int has_working_directory;\n>  extern const char **get_pathspec(const char *prefix, const char **pathspec);\n>  extern const char *setup_git_directory_gently(int *);\n>  extern const char *setup_git_directory(void);\n> \n> I think \"has_working_directory\" and \"GIT_WORK_DIR\" are a bit\n> confusing, as everybody knows what a working directory is, and\n> it is returned by `pwd`.  But that is obviously not what you\n> mean by these words.\n>\n> We seem to use the word \"working tree\" in our documentation to\n> differenciate the concept of \"directory that corresponds to the\n> toplevel of the tree structure represented by the index and a\n> tree object\" from the UNIXy concept of the \"current working\n> directory\".\n\nOk, I didn't know about this differentiation, git grep 'working\ndirectory' Documentation shows some places that should probable get\nchanged (git-diff-index.txt for example).\n \n> No matter what that concept will end up being called, has_XXX\n> does not sound right either.  Everybody has the working tree;\n> the new mechanism is about having the working tree in unusual\n> location, different from the conventional \"attached directly\n> above the repository\" layout.  Perhaps \"separate_working_tree\"?\n\nHow about inside_working_tree?\n\n> diff --git a/environment.c b/environment.c\n> index 0151ad0..7bf6a87 100644\n> --- a/environment.c\n> +++ b/environment.c\n> @@ -59,8 +59,15 @@ static void setup_git_env(void)\n>  int is_bare_repository(void)\n>  {\n>  \tconst char *dir, *s;\n> -\tif (0 <= is_bare_repository_cfg)\n> -\t\treturn is_bare_repository_cfg;\n> +\t/* definitely bare */\n> +\tif (is_bare_repository_cfg == 1)\n> +\t\treturn 1;\n> +\t/* GIT_WORK_DIR is set, bare if cwd is outside */\n> +\tif (has_working_directory >= 0)\n> +\t\treturn !has_working_directory;\n> +\t/* configuration says it is not bare */\n> +\tif (is_bare_repository_cfg == 0)\n> +\t\treturn 0;\n\nThis only changes the behaviour if GIT_WORK_DIR is used.  In this case\nis_bare_repository is true if either core.bare is true or we are not\nin the specified working tree.  This will make commands which require\nthe working tree stop when they are not run below the working tree.\nWe could also use the old behaviour when the command is not run in the\nspecified working tree by using the cwd as working tree or guessing\nbased on the GIT_DIR name (see below).\n\nPerhaps I'm also abusing is_bare_repository because the property\n'bare' of a repository does not change if you are in- or outside of\nthe associated working tree.  But the comment for NOT_BARE says\n\"require working tree to be present\", I'm not sure if 'present' means\n'has one at all' or 'the command is run inside the working tree'.\n\nI also noticed that handle_internal_command() will use\nis_bare_repository() without calling git_config(git_default_config)\nand therefore is_bare_repository() will always use the guessing\nmechanism to find out if the repository is bare or not.  Therefore\nGIT_DIR=/path/to/.git will use the cwd as working tree but\nGIT_DIR=/path/to/foo.git will complain because git guesses it is bare\neven though the config might say otherwise.\n\n> This feels convoluted.  Both of these variables stay -1\n> (uninitialized) when unknown, set to 0 if definite negative and\n> set to 1 if definite positive, so it is unclear why you are\n> checking only positive is_bare first, then the new setting and\n> then negative is_bare later.  Wouldn't it be easier to\n> understand if it were written like this?\n> \n> \t/* if configuration says so, then we obey. */\n> \tif (0 <= is_bare_repository_cfg)\n> \t\treturn is_bare_repository_cfg;\n> \n> \t/*\n>          * if separate working-tree is specified, then we _do_\n>          * have the working tree and the repository is not bare.\n>          */\n> \tif (0 <= separate_working_tree_cfg)\n>         \treturn !separate_working_tree_cfg;\n\nSee the explanation above.\n\n> diff --git a/setup.c b/setup.c\n> index a45ea83..208124f 100644\n> --- a/setup.c\n> +++ b/setup.c\n> @@ -192,28 +192,143 @@ int is_inside_git_dir(void)\n>  \treturn inside_git_dir;\n>  }\n>  \n> +static int stat_git_work_dir(struct stat *st)\n> +{\n[..]\n> +\treturn 1;\n> +}\n> \n> Blech.  stat_* that returns 1 for success, 0 for wtf (perhaps\n> meaning \"n/a\")?\n\nYou're right, the return value should be changed to follow the\nconventions.\n\n> I think naming this function \"stat\" is exposing too much\n> implementation detail.  Can the name describe _why_ the caller\n> may want to call this function, iow, to achieve what goal?  For\n> example, \"check_separate_working_tree()\" that returns false when\n> separate-working-tree feature is not used is easier to\n> understand, I would say.  And as a side effect of checking, you\n> would get stat info back that you can later use to dig into the\n> working tree, but that is an implementation detail.\n\nWell, the implementation detail of stat is quite important to the\n(only) caller in this case.  But it also does other stuff (like\ndie'ing if the working directory does not exist) so you're right that\nit is not obvious what this function does.  As we probably wont use\nthe stat information anymore (see below) this function will be\nchanged anyway and I'll try to find a better name if some helper\nfunction like this stays in the code.\n\n>  const char *setup_git_directory_gently(int *nongit_ok)\n>  {\n>  \tstatic char cwd[PATH_MAX+1];\n>  \tconst char *gitdirenv;\n>  \tint len, offset;\n>  \n> -\t/*\n> -\t * If GIT_DIR is set explicitly, we're not going\n> -\t * to do any discovery, but we still do repository\n> -\t * validation.\n> -\t */\n> \n> Isn't this comment still half-valid?  We never do \"discovery\";\n> we however now allow the working tree to be specified explicitly\n> as an option.\n\nPerhaps something like this?\n\n/*\n * If GIT_DIR is set explicitly we do repository validation and will\n * check for GIT_WORK_TREE as toplevel working tree.\n */\n\n> +\t\t\tif (stat(cwd, &st))\n> +\t\t\t\tdie(\"Unable to stat '%s'\", cwd);\n> +\t\t\tif (st_work.st_dev == st.st_dev &&\n> +\t\t\t    st_work.st_ino == st.st_ino)\n> +\t\t\t\tbreak;\n[..]\n> \n> Is it safe to assume that we can rely on st_dev/st_ino\n> comparison?\n\nThat is the way many shells and pwd get the current working directory\nkeeping the symlinks in (this involves $PWD as reference path).  But\nwe probably don't need this, see below.\n\n> Do we really need to do this?  Unless symlinks and automounts\n> are involved, shouldn't git_work_dir be a substring of cwd and\n> in that case can't you simply find the prefix with prefixcmp()?\n\nIt should work if we do getcwd() in the cwd and the specified working\ntree.  Symlinks in the working tree pointing to another directory in\nthe working tree should work too and symlinks pointing outside are not\ninside the working tree.\n\n> I know doing that would not let you test the \"is this inside\n> git-dir\" condition when GIT_DIR is relative path, but I suspect\n> the user deserves it if he is dissociating the working tree from\n> the usual repository location with the new mechanism, specify\n> GIT_DIR with relative path _and_ chdir around into GIT_DIR.  I\n> know you meant well, but the above feels rather scary code for\n> dubious benefit.\n\nWith another getcwd() inside GIT_DIR we can probably check for this\ntoo.\n"},{"id":"37315","messageId":"20070317143452.GA21140@moooo.ath.cx","threadId":"7282","inReplyTo":"7vbqiss4yw.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] git-init: set core.workdir when GIT_WORK_DIR is specified","fromName":"Matthias Lederhofer","fromEmail":"matled@gmx.net","sentAt":"2007-03-17T14:34:52Z","receivedAt":"2007-03-17T14:34:52Z","isPatch":true,"sender":{"key":"matled@gmx.net","avatar":null},"body":"Here is a new patch series replacing ml/workdir.\n\nChanges:\n * rename GIT_WORK_DIR to GIT_WORK_TREE, --work-dir to --work-tree and\n   core.workdir to core.worktree\n * use getcwd and prefixcmp instead of stat to check if cwd is below\n   GIT_DIR or GIT_WORK_TREE\n * rename 'has_working_directory' to 'inside_working_tree'\n\nThe first two patches have not changed except for their order in the\nseries but I repost them anyway for easier review.\n\nThings I'm not sure about how/if to change (see my last mail too)\n * is_bare_repository() uses the old check\n       /* definitely bare */\n       if (is_bare_repository_cfg == 1)\n               return 1;\n       /* GIT_WORK_TREE is set, bare if cwd is outside */\n       if (inside_working_tree >= 0)\n               return !inside_working_tree;\n       /* configuration says it is not bare */\n       if (is_bare_repository_cfg == 0)\n               return 0;\n * is_bare_repository() in general\n * git init does not show the expansion of GIT_WORK_TREE to an\n   absolute path, this might confuse the user\n"},{"id":"37316","messageId":"20070317144217.GA26290@moooo.ath.cx","threadId":"7282","inReplyTo":"20070317143452.GA21140@moooo.ath.cx","subject":"[PATCH 1/5] rev-parse: --is-bare-repository option","fromName":"Matthias Lederhofer","fromEmail":"matled@gmx.net","sentAt":"2007-03-17T14:42:17Z","receivedAt":"2007-03-17T14:42:17Z","isPatch":true,"sender":{"key":"matled@gmx.net","avatar":null},"body":"Signed-off-by: Matthias Lederhofer <matled@gmx.net>\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n---\n Documentation/git-rev-parse.txt |    7 +++++++\n builtin-rev-parse.c             |    5 +++++\n git-sh-setup.sh                 |    6 +-----\n git-svn.perl                    |    2 +-\n 4 files changed, 14 insertions(+), 6 deletions(-)\n\ndiff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt\nindex ccc66aa..d024d93 100644\n--- a/Documentation/git-rev-parse.txt\n+++ b/Documentation/git-rev-parse.txt\n@@ -89,6 +89,13 @@ OPTIONS\n --git-dir::\n \tShow `$GIT_DIR` if defined else show the path to the .git directory.\n \n+--is-inside-git-dir::\n+\tWhen the current working directory is below the repository\n+\tdirectory print \"true\", otherwise \"false\".\n+\n+--is-bare-repository::\n+\tWhen the repository is bare print \"true\", otherwise \"false\".\n+\n --short, --short=number::\n \tInstead of outputting the full SHA1 values of object names try to\n \tabbreviate them to a shorter unique name. When no length is specified\ndiff --git a/builtin-rev-parse.c b/builtin-rev-parse.c\nindex 37addb2..71d5162 100644\n--- a/builtin-rev-parse.c\n+++ b/builtin-rev-parse.c\n@@ -352,6 +352,11 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)\n \t\t\t\t\t\t: \"false\");\n \t\t\t\tcontinue;\n \t\t\t}\n+\t\t\tif (!strcmp(arg, \"--is-bare-repository\")) {\n+\t\t\t\tprintf(\"%s\\n\", is_bare_repository() ? \"true\"\n+\t\t\t\t\t\t: \"false\");\n+\t\t\t\tcontinue;\n+\t\t\t}\n \t\t\tif (!prefixcmp(arg, \"--since=\")) {\n \t\t\t\tshow_datestring(\"--max-age=\", arg+8);\n \t\t\t\tcontinue;\ndiff --git a/git-sh-setup.sh b/git-sh-setup.sh\nindex f24c7f2..9ac657a 100755\n--- a/git-sh-setup.sh\n+++ b/git-sh-setup.sh\n@@ -29,11 +29,7 @@ set_reflog_action() {\n }\n \n is_bare_repository () {\n-\tgit-config --bool --get core.bare ||\n-\tcase \"$GIT_DIR\" in\n-\t.git | */.git) echo false ;;\n-\t*) echo true ;;\n-\tesac\n+\tgit-rev-parse --is-bare-repository\n }\n \n cd_to_toplevel () {\ndiff --git a/git-svn.perl b/git-svn.perl\nindex e845789..c4e343a 100755\n--- a/git-svn.perl\n+++ b/git-svn.perl\n@@ -562,7 +562,7 @@ sub post_fetch_checkout {\n \tmy $index = $ENV{GIT_INDEX_FILE} || \"$ENV{GIT_DIR}/index\";\n \treturn if -f $index;\n \n-\tchomp(my $bare = `git config --bool --get core.bare`);\n+\tchomp(my $bare = `git rev-parse --is-bare-repository`);\n \treturn if $bare eq 'true';\n \treturn if command_oneline(qw/rev-parse --is-inside-git-dir/) eq 'true';\n \tcommand_noisy(qw/read-tree -m -u -v HEAD HEAD/);\n-- \n1.5.0.4.414.g32da9\n"},{"id":"37317","messageId":"20070317144342.GB26290@moooo.ath.cx","threadId":"7282","inReplyTo":"20070317143452.GA21140@moooo.ath.cx","subject":"[PATCH 2/5] test git-rev-parse","fromName":"Matthias Lederhofer","fromEmail":"matled@gmx.net","sentAt":"2007-03-17T14:43:42Z","receivedAt":"2007-03-17T14:43:42Z","isPatch":true,"sender":{"key":"matled@gmx.net","avatar":null},"body":"this tests --is-bare-repository, --is-inside-git-dir, --show-cdup and\n--show-prefix\n\nSigned-off-by: Matthias Lederhofer <matled@gmx.net>\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n---\n t/t1500-rev-parse.sh |   57 ++++++++++++++++++++++++++++++++++++++++++++++++++\n 1 files changed, 57 insertions(+), 0 deletions(-)\n create mode 100755 t/t1500-rev-parse.sh\n\ndiff --git a/t/t1500-rev-parse.sh b/t/t1500-rev-parse.sh\nnew file mode 100755\nindex 0000000..c385660\n--- /dev/null\n+++ b/t/t1500-rev-parse.sh\n@@ -0,0 +1,57 @@\n+#!/bin/sh\n+\n+test_description='test git rev-parse'\n+. ./test-lib.sh\n+\n+test_expect_success 'toplevel: is-bare-repository' \\\n+\t'test \"false\" = \"$(git rev-parse --is-bare-repository)\"'\n+test_expect_success 'toplevel: is-inside-git-dir' \\\n+\t'test \"false\" = \"$(git rev-parse --is-inside-git-dir)\"'\n+test_expect_success 'toplevel: show-cdup' \\\n+\t'test \"\" = \"$(git rev-parse --show-cdup)\"'\n+test_expect_success 'toplevel: show-prefix' \\\n+\t'test \"\" = \"$(git rev-parse --show-prefix)\"'\n+\n+cd .git/objects || exit 1\n+test_expect_success 'in-git-dir: is-bare-repository' \\\n+\t'test \"false\" = \"$(git rev-parse --is-bare-repository)\"'\n+test_expect_success 'in-git-dir: is-inside-git-dir' \\\n+\t'test \"true\" = \"$(git rev-parse --is-inside-git-dir)\"'\n+test_expect_success 'in-git-dir: show-cdup' \\\n+\t'test \"../../\" = \"$(git rev-parse --show-cdup)\"'\n+test_expect_success 'in-git-dir: show-prefix' \\\n+\t'test \".git/objects/\" = \"$(git rev-parse --show-prefix)\"'\n+cd ../.. || exit 1\n+\n+mkdir sub || exit 1\n+cd sub || exit 1\n+test_expect_success 'subdirectory: is-bare-repository' \\\n+\t'test \"false\" = \"$(git rev-parse --is-bare-repository)\"'\n+test_expect_success 'subdirectory: is-inside-git-dir' \\\n+\t'test \"false\" = \"$(git rev-parse --is-inside-git-dir)\"'\n+test_expect_success 'subdirectory: show-cdup' \\\n+\t'test \"../\" = \"$(git rev-parse --show-cdup)\"'\n+test_expect_success 'subdirectory: show-prefix' \\\n+\t'test \"sub/\" = \"$(git rev-parse --show-prefix)\"'\n+cd .. || exit 1\n+\n+test_expect_success 'core.bare = true: is-bare-repository' \\\n+\t'git config core.bare true &&\n+\ttest \"true\" = \"$(git rev-parse --is-bare-repository)\"'\n+test_expect_success 'unset core.bare: is-bare-repository' \\\n+\t'git config --unset core.bare &&\n+\ttest \"false\" = \"$(git rev-parse --is-bare-repository)\"'\n+\n+mv .git foo.git || exit 1\n+export GIT_DIR=foo.git\n+export GIT_CONFIG=foo.git/config\n+test_expect_success 'GIT_DIR=foo.git: is-bare-repository' \\\n+\t'test \"true\" = \"$(git rev-parse --is-bare-repository)\"'\n+test_expect_success 'GIT_DIR=foo.git, core.bare = true: is-bare-repository' \\\n+\t'git --git-dir foo.git config core.bare true &&\n+\ttest \"true\" = \"$(git --git-dir foo.git rev-parse --is-bare-repository)\"'\n+test_expect_success 'GIT_DIR=foo.git, core.bare = false: is-bare-repository' \\\n+\t'git config core.bare false &&\n+\ttest \"false\" = \"$(git rev-parse --is-bare-repository)\"'\n+\n+test_done\n-- \n1.5.0.4.414.g32da9\n"},{"id":"37318","messageId":"20070317144403.GC26290@moooo.ath.cx","threadId":"7282","inReplyTo":"20070317143452.GA21140@moooo.ath.cx","subject":"[PATCH 3/5] introduce GIT_WORK_TREE environment variable","fromName":"Matthias Lederhofer","fromEmail":"matled@gmx.net","sentAt":"2007-03-17T14:44:03Z","receivedAt":"2007-03-17T14:44:03Z","isPatch":true,"sender":{"key":"matled@gmx.net","avatar":null},"body":"This environment variable can be used with GIT_DIR to\nspecify the working tree.  When GIT_DIR is not set this\nvariable is ignored.  As for GIT_DIR there is also the\noption git --work-tree which overrides the environment\nvariable and a config setting core.worktree which is used as\ndefault value.\n\nSigned-off-by: Matthias Lederhofer <matled@gmx.net>\n---\n Documentation/config.txt |    4 ++\n Documentation/git.txt    |   17 +++++++-\n cache.h                  |    2 +\n environment.c            |   11 ++++-\n git.c                    |   12 +++++-\n setup.c                  |   98 ++++++++++++++++++++++++++++++++++++++++++---\n t/test-lib.sh            |    1 +\n 7 files changed, 134 insertions(+), 11 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 953acae..dc1497d 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -162,6 +162,10 @@ repository that ends in \"/.git\" is assumed to be not bare (bare =\n false), while all other repositories are assumed to be bare (bare\n = true).\n \n+core.worktree::\n+\tPath to the working tree when GIT_DIR is set.  This can be\n+\toverriden by GIT_WORK_TREE.\n+\n core.logAllRefUpdates::\n \tUpdates to a ref <ref> is logged to the file\n \t\"$GIT_DIR/logs/<ref>\", by appending the new and old\ndiff --git a/Documentation/git.txt b/Documentation/git.txt\nindex e875e83..e870ac8 100644\n--- a/Documentation/git.txt\n+++ b/Documentation/git.txt\n@@ -10,7 +10,8 @@ SYNOPSIS\n --------\n [verse]\n 'git' [--version] [--exec-path[=GIT_EXEC_PATH]] [-p|--paginate]\n-    [--bare] [--git-dir=GIT_DIR] [--help] COMMAND [ARGS]\n+    [--bare] [--git-dir=GIT_DIR] [--work-tree=GIT_WORK_TREE]\n+    [--help] COMMAND [ARGS]\n \n DESCRIPTION\n -----------\n@@ -81,6 +82,14 @@ OPTIONS\n \tSet the path to the repository. This can also be controlled by\n \tsetting the GIT_DIR environment variable.\n \n+--work-tree=<path>::\n+\tSet the path to the working tree.  The value will be used only\n+\tin combination with $GIT_DIR or '--git-dir'.  If GIT_DIR is\n+\tset but this option is not git will assume that the current\n+\tdirectory is also the working tree.\n+\tThis can also be controlled by setting the GIT_WORK_TREE\n+\tenvironment variable.\n+\n --bare::\n \tSame as --git-dir=`pwd`.\n \n@@ -325,6 +334,12 @@ git so take care if using Cogito etc.\n \tspecifies a path to use instead of the default `.git`\n \tfor the base of the repository.\n \n+'GIT_WORK_TREE'::\n+\tSet the path to the working tree.  The value will be used only\n+\tin combination with $GIT_DIR or '--git-dir'.  If GIT_DIR is\n+\tset but this option is not git will assume that the current\n+\tdirectory is also the working tree.\n+\n git Commits\n ~~~~~~~~~~~\n 'GIT_AUTHOR_NAME'::\ndiff --git a/cache.h b/cache.h\nindex 3818e10..ced091b 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -144,6 +144,7 @@ enum object_type {\n };\n \n #define GIT_DIR_ENVIRONMENT \"GIT_DIR\"\n+#define GIT_WORKING_TREE_ENVIRONMENT \"GIT_WORK_TREE\"\n #define DEFAULT_GIT_DIR_ENVIRONMENT \".git\"\n #define DB_ENVIRONMENT \"GIT_OBJECT_DIRECTORY\"\n #define INDEX_ENVIRONMENT \"GIT_INDEX_FILE\"\n@@ -164,6 +165,7 @@ extern char *get_graft_file(void);\n \n #define ALTERNATE_DB_ENVIRONMENT \"GIT_ALTERNATE_OBJECT_DIRECTORIES\"\n \n+extern int inside_working_tree;\n extern const char **get_pathspec(const char *prefix, const char **pathspec);\n extern const char *setup_git_directory_gently(int *);\n extern const char *setup_git_directory(void);\ndiff --git a/environment.c b/environment.c\nindex 0151ad0..208b7aa 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -59,8 +59,15 @@ static void setup_git_env(void)\n int is_bare_repository(void)\n {\n \tconst char *dir, *s;\n-\tif (0 <= is_bare_repository_cfg)\n-\t\treturn is_bare_repository_cfg;\n+\t/* definitely bare */\n+\tif (is_bare_repository_cfg == 1)\n+\t\treturn 1;\n+\t/* GIT_WORK_TREE is set, bare if cwd is outside */\n+\tif (inside_working_tree >= 0)\n+\t\treturn !inside_working_tree;\n+\t/* configuration says it is not bare */\n+\tif (is_bare_repository_cfg == 0)\n+\t\treturn 0;\n \n \tdir = get_git_dir();\n \tif (!strcmp(dir, DEFAULT_GIT_DIR_ENVIRONMENT))\ndiff --git a/git.c b/git.c\nindex dde4d07..9d7eeb3 100644\n--- a/git.c\n+++ b/git.c\n@@ -4,7 +4,7 @@\n #include \"quote.h\"\n \n const char git_usage_string[] =\n-\t\"git [--version] [--exec-path[=GIT_EXEC_PATH]] [-p|--paginate] [--bare] [--git-dir=GIT_DIR] [--help] COMMAND [ARGS]\";\n+\t\"git [--version] [--exec-path[=GIT_EXEC_PATH]] [-p|--paginate] [--bare] [--git-dir=GIT_DIR] [--work-tree=GIT_WORK_TREE] [--help] COMMAND [ARGS]\";\n \n static void prepend_to_path(const char *dir, int len)\n {\n@@ -68,6 +68,16 @@ static int handle_options(const char*** argv, int* argc)\n \t\t\t(*argc)--;\n \t\t} else if (!prefixcmp(cmd, \"--git-dir=\")) {\n \t\t\tsetenv(GIT_DIR_ENVIRONMENT, cmd + 10, 1);\n+\t\t} else if (!strcmp(cmd, \"--work-tree\")) {\n+\t\t\tif (*argc < 2) {\n+\t\t\t\tfprintf(stderr, \"No directory given for --work-tree.\\n\" );\n+\t\t\t\tusage(git_usage_string);\n+\t\t\t}\n+\t\t\tsetenv(GIT_WORKING_TREE_ENVIRONMENT, (*argv)[1], 1);\n+\t\t\t(*argv)++;\n+\t\t\t(*argc)--;\n+\t\t} else if (!prefixcmp(cmd, \"--work-tree=\")) {\n+\t\t\tsetenv(GIT_WORKING_TREE_ENVIRONMENT, cmd + 11, 1);\n \t\t} else if (!strcmp(cmd, \"--bare\")) {\n \t\t\tstatic char git_dir[PATH_MAX+1];\n \t\t\tsetenv(GIT_DIR_ENVIRONMENT, getcwd(git_dir, sizeof(git_dir)), 1);\ndiff --git a/setup.c b/setup.c\nindex a45ea83..ee0719a 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -192,6 +192,18 @@ int is_inside_git_dir(void)\n \treturn inside_git_dir;\n }\n \n+static char *git_work_tree;\n+\n+static int git_work_tree_config(const char *var, const char *value)\n+{\n+\tif (!strcmp(var, \"core.worktree\")) {\n+\t\tstrlcpy(git_work_tree, value, PATH_MAX);\n+\t}\n+\treturn 0;\n+}\n+\n+int inside_working_tree = -1;\n+\n const char *setup_git_directory_gently(int *nongit_ok)\n {\n \tstatic char cwd[PATH_MAX+1];\n@@ -199,21 +211,93 @@ const char *setup_git_directory_gently(int *nongit_ok)\n \tint len, offset;\n \n \t/*\n-\t * If GIT_DIR is set explicitly, we're not going\n-\t * to do any discovery, but we still do repository\n-\t * validation.\n+\t * If GIT_DIR is set explicitly, we do repository validation\n+\t * and check for GIT_WORK_TREE as working tree.\n \t */\n \tgitdirenv = getenv(GIT_DIR_ENVIRONMENT);\n \tif (gitdirenv) {\n+\t\tconst char *gitwt;\n+\t\tchar worktree[PATH_MAX+1], gitdir[PATH_MAX+1];\n+\t\tint len;\n+\t\tint wt_rel_cwd;\n+\n \t\tif (PATH_MAX - 40 < strlen(gitdirenv))\n \t\t\tdie(\"'$%s' too big\", GIT_DIR_ENVIRONMENT);\n-\t\tif (is_git_directory(gitdirenv))\n+\t\tif (!is_git_directory(gitdirenv)) {\n+\t\t\tif (nongit_ok) {\n+\t\t\t\t*nongit_ok = 1;\n+\t\t\t\treturn NULL;\n+\t\t\t}\n+\t\t\tdie(\"Not a git repository: '%s'\", gitdirenv);\n+\t\t}\n+\n+\t\tgitwt = getenv(GIT_WORKING_TREE_ENVIRONMENT);\n+\t\twt_rel_cwd = (gitwt && gitwt[0] != '/');\n+\t\t/* get worktree from config */\n+\t\tif (!gitwt) {\n+\t\t\twt_rel_cwd = 0;\n+\t\t\tworktree[0] = '\\0';\n+\t\t\tgit_work_tree = worktree;\n+\t\t\tgit_config(git_work_tree_config);\n+\t\t\tgit_work_tree = NULL;\n+\t\t\tif (worktree[0])\n+\t\t\t\tgitwt = worktree;\n+\t\t}\n+\t\tif (!gitwt)\n \t\t\treturn NULL;\n-\t\tif (nongit_ok) {\n-\t\t\t*nongit_ok = 1;\n+\n+\t\t/* run getcwd in cwd, GIT_DIR and GIT_WORK_TREE */\n+\t\tif (!getcwd(cwd, sizeof(cwd)-1) || cwd[0] != '/')\n+\t\t\tdie(\"Unable to read current working directory\");\n+\t\tif (chdir(gitdirenv))\n+\t\t\tdie(\"Cannot change directory to '%s'\", gitdirenv);\n+\t\tif (!getcwd(gitdir, sizeof(gitdir)-1) || gitdir[0] != '/')\n+\t\t\tdie(\"Unable to read current working directory\");\n+\t\t/* relative path from old cwd */\n+\t\tif (wt_rel_cwd && chdir(cwd))\n+\t\t\tdie(\"Cannot come back to cwd\");\n+\t\tif (chdir(gitwt)) {\n+\t\t\tif (wt_rel_cwd || gitwt[0] == '/')\n+\t\t\t\tdie(\"Cannot change directory to working tree \"\n+\t\t\t\t\t\"'%s'\", gitwt);\n+\t\t\telse\n+\t\t\t\tdie(\"Cannot change directory to working tree \"\n+\t\t\t\t\t\"'%s' from $GIT_DIR\", gitwt);\n+\t\t}\n+\t\tif (!getcwd(worktree, sizeof(worktree)-1) || worktree[0] != '/')\n+\t\t\tdie(\"Unable to read current working directory\");\n+\n+\t\tlen = strlen(cwd);\n+\t\tcwd[len] = '/';\n+\t\tcwd[len+1] = '\\0';\n+\n+\t\tlen = strlen(worktree);\n+\t\tworktree[len] = '/';\n+\t\tworktree[len+1] = '\\0';\n+\t\tinside_working_tree = !prefixcmp(cwd, worktree);\n+\n+\t\tif (inside_working_tree) {\n+\t\t\tinside_git_dir = 0;\n+\t\t} else {\n+\t\t\tlen = strlen(gitdir);\n+\t\t\tgitdir[len] = '/';\n+\t\t\tgitdir[len+1] = '\\0';\n+\t\t\tinside_git_dir = !prefixcmp(cwd, gitdir);\n+\t\t\tgitdir[len] = '\\0';\n+\t\t}\n+\n+\t\tif (!inside_working_tree) {\n+\t\t\tif (chdir(cwd))\n+\t\t\t\tdie(\"Cannot come back to cwd\");\n \t\t\treturn NULL;\n \t\t}\n-\t\tdie(\"Not a git repository: '%s'\", gitdirenv);\n+\t\tif (gitdirenv[0] != '/')\n+\t\t\tsetenv(GIT_DIR_ENVIRONMENT, gitdir, 1);\n+\n+\t\tlen = strlen(worktree);\n+\t\tif (cwd[len] == '\\0')\n+\t\t\treturn NULL;\n+\t\treturn cwd+len;\n \t}\n \n \tif (!getcwd(cwd, sizeof(cwd)-1) || cwd[0] != '/')\ndiff --git a/t/test-lib.sh b/t/test-lib.sh\nindex c075474..77c6d23 100755\n--- a/t/test-lib.sh\n+++ b/t/test-lib.sh\n@@ -25,6 +25,7 @@ GIT_COMMITTER_EMAIL=committer@example.com\n GIT_COMMITTER_NAME='C O Mitter'\n unset GIT_DIFF_OPTS\n unset GIT_DIR\n+unset GIT_WORK_TREE\n unset GIT_EXTERNAL_DIFF\n unset GIT_INDEX_FILE\n unset GIT_OBJECT_DIRECTORY\n-- \n1.5.0.4.414.g32da9\n"},{"id":"37319","messageId":"20070317144456.GD26290@moooo.ath.cx","threadId":"7282","inReplyTo":"20070317143452.GA21140@moooo.ath.cx","subject":"[PATCH 4/5] test GIT_WORK_TREE","fromName":"Matthias Lederhofer","fromEmail":"matled@gmx.net","sentAt":"2007-03-17T14:44:56Z","receivedAt":"2007-03-17T14:44:56Z","isPatch":true,"sender":{"key":"matled@gmx.net","avatar":null},"body":"Signed-off-by: Matthias Lederhofer <matled@gmx.net>\n---\n t/t1501-worktree.sh |   91 +++++++++++++++++++++++++++++++++++++++++++++++++++\n 1 files changed, 91 insertions(+), 0 deletions(-)\n create mode 100755 t/t1501-worktree.sh\n\ndiff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh\nnew file mode 100755\nindex 0000000..bc08994\n--- /dev/null\n+++ b/t/t1501-worktree.sh\n@@ -0,0 +1,91 @@\n+#!/bin/sh\n+\n+test_description='test GIT_WORK_TREE'\n+. ./test-lib.sh\n+\n+export GIT_DIR=$(pwd)/repository\n+export GIT_CONFIG=\"$GIT_DIR/config\"\n+top=$(pwd) || exit 1\n+mv .git \"$GIT_DIR\" || exit 1\n+mkdir -p working/tree || exit 1\n+\n+# test setup code and precedence of core.worktree, GIT_WORK_TREE and --work-tree\n+test_expect_failure 'GIT_WORK_TREE=non-existent' \\\n+\t'env GIT_WORK_TREE=non-existent git rev-parse'\n+test_expect_success 'GIT_WORK_TREE=working/tree' \\\n+\t'env GIT_WORK_TREE=working/tree git rev-parse'\n+test_expect_success 'GIT_WORK_TREE=`pwd`/working/tree' \\\n+\t'env GIT_WORK_TREE=\"$(pwd)\"/working/tree git rev-parse'\n+\n+test_expect_success '--work-tree' \\\n+\t'git --work-tree working/tree rev-parse'\n+test_expect_success '--work-tree overrides GIT_WORK_TREE' \\\n+\t'env GIT_WORK_TREE=non-existent git --work-tree working/tree rev-parse'\n+\n+test_expect_success 'core.worktree = non-existent' \\\n+\t'git config core.worktree non-existent'\n+test_expect_failure 'core.worktree' \\\n+\t'git rev-parse'\n+test_expect_success 'GIT_WORK_TREE overrides core.worktree' \\\n+\t'env GIT_WORK_TREE=working/tree git rev-parse'\n+test_expect_success '--work-tree overrides core.worktree' \\\n+\t'git --work-tree working/tree rev-parse'\n+\n+test_expect_success 'core.worktree = `pwd`/working/tree' \\\n+\t'git --work-tree . config core.worktree \"$(pwd)\"/working/tree'\n+test_expect_success 'core.worktree' \\\n+\t'git rev-parse'\n+test_expect_success 'core.worktree = ../working/tree' \\\n+\t'git --work-tree . config core.worktree ../working/tree'\n+test_expect_success 'core.worktree' \\\n+\t'git rev-parse'\n+\n+# outside of working tree\n+test_expect_success 'outside: --is-bare-repository' \\\n+\t'test \"true\" = \"$(git rev-parse --is-bare-repository)\"'\n+\n+# in toplevel working tree\n+cd working/tree || exit 1\n+test_expect_success 'inside: --is-bare-repository' \\\n+\t'test \"false\" = \"$(git rev-parse --is-bare-repository)\"'\n+test_expect_success 'inside: --is-inside-git-dir' \\\n+\t'test \"false\" = \"$(git rev-parse --is-inside-git-dir)\"'\n+test_expect_success 'inside: --show-prefix' \\\n+\t'test \"\" = \"$(git rev-parse --show-prefix)\"'\n+test_expect_success 'inside: --show-cdup' \\\n+\t'test \"\" = \"$(git rev-parse --show-cdup)\"'\n+\n+# in subdirectory\n+mkdir -p a/b || exit 1\n+cd a/b || exit 1\n+test_expect_success 'subdirectory: --is-bare-repository' \\\n+\t'test \"false\" = \"$(git rev-parse --is-bare-repository)\"'\n+test_expect_success 'subdirectory: --is-inside-git-dir' \\\n+\t'test \"false\" = \"$(git rev-parse --is-inside-git-dir)\"'\n+test_expect_success 'subdirectory: --show-prefix' \\\n+\t'test \"a/b/\" = \"$(git rev-parse --show-prefix)\"'\n+test_expect_success 'subdirectory: --show-cdup' \\\n+\t'test \"../../\" = \"$(git rev-parse --show-cdup)\"'\n+\n+# in repository directory\n+cd \"$top/repository\" || exit 1\n+test_expect_success 'repository: --is-bare-repository' \\\n+\t'test \"true\" = \"$(git rev-parse --is-bare-repository)\"'\n+test_expect_success 'repository: --is-inside-git-dir' \\\n+\t'test \"true\" = \"$(git rev-parse --is-inside-git-dir)\"'\n+cd objects || exit 1\n+test_expect_success 'repository/objects: --is-inside-git-dir' \\\n+\t'test \"true\" = \"$(git rev-parse --is-inside-git-dir)\"'\n+cd .. || exit 1\n+\n+# worktree is subdirectory of repository\n+mkdir worktree || exit 1\n+cd worktree || exit 1\n+test_expect_success 'core.worktree = worktree' \\\n+\t'git config core.worktree worktree'\n+test_expect_success 'repository/worktree: --is-bare-repository' \\\n+\t'test \"false\" = \"$(git rev-parse --is-bare-repository)\"'\n+test_expect_success 'repository/worktree: --is-inside-git-dir' \\\n+\t'test \"false\" = \"$(git rev-parse --is-inside-git-dir)\"'\n+\n+test_done\n-- \n1.5.0.4.414.g32da9\n"},{"id":"37320","messageId":"20070317144531.GE26290@moooo.ath.cx","threadId":"7282","inReplyTo":"20070317143452.GA21140@moooo.ath.cx","subject":"[PATCH 5/5] git-init: set core.worktree when GIT_WORK_TREE is specified","fromName":"Matthias Lederhofer","fromEmail":"matled@gmx.net","sentAt":"2007-03-17T14:45:31Z","receivedAt":"2007-03-17T14:45:31Z","isPatch":true,"sender":{"key":"matled@gmx.net","avatar":null},"body":"git init will die with an error message before doing anything if the\nvalue of GIT_WORK_TREE is no valid directory.  GIT_WORK_TREE is also\nexpanded to an absolute path for the config file.\n\nSigned-off-by: Matthias Lederhofer <matled@gmx.net>\n---\n builtin-init-db.c   |   31 ++++++++++++++++++++++++++++++-\n t/t1501-worktree.sh |   15 +++++++++++++++\n 2 files changed, 45 insertions(+), 1 deletions(-)\n\ndiff --git a/builtin-init-db.c b/builtin-init-db.c\nindex 4df9fd0..4ea8c1f 100644\n--- a/builtin-init-db.c\n+++ b/builtin-init-db.c\n@@ -182,6 +182,7 @@ static int create_default_files(const char *git_dir, const char *template_path)\n \tchar repo_version_string[10];\n \tint reinit;\n \tint filemode;\n+\tconst char *git_work_tree = getenv(GIT_WORKING_TREE_ENVIRONMENT);\n \n \tif (len > sizeof(path)-50)\n \t\tdie(\"insane git directory %s\", git_dir);\n@@ -252,7 +253,7 @@ static int create_default_files(const char *git_dir, const char *template_path)\n \t}\n \tgit_config_set(\"core.filemode\", filemode ? \"true\" : \"false\");\n \n-\tif (is_bare_repository()) {\n+\tif (is_bare_repository() && !git_work_tree) {\n \t\tgit_config_set(\"core.bare\", \"true\");\n \t}\n \telse {\n@@ -260,6 +261,8 @@ static int create_default_files(const char *git_dir, const char *template_path)\n \t\t/* allow template config file to override the default */\n \t\tif (log_all_ref_updates == -1)\n \t\t    git_config_set(\"core.logallrefupdates\", \"true\");\n+\t\tif (git_work_tree)\n+\t\t\tgit_config_set(\"core.worktree\", git_work_tree);\n \t}\n \treturn reinit;\n }\n@@ -276,6 +279,7 @@ static const char init_db_usage[] =\n int cmd_init_db(int argc, const char **argv, const char *prefix)\n {\n \tconst char *git_dir;\n+\tconst char *git_work_tree;\n \tconst char *sha1_dir;\n \tconst char *template_dir = NULL;\n \tchar *path;\n@@ -294,6 +298,31 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)\n \t}\n \n \t/*\n+\t * check value of $GIT_WORK_TREE\n+\t * if it is set it has to be a valid directory\n+\t */\n+\tgit_work_tree = getenv(GIT_WORKING_TREE_ENVIRONMENT);\n+\tif (git_work_tree) {\n+\t\tchar cwd[PATH_MAX];\n+\n+\t\tif (!getcwd(cwd, sizeof(cwd)) || cwd[0] != '/')\n+\t\t\tdie(\"Unable to read current working directory\");\n+\t\tif (chdir(git_work_tree))\n+\t\t\tdie(\"chdir to specified working tree '%s' failed\",\n+\t\t\t\tgit_work_tree);\n+\t\t/* get absolute path */\n+\t\tif (git_work_tree[0] != '/') {\n+\t\t\tchar worktree[PATH_MAX];\n+\t\t\tif (!getcwd(worktree, sizeof(worktree)) ||\n+\t\t\t\tworktree[0] != '/')\n+\t\t\t\tdie(\"Unable to read current working directory\");\n+\t\t\tsetenv(GIT_WORKING_TREE_ENVIRONMENT, worktree, 1);\n+\t\t}\n+\t\tif (chdir(cwd))\n+\t\t\tdie(\"Cannot come back to cwd\");\n+\t}\n+\n+\t/*\n \t * Set up the default .git directory contents\n \t */\n \tgit_dir = getenv(GIT_DIR_ENVIRONMENT);\ndiff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh\nindex bc08994..4db4b6a 100755\n--- a/t/t1501-worktree.sh\n+++ b/t/t1501-worktree.sh\n@@ -88,4 +88,19 @@ test_expect_success 'repository/worktree: --is-bare-repository' \\\n test_expect_success 'repository/worktree: --is-inside-git-dir' \\\n \t'test \"false\" = \"$(git rev-parse --is-inside-git-dir)\"'\n \n+# git init\n+cd \"$top\" || exit 1\n+export GIT_DIR=$(pwd)/repository2\n+test_expect_failure 'git --work-tree non-existent init' \\\n+\t'git --work-tree non-existent init'\n+test_expect_success 'git --work-tree working/tree init' \\\n+\t'git --work-tree working/tree init'\n+test_expect_success 'config knows core.worktree' \\\n+\t'git config core.worktree'\n+git config --unset core.worktree || exit 1\n+test_expect_success 'git --work-tree `pwd`/working init' \\\n+\t'git --work-tree \"$(pwd)\"/working init'\n+test_expect_success 'config knows core.worktree' \\\n+\t'git config core.worktree'\n+\n test_done\n-- \n1.5.0.4.414.g32da9\n"},{"id":"37360","messageId":"7vr6rnlyzt.fsf@assigned-by-dhcp.cox.net","threadId":"7282","inReplyTo":"20070317143452.GA21140@moooo.ath.cx","subject":"Re: [PATCH] git-init: set core.workdir when GIT_WORK_DIR is specified","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2007-03-18T08:47:18Z","receivedAt":"2007-03-18T08:47:18Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Matthias Lederhofer <matled@gmx.net> writes:\n\n> Here is a new patch series replacing ml/workdir.\n>\n> Changes:\n>  * rename GIT_WORK_DIR to GIT_WORK_TREE, --work-dir to --work-tree and\n>    core.workdir to core.worktree\n>  * use getcwd and prefixcmp instead of stat to check if cwd is below\n>    GIT_DIR or GIT_WORK_TREE\n>  * rename 'has_working_directory' to 'inside_working_tree'\n>\n> The first two patches have not changed except for their order in the\n> series but I repost them anyway for easier review.\n\nThanks.  I somehow felt funny to see my sign-off on some of your\npatches, but it makes perfect sense with the above explanation.\n\nA word of caution when working with me.  \n\nAlmost always, I haven't thought things through more thoroughly\nthan the contributor did, so many of my comments of course show\na lot of cluelessness.  Your explanation on the reason why you\nstructured is_bare_repository() check that way illustrated\nissues to me and the list very well.\n\nI often mix comments that are not serious suggestions and\nquestions, just to play devil's advocate.  An earlier example\nwas \"should the relative directory (either --work-dir option or\nenvironment) be taken relative to GIT_DIR?\"  The expected answer\nwas \"it should be relative to `pwd`, because expected use of\nrelative path at runtime (as opposed to setting in\n$GIT_DIR/config) is one-shot, like this:\n\n\t$ cd top-of-project/some/where\n        $ git --work-dir=../.. do-something\n\nand making it relative to $GIT_DIR is just crazy, because the\ntop may not be related with $GIT_DIR in any easy-to-remember way\nat all.\"  I want to hear such rebuttal to make sure that the\ncontributor thought things through.  Not amending certain parts\nof the patch, with clear explanation to defend it, is always\nbetter.  Amending a patch only to satisfy such a non-serious\ncomment is to fail the test.\n\n> Things I'm not sure about how/if to change (see my last mail too)\n>  * is_bare_repository() uses the old check\n>        /* definitely bare */\n>        if (is_bare_repository_cfg == 1)\n>                return 1;\n>        /* GIT_WORK_TREE is set, bare if cwd is outside */\n>        if (inside_working_tree >= 0)\n>                return !inside_working_tree;\n>        /* configuration says it is not bare */\n>        if (is_bare_repository_cfg == 0)\n>                return 0;\n>  * is_bare_repository() in general\n\nThere is a bit of chicken and egg involved in is_bare, because\nwe need to find out where GIT_DIR is in order to find where to\nread GIT_DIR/config from, and only after reading the file we\nwould know if the user explicitly told us the repository is\nbare, and setup_gently does not want to cd-up if the repository\nis bare (i.e. there is no \"top\" to move to).\n\n>  * git init does not show the expansion of GIT_WORK_TREE to an\n>    absolute path, this might confuse the user\n\nIf the feature might confuse the user without extra output, it\nprobably is confusing to begin with, with or without it, so one\noption might be to refuse relative path when running git-init.\n\nHowever, as long as the expansion to absolute path is done\ncorrectly, I do not think there is any room for confusion.  Who\nwould want a feature that lets you set work-tree to ../.., so\nthat no matter where in the working tree you cd around, git\nassumes that the toplevel is two level up?  If you record the\nwork tree location in the configuration, you would want it to be\nstable, and I do not think anybody would expect it be stored as\nrelative.  So I thought having the printf() would be a good way\nfor debugging the absolute expansion, but after that I do not\nthink it is needed (but again, I may well be missing some issues\nyou've thought about, so please tell me otherwise).\n"},{"id":"37369","messageId":"20070318111800.GA15147@moooo.ath.cx","threadId":"7282","inReplyTo":"7vr6rnlyzt.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] git-init: set core.workdir when GIT_WORK_DIR is specified","fromName":"Matthias Lederhofer","fromEmail":"matled@gmx.net","sentAt":"2007-03-18T11:18:00Z","receivedAt":"2007-03-18T11:18:00Z","isPatch":true,"sender":{"key":"matled@gmx.net","avatar":null},"body":"Junio C Hamano <junkio@cox.net> wrote:\n> Matthias Lederhofer <matled@gmx.net> writes:\n> >  * git init does not show the expansion of GIT_WORK_TREE to an\n> >    absolute path, this might confuse the user\n> \n> If the feature might confuse the user without extra output, it\n> probably is confusing to begin with, with or without it, so one\n> option might be to refuse relative path when running git-init.\n> \n> However, as long as the expansion to absolute path is done\n> correctly, I do not think there is any room for confusion.  Who\n> would want a feature that lets you set work-tree to ../.., so\n> that no matter where in the working tree you cd around, git\n> assumes that the toplevel is two level up?  If you record the\n> work tree location in the configuration, you would want it to be\n> stable, and I do not think anybody would expect it be stored as\n> relative.  So I thought having the printf() would be a good way\n> for debugging the absolute expansion, but after that I do not\n> think it is needed (but again, I may well be missing some issues\n> you've thought about, so please tell me otherwise).\n\nI really don't know what people would expect from git --work-tree=foo\ninit and therefore I thought it might help to tell them \"core.worktree\n= /path/to/foo\".  For example one could think this would work (without\nthe message in brackets):\n\n    ~/foo$ export GIT_DIR=`pwd`/repository.git\n    ~/foo$ mkdir src\n    ~/foo$ git --work-tree=src init\n   [core.worktree = /home/user/foo/src]\n    Initialized empty Git repository in /home/user/foo/repository.git/\n    ~/foo$ cd ..; mv foo bar; cd bar\n    ~/bar$ export GIT_DIR=`pwd`/repository.git\n\nWith the message in brackets it would be clear what breaks after\nrenaming the directory.\n\nNote: git config core.worktree ../src fails after moving the working\ntree because the value of core.worktree checked for validity.\nEither run\n\n    $ git --work-tree=. config [args]\n\nor just do\n\n    $ git --work-tree=src init\n\nagain in the new location and git-init will set core.worktree again.\n"},{"id":"37391","messageId":"20070318194305.GA30843@moooo.ath.cx","threadId":"7282","inReplyTo":"20070317144403.GC26290@moooo.ath.cx","subject":"Re: [PATCH 3/5] introduce GIT_WORK_TREE environment variable","fromName":"Matthias Lederhofer","fromEmail":"matled@gmx.net","sentAt":"2007-03-18T19:43:05Z","receivedAt":"2007-03-18T19:43:05Z","isPatch":true,"sender":{"key":"matled@gmx.net","avatar":null},"body":"Matthias Lederhofer <matled@gmx.net> wrote:\n> diff --git a/setup.c b/setup.c\n[..]\n>  const char *setup_git_directory_gently(int *nongit_ok)\n>  {\n>  \tstatic char cwd[PATH_MAX+1];\n> @@ -199,21 +211,93 @@ const char *setup_git_directory_gently(int *nongit_ok)\n>  \tint len, offset;\n>  \n>  \t/*\n> -\t * If GIT_DIR is set explicitly, we're not going\n> -\t * to do any discovery, but we still do repository\n> -\t * validation.\n> +\t * If GIT_DIR is set explicitly, we do repository validation\n> +\t * and check for GIT_WORK_TREE as working tree.\n>  \t */\n>  \tgitdirenv = getenv(GIT_DIR_ENVIRONMENT);\n>  \tif (gitdirenv) {\n> +\t\tconst char *gitwt;\n> +\t\tchar worktree[PATH_MAX+1], gitdir[PATH_MAX+1];\n> +\t\tint len;\n                ^^^^^^^^\nThis is not really needed because there is already a variable len of\nthe same type.\n"},{"id":"37393","messageId":"20070318201209.GA1968@moooo.ath.cx","threadId":"7282","inReplyTo":"20070317144403.GC26290@moooo.ath.cx","subject":"Re: [PATCH 3/5] introduce GIT_WORK_TREE environment variable","fromName":"Matthias Lederhofer","fromEmail":"matled@gmx.net","sentAt":"2007-03-18T20:12:09Z","receivedAt":"2007-03-18T20:12:09Z","isPatch":true,"sender":{"key":"matled@gmx.net","avatar":null},"body":"Matthias Lederhofer <matled@gmx.net> wrote:\n> +\t\tinside_working_tree = !prefixcmp(cwd, worktree);\n[..]\n> +\t\t\tinside_git_dir = !prefixcmp(cwd, gitdir);\n\nThis time a real bug: the parameters have to be the other way around.\n"},{"id":"37394","messageId":"20070318202302.GA5191@moooo.ath.cx","threadId":"7282","inReplyTo":"20070318201209.GA1968@moooo.ath.cx","subject":"Re: [PATCH 3/5] introduce GIT_WORK_TREE environment variable","fromName":"Matthias Lederhofer","fromEmail":"matled@gmx.net","sentAt":"2007-03-18T20:23:02Z","receivedAt":"2007-03-18T20:23:02Z","isPatch":true,"sender":{"key":"matled@gmx.net","avatar":null},"body":"Matthias Lederhofer <matled@gmx.net> wrote:\n> Matthias Lederhofer <matled@gmx.net> wrote:\n> > +\t\tinside_working_tree = !prefixcmp(cwd, worktree);\n> [..]\n> > +\t\t\tinside_git_dir = !prefixcmp(cwd, gitdir);\n> \n> This time a real bug: the parameters have to be the other way around.\n\nSorry, it was right.  prefixcmp got me confused again when doing some\ntesting and the result wasn't what I expected.  I'll go and copy&paste\n100 times !prefixcmp(str, prefix) means \"begins str with prefix?\"\n"},{"id":"37396","messageId":"7v4poil2id.fsf@assigned-by-dhcp.cox.net","threadId":"7282","inReplyTo":"20070318202302.GA5191@moooo.ath.cx","subject":"Re: [PATCH 3/5] introduce GIT_WORK_TREE environment variable","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2007-03-18T20:28:58Z","receivedAt":"2007-03-18T20:28:58Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Matthias Lederhofer <matled@gmx.net> writes:\n\n> Matthias Lederhofer <matled@gmx.net> wrote:\n>> Matthias Lederhofer <matled@gmx.net> wrote:\n>> > +\t\tinside_working_tree = !prefixcmp(cwd, worktree);\n>> [..]\n>> > +\t\t\tinside_git_dir = !prefixcmp(cwd, gitdir);\n>> \n>> This time a real bug: the parameters have to be the other way around.\n>\n> Sorry, it was right.  prefixcmp got me confused again when doing some\n> testing and the result wasn't what I expected.  I'll go and copy&paste\n> 100 times !prefixcmp(str, prefix) means \"begins str with prefix?\"\n\nI do not mind replacing the whole set, but keeping track of\nthese small \"oops\", \"oh\", \"ah\" are confusing to me.\n\nCould you take a deep breath, review them yourself one more\ntime, and resend, *after* making sure that you are confident\nwith them enough to feel that you would not have to issue\n\"oops\", \"sorry\", \"ah this is better\" messages for a few days\nafter sending them out, pretty please?\n"},{"id":"37401","messageId":"20070318211836.GA12456@moooo.ath.cx","threadId":"7282","inReplyTo":"7vr6rnlyzt.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] git-init: set core.workdir when GIT_WORK_DIR is specified","fromName":"Matthias Lederhofer","fromEmail":"matled@gmx.net","sentAt":"2007-03-18T21:18:36Z","receivedAt":"2007-03-18T21:18:36Z","isPatch":true,"sender":{"key":"matled@gmx.net","avatar":null},"body":"Junio C Hamano <junkio@cox.net> wrote:\n> Matthias Lederhofer <matled@gmx.net> writes:\n> >  * is_bare_repository() in general\n> \n> There is a bit of chicken and egg involved in is_bare, because\n> we need to find out where GIT_DIR is in order to find where to\n> read GIT_DIR/config from, and only after reading the file we\n> would know if the user explicitly told us the repository is\n> bare, and setup_gently does not want to cd-up if the repository\n> is bare (i.e. there is no \"top\" to move to).\n\nHow about changing setup_git_directory_gently to do the following:\n\nFind the git directory ($GIT_DIR, .git in parent directories and \".\"\nat last).\n\nRead configuration for core.bare and core.worktree.  If core.bare is\nnot specified do the old guessing.\n\nif core.bare = true:\n    Set GIT_DIR if it isn't set yet and stop (don't change the\n    directory).\n\nif core.bare = false:\n    GIT_DIR specified:\n        use GIT_WORK_TREE, core.worktree or \".\" as working tree\n    found repository as .git directory:\n        use the parent directory of the .git directory as working tree\n    found repository in \".\":\n        use \".\" as working tree\n\n    if cwd is below the working tree:\n        change to working tree\n        inside_work_tree = 1\n        return prefix\n    if cwd is outside of the working tree:\n        inside_work_tree = 0\n        return NULL\n"},{"id":"37502","messageId":"Pine.LNX.4.63.0703191523520.22628@wbgn013.biozentrum.uni-wuerzburg.de","threadId":"7282","inReplyTo":"7vk5xensjn.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] git-init: set core.workdir when GIT_WORK_DIR is specified","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-03-19T14:24:53Z","receivedAt":"2007-03-19T14:24:53Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Sun, 18 Mar 2007, Junio C Hamano wrote:\n\n> Matthias Lederhofer <matled@gmx.net> writes:\n> \n> > Junio C Hamano <junkio@cox.net> wrote:\n> >> Matthias Lederhofer <matled@gmx.net> writes:\n> >> >  * is_bare_repository() in general\n> >> \n> >> There is a bit of chicken and egg involved in is_bare, because\n> >> we need to find out where GIT_DIR is in order to find where to\n> >> read GIT_DIR/config from, and only after reading the file we\n> >> would know if the user explicitly told us the repository is\n> >> bare, and setup_gently does not want to cd-up if the repository\n> >> is bare (i.e. there is no \"top\" to move to).\n> >\n> > How about changing setup_git_directory_gently to do the following:\n> >\n> > Find the git directory ($GIT_DIR, .git in parent directories and \".\"\n> > at last).\n> >\n> > Read configuration for core.bare and core.worktree.  If core.bare is\n> > not specified do the old guessing.\n> >\n> > if core.bare = true:\n> >     Set GIT_DIR if it isn't set yet and stop (don't change the\n> >     directory).\n> >\n> > if core.bare = false:\n> >     GIT_DIR specified:\n> >         use GIT_WORK_TREE, core.worktree or \".\" as working tree\n> >     found repository as .git directory:\n> >         use the parent directory of the .git directory as working tree\n> >     found repository in \".\":\n> >         use \".\" as working tree\n> >\n> >     if cwd is below the working tree:\n> >         change to working tree\n> >         inside_work_tree = 1\n> >         return prefix\n> >     if cwd is outside of the working tree:\n> >         inside_work_tree = 0\n> >         return NULL\n> \n> Luckily, this is an area that two of the most active git\n> regulars have touched, and I can rely on their judgement to help\n> me ;-)\n> \n> What you describe sounds like a sane outline to me.\n\nYes, I like it, too (that is, I did not find an obvious flaw in it).\n\nCiao,\nDscho\n"},{"id":"38191","messageId":"20070327220721.GA20495@moooo.ath.cx","threadId":"7282","inReplyTo":"20070317144342.GB26290@moooo.ath.cx","subject":"[PATCH(amend)] test git-rev-parse","fromName":"Matthias Lederhofer","fromEmail":"matled@gmx.net","sentAt":"2007-03-27T22:07:21Z","receivedAt":"2007-03-27T22:07:21Z","isPatch":true,"sender":{"key":"matled@gmx.net","avatar":null},"body":"this tests --is-bare-repository, --is-inside-git-dir, --show-cdup and\n--show-prefix\n\nSigned-off-by: Matthias Lederhofer <matled@gmx.net>\n---\nThe old version used --git-dir twice which was unnecessary.\n---\n t/t1500-rev-parse.sh |   57 ++++++++++++++++++++++++++++++++++++++++++++++++++\n 1 files changed, 57 insertions(+), 0 deletions(-)\n create mode 100755 t/t1500-rev-parse.sh\n\ndiff --git a/t/t1500-rev-parse.sh b/t/t1500-rev-parse.sh\nnew file mode 100755\nindex 0000000..bfc615d\n--- /dev/null\n+++ b/t/t1500-rev-parse.sh\n@@ -0,0 +1,57 @@\n+#!/bin/sh\n+\n+test_description='test git rev-parse'\n+. ./test-lib.sh\n+\n+test_expect_success 'toplevel: is-bare-repository' \\\n+\t'test \"false\" = \"$(git rev-parse --is-bare-repository)\"'\n+test_expect_success 'toplevel: is-inside-git-dir' \\\n+\t'test \"false\" = \"$(git rev-parse --is-inside-git-dir)\"'\n+test_expect_success 'toplevel: show-cdup' \\\n+\t'test \"\" = \"$(git rev-parse --show-cdup)\"'\n+test_expect_success 'toplevel: show-prefix' \\\n+\t'test \"\" = \"$(git rev-parse --show-prefix)\"'\n+\n+cd .git/objects || exit 1\n+test_expect_success 'in-git-dir: is-bare-repository' \\\n+\t'test \"false\" = \"$(git rev-parse --is-bare-repository)\"'\n+test_expect_success 'in-git-dir: is-inside-git-dir' \\\n+\t'test \"true\" = \"$(git rev-parse --is-inside-git-dir)\"'\n+test_expect_success 'in-git-dir: show-cdup' \\\n+\t'test \"../../\" = \"$(git rev-parse --show-cdup)\"'\n+test_expect_success 'in-git-dir: show-prefix' \\\n+\t'test \".git/objects/\" = \"$(git rev-parse --show-prefix)\"'\n+cd ../.. || exit 1\n+\n+mkdir sub || exit 1\n+cd sub || exit 1\n+test_expect_success 'subdirectory: is-bare-repository' \\\n+\t'test \"false\" = \"$(git rev-parse --is-bare-repository)\"'\n+test_expect_success 'subdirectory: is-inside-git-dir' \\\n+\t'test \"false\" = \"$(git rev-parse --is-inside-git-dir)\"'\n+test_expect_success 'subdirectory: show-cdup' \\\n+\t'test \"../\" = \"$(git rev-parse --show-cdup)\"'\n+test_expect_success 'subdirectory: show-prefix' \\\n+\t'test \"sub/\" = \"$(git rev-parse --show-prefix)\"'\n+cd .. || exit 1\n+\n+test_expect_success 'core.bare = true: is-bare-repository' \\\n+\t'git config core.bare true &&\n+\ttest \"true\" = \"$(git rev-parse --is-bare-repository)\"'\n+test_expect_success 'unset core.bare: is-bare-repository' \\\n+\t'git config --unset core.bare &&\n+\ttest \"false\" = \"$(git rev-parse --is-bare-repository)\"'\n+\n+mv .git foo.git || exit 1\n+export GIT_DIR=foo.git\n+export GIT_CONFIG=foo.git/config\n+test_expect_success 'GIT_DIR=foo.git: is-bare-repository' \\\n+\t'test \"true\" = \"$(git rev-parse --is-bare-repository)\"'\n+test_expect_success 'GIT_DIR=foo.git, core.bare = true: is-bare-repository' \\\n+\t'git config core.bare true &&\n+\ttest \"true\" = \"$(git rev-parse --is-bare-repository)\"'\n+test_expect_success 'GIT_DIR=foo.git, core.bare = false: is-bare-repository' \\\n+\t'git config core.bare false &&\n+\ttest \"false\" = \"$(git rev-parse --is-bare-repository)\"'\n+\n+test_done\n-- \n1.5.1.rc2.621.gd841-dirty\n"}]}