{"thread":{"id":"9263","subject":"[PATCH 0/8 REVISION2] work-tree cleanups","startedAt":"2007-07-27T18:55:21Z","lastAt":"2007-07-29T20:02:56Z","messageCount":30,"participants":["Johannes Schindelin","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":8},"messages":[{"id":"48811","messageId":"Pine.LNX.4.64.0707271851370.14781@racer.site","threadId":"9263","inReplyTo":null,"subject":"[PATCH 0/8 REVISION2] work-tree cleanups","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-07-27T18:55:21Z","receivedAt":"2007-07-27T18:55:21Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nthe patch series I sent was almost as bogus as the original work-tree \npatch series.  However, thanks to the comments, and a night's sleep, here \ncomes a revised patch series which is not only readable (it was readable \nbefore, too), but which actually works as expected.\n\nNot only does it pass the tests, but it also adds some tests of its own.\n\nAnd yes, you can \"GIT_DIR=/some/where git add <file>...\" now.  Even if you \nare not at your working tree's root.\n\nCiao,\nDscho\n"},{"id":"48812","messageId":"Pine.LNX.4.64.0707271955450.14781@racer.site","threadId":"9263","inReplyTo":"Pine.LNX.4.64.0707271851370.14781@racer.site","subject":"[PATCH 1/8] Add is_absolute_path() and make_absolute_path()","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-07-27T18:56:06Z","receivedAt":"2007-07-27T18:56:06Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"\nThis patch adds convenience functions to work with absolute paths.\nThe function is_absolute_path() should help the efforts to integrate\nthe MinGW fork.\n\nNote that make_absolute_path() returns a pointer to a static buffer.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n\n\tOkay, gone is normalize_path().  In contrast, \"make_absolute_path()\"\n\tdoes the getcwd() && chdir() && getcwd() && chdir(back) mantra, to\n\tfollow symlinks.\n\n\tAFAICT, make_absolute_path() would be a Good Thing to use for the\n\trecent lockfile stuff.\n\n Makefile             |    2 +-\n cache.h              |    5 ++++\n path.c               |   62 ++++++++++++++++++++++++++++++++++++++++++++++++++\n t/t0000-basic.sh     |   16 +++++++++++++\n test-absolute-path.c |   11 +++++++++\n 5 files changed, 95 insertions(+), 1 deletions(-)\n create mode 100644 test-absolute-path.c\n\ndiff --git a/Makefile b/Makefile\nindex d8100ad..546e008 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -936,7 +936,7 @@ endif\n \n ### Testing rules\n \n-TEST_PROGRAMS = test-chmtime$X test-genrandom$X test-date$X test-delta$X test-sha1$X test-match-trees$X\n+TEST_PROGRAMS = test-chmtime$X test-genrandom$X test-date$X test-delta$X test-sha1$X test-match-trees$X test-absolute-path$X\n \n all:: $(TEST_PROGRAMS)\n \ndiff --git a/cache.h b/cache.h\nindex 53801b8..98af530 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -358,6 +358,11 @@ int git_config_perm(const char *var, const char *value);\n int adjust_shared_perm(const char *path);\n int safe_create_leading_directories(char *path);\n char *enter_repo(char *path, int strict);\n+static inline int is_absolute_path(const char *path)\n+{\n+\treturn path[0] == '/';\n+}\n+const char *make_absolute_path(const char *path);\n \n /* Read and unpack a sha1 file into memory, write memory to a sha1 file */\n extern int sha1_object_info(const unsigned char *, unsigned long *);\ndiff --git a/path.c b/path.c\nindex c4ce962..0f7012f 100644\n--- a/path.c\n+++ b/path.c\n@@ -292,3 +292,65 @@ int adjust_shared_perm(const char *path)\n \t\treturn -2;\n \treturn 0;\n }\n+\n+/* We allow \"recursive\" symbolic links. Only within reason, though. */\n+#define MAXDEPTH 5\n+\n+const char *make_absolute_path(const char *path)\n+{\n+\tstatic char bufs[2][PATH_MAX + 1], *buf = bufs[0], *next_buf = bufs[1];\n+\tchar cwd[1024] = \"\";\n+\tint buf_index = 1, len;\n+\n+\tint depth = MAXDEPTH;\n+\tchar *last_elem = NULL;\n+\tstruct stat st;\n+\n+\tif (strlcpy(buf, path, PATH_MAX) >= PATH_MAX)\n+\t\tdie (\"Too long path: %.*s\", 60, path);\n+\n+\twhile (depth--) {\n+\t\tif (stat(buf, &st) || !S_ISDIR(st.st_mode)) {\n+\t\t\tchar *last_slash = strrchr(buf, '/');\n+\t\t\t*last_slash = '\\0';\n+\t\t\tlast_elem = xstrdup(last_slash + 1);\n+\t\t}\n+\n+\t\tif (*buf) {\n+\t\t\tif (!*cwd && getcwd(cwd, sizeof(cwd)) < 0)\n+\t\t\t\tdie (\"Could not get current working directory\");\n+\n+\t\t\tif (chdir(buf))\n+\t\t\t\tdie (\"Could not switch to '%s'\", buf);\n+\t\t}\n+\t\tif (getcwd(buf, PATH_MAX) < 0)\n+\t\t\tdie (\"Could not get current working directory\");\n+\n+\t\tif (last_elem) {\n+\t\t\tint len = strlen(buf);\n+\t\t\tif (len + strlen(last_elem) + 2 > PATH_MAX)\n+\t\t\t\tdie (\"Too long path name: '%s/%s'\",\n+\t\t\t\t\t\tbuf, last_elem);\n+\t\t\tbuf[len] = '/';\n+\t\t\tstrcpy(buf + len + 1, last_elem);\n+\t\t\tfree(last_elem);\n+\t\t\tlast_elem = NULL;\n+\t\t}\n+\n+\t\tif (!lstat(buf, &st) && S_ISLNK(st.st_mode)) {\n+\t\t\tlen = readlink(buf, next_buf, PATH_MAX);\n+\t\t\tif (len < 0)\n+\t\t\t\tdie (\"Invalid symlink: %s\", buf);\n+\t\t\tnext_buf[len] = '\\0';\n+\t\t\tbuf = next_buf;\n+\t\t\tbuf_index = 1 - buf_index;\n+\t\t\tnext_buf = bufs[buf_index];\n+\t\t} else\n+\t\t\tbreak;\n+\t}\n+\n+\tif (*cwd && chdir(cwd))\n+\t\tdie (\"Could not change back to '%s'\", cwd);\n+\n+\treturn buf;\n+}\ndiff --git a/t/t0000-basic.sh b/t/t0000-basic.sh\nindex 4bba9c0..4e49d59 100755\n--- a/t/t0000-basic.sh\n+++ b/t/t0000-basic.sh\n@@ -281,4 +281,20 @@ test_expect_success 'update-index D/F conflict' '\n \ttest $numpath0 = 1\n '\n \n+test_expect_success 'absolute path works as expected' '\n+\tmkdir first &&\n+\tln -s ../.git first/.git &&\n+\tmkdir second &&\n+\tln -s ../first second/other &&\n+\tmkdir third &&\n+\tdir=\"$(cd .git; pwd -P)\" &&\n+\tdir2=third/../second/other/.git &&\n+\ttest \"$dir\" = \"$(test-absolute-path $dir2)\" &&\n+\tfile=\"$dir\"/index &&\n+\ttest \"$file\" = \"$(test-absolute-path $dir2/index)\" &&\n+\tln -s ../first/file .git/syml &&\n+\tsym=\"$(cd first; pwd -P)\"/file &&\n+\ttest \"$sym\" = \"$(test-absolute-path $dir2/syml)\"\n+'\n+\n test_done\ndiff --git a/test-absolute-path.c b/test-absolute-path.c\nnew file mode 100644\nindex 0000000..c959ea2\n--- /dev/null\n+++ b/test-absolute-path.c\n@@ -0,0 +1,11 @@\n+#include \"cache.h\"\n+\n+int main(int argc, char **argv)\n+{\n+\twhile (argc > 1) {\n+\t\tputs(make_absolute_path(argv[1]));\n+\t\targc--;\n+\t\targv++;\n+\t}\n+\treturn 0;\n+}\n-- \n1.5.3.rc3.18.g49a1\n"},{"id":"48813","messageId":"Pine.LNX.4.64.0707271956140.14781@racer.site","threadId":"9263","inReplyTo":"Pine.LNX.4.64.0707271851370.14781@racer.site","subject":"[PATCH 2/8] Add functions get_relative_cwd() and is_inside_dir()","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-07-27T18:56:35Z","receivedAt":"2007-07-27T18:56:35Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"\nThe function get_relative_cwd() works just as getcwd(), only that it\ntakes an absolute path as additional parameter, returning the prefix\nof the current working directory relative to the given path.  If the\ncwd is no subdirectory of the given path, it returns NULL.\n\nis_inside_dir() is just a trivial wrapper over get_relative_cwd().\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n\tThis patch should be the same as I sent out earlier.  Just to\n\tmake sure that you get the correct version, I send it again.\n\n dir.c |   30 ++++++++++++++++++++++++++++++\n dir.h |    3 +++\n 2 files changed, 33 insertions(+), 0 deletions(-)\n\ndiff --git a/dir.c b/dir.c\nindex 8d8faf5..c16a004 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -642,3 +642,33 @@ file_exists(const char *f)\n   struct stat sb;\n   return stat(f, &sb) == 0;\n }\n+\n+char *get_relative_cwd(char *buffer, int size, const char *dir)\n+{\n+\tchar *cwd = buffer;\n+\n+\tif (!dir)\n+\t\treturn 0;\n+\n+\tif (!getcwd(buffer, PATH_MAX))\n+\t\treturn 0;\n+\n+\tif (!is_absolute_path(dir))\n+\t\tdir = make_absolute_path(dir);\n+\n+\twhile (*dir && *dir == *cwd) {\n+\t\tdir++;\n+\t\tcwd++;\n+\t}\n+\tif (*dir)\n+\t\treturn NULL;\n+\tif (*cwd == '/')\n+\t\treturn cwd + 1;\n+\treturn cwd;\n+}\n+\n+int is_inside_dir(const char *dir)\n+{\n+\tchar buffer[PATH_MAX];\n+\treturn get_relative_cwd(buffer, sizeof(buffer), dir) != NULL;\n+}\ndiff --git a/dir.h b/dir.h\nindex ec0e8ab..f55a87b 100644\n--- a/dir.h\n+++ b/dir.h\n@@ -61,4 +61,7 @@ extern void add_exclude(const char *string, const char *base,\n extern int file_exists(const char *);\n extern struct dir_entry *dir_add_name(struct dir_struct *dir, const char *pathname, int len);\n \n+extern char *get_relative_cwd(char *buffer, int size, const char *dir);\n+extern int is_inside_dir(const char *dir);\n+\n #endif\n-- \n1.5.3.rc3.18.g49a1\n"},{"id":"48814","messageId":"Pine.LNX.4.64.0707271956420.14781@racer.site","threadId":"9263","inReplyTo":"Pine.LNX.4.64.0707271851370.14781@racer.site","subject":"[PATCH 3/8] Clean up work-tree handling","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-07-27T18:56:57Z","receivedAt":"2007-07-27T18:56:57Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"\nThe old version of work-tree support was an unholy mess, barely readable,\nand not to the point.\n\nFor example, why do you have to provide a worktree, when it is not used?\nAs in \"git status\".  Now it works.\n\nAnother riddle was: if you can have work trees inside the git dir, why\nare some programs complaining that they need a work tree?\n\nIOW when inside repo.git/work, where GIT_DIR points to repo.git\nand GIT_WORK_TREE to work, and cwd is work, --is-inside-git-dir _must_\nreturn true, because it is _in the git dir_, but scripts _must_ test\nfor the right thing.\n\nAlso, GIT_DIR=../.git should behave the same as if no GIT_DIR was\nspecified, unless there is a repository in the current working directory.\nIt does now.\n\nIn related news, a long standing bug was fixed: when in .git/bla/x.git/,\nwhich is a bare repository, git formerly assumed ../.. to be the\nappropriate git dir.  This problem was reported by Shawn Pearce to have\ncaused much pain, where a colleague mistakenly ran \"git init\" in \"/\" a\nlong time ago, and bare repositories just would not work.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n\tNot only because of ohloh am I proud that in spite of removing\n\tmore lines than I added, there were more comments added than\n\tremoved...\n\n builtin-rev-parse.c |   12 +--\n cache.h             |    2 +\n environment.c       |   32 +++++--\n setup.c             |  270 ++++++++++++++++++++++-----------------------------\n 4 files changed, 143 insertions(+), 173 deletions(-)\n\ndiff --git a/builtin-rev-parse.c b/builtin-rev-parse.c\nindex 497903a..3f787a8 100644\n--- a/builtin-rev-parse.c\n+++ b/builtin-rev-parse.c\n@@ -320,15 +320,9 @@ 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, \"--show-cdup\")) {\n-\t\t\t\tconst char *pfx = prefix;\n-\t\t\t\twhile (pfx) {\n-\t\t\t\t\tpfx = strchr(pfx, '/');\n-\t\t\t\t\tif (pfx) {\n-\t\t\t\t\t\tpfx++;\n-\t\t\t\t\t\tprintf(\"../\");\n-\t\t\t\t\t}\n-\t\t\t\t}\n-\t\t\t\tputchar('\\n');\n+\t\t\t\tconst char *work_tree = get_git_work_tree();\n+\t\t\t\tif (work_tree)\n+\t\t\t\t\tprintf(\"%s\\n\", work_tree);\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t\tif (!strcmp(arg, \"--git-dir\")) {\ndiff --git a/cache.h b/cache.h\nindex 98af530..c0cab34 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -208,12 +208,14 @@ enum object_type {\n extern int is_bare_repository_cfg;\n extern int is_bare_repository(void);\n extern int is_inside_git_dir(void);\n+extern char *git_work_tree_cfg;\n extern int is_inside_work_tree(void);\n extern const char *get_git_dir(void);\n extern char *get_object_directory(void);\n extern char *get_refs_directory(void);\n extern char *get_index_file(void);\n extern char *get_graft_file(void);\n+extern const char *get_git_work_tree(void);\n \n #define ALTERNATE_DB_ENVIRONMENT \"GIT_ALTERNATE_OBJECT_DIRECTORIES\"\n \ndiff --git a/environment.c b/environment.c\nindex f83fb9e..cb112a4 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -35,6 +35,10 @@ int pager_in_use;\n int pager_use_color = 1;\n int auto_crlf = 0;\t/* 1: both ways, -1: only when adding git objects */\n \n+/* This is set by setup_git_dir_gently() and/or git_default_config() */\n+char *git_work_tree_cfg;\n+static const char *work_tree;\n+\n static const char *git_dir;\n static char *git_object_dir, *git_index_file, *git_refs_dir, *git_graft_file;\n \n@@ -62,15 +66,8 @@ static void setup_git_env(void)\n \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-\n-\tdir = get_git_dir();\n-\tif (!strcmp(dir, DEFAULT_GIT_DIR_ENVIRONMENT))\n-\t\treturn 0;\n-\ts = strrchr(dir, '/');\n-\treturn !s || strcmp(s + 1, DEFAULT_GIT_DIR_ENVIRONMENT);\n+\t/* if core.bare is not 'false', let's see if there is a work tree */\n+\treturn is_bare_repository_cfg && !get_git_work_tree();\n }\n \n const char *get_git_dir(void)\n@@ -80,6 +77,23 @@ const char *get_git_dir(void)\n \treturn git_dir;\n }\n \n+const char *get_git_work_tree(void)\n+{\n+\tstatic int initialized = 0;\n+\tif (!initialized) {\n+\t\twork_tree = getenv(GIT_WORK_TREE_ENVIRONMENT);\n+\t\tif (!work_tree) {\n+\t\t\twork_tree = git_work_tree_cfg;\n+\t\t\tif (work_tree && !is_absolute_path(work_tree))\n+\t\t\t\twork_tree = xstrdup(git_path(work_tree));\n+\t\t}\n+\t\tif (work_tree && !is_absolute_path(work_tree))\n+\t\t\twork_tree = xstrdup(make_absolute_path(work_tree));\n+\t\tinitialized = 1;\n+\t}\n+\treturn work_tree;\n+}\n+\n char *get_object_directory(void)\n {\n \tif (!git_object_dir)\ndiff --git a/setup.c b/setup.c\nindex 7b07144..0323d25 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -1,4 +1,8 @@\n #include \"cache.h\"\n+#include \"dir.h\"\n+\n+static int inside_git_dir = -1;\n+static int inside_work_tree = -1;\n \n const char *prefix_path(const char *prefix, int len, const char *path)\n {\n@@ -170,100 +174,80 @@ static int is_git_directory(const char *suspect)\n \treturn 1;\n }\n \n-static int inside_git_dir = -1;\n-\n int is_inside_git_dir(void)\n {\n-\tif (inside_git_dir >= 0)\n-\t\treturn inside_git_dir;\n-\tdie(\"BUG: is_inside_git_dir called before setup_git_directory\");\n+\tif (inside_git_dir < 0)\n+\t\tinside_git_dir = is_inside_dir(get_git_dir());\n+\treturn inside_git_dir;\n }\n \n-static int inside_work_tree = -1;\n-\n int is_inside_work_tree(void)\n {\n-\tif (inside_git_dir >= 0)\n-\t\treturn inside_work_tree;\n-\tdie(\"BUG: is_inside_work_tree called before setup_git_directory\");\n+\tif (inside_work_tree < 0)\n+\t\tinside_work_tree = is_inside_dir(get_git_work_tree());\n+\treturn inside_work_tree;\n }\n \n-static char *gitworktree_config;\n-\n-static int git_setup_config(const char *var, const char *value)\n+/*\n+ * If no worktree was given, and we are outside of a default work tree,\n+ * now is the time to set it.\n+ *\n+ * In other words, if the user calls git with something like\n+ *\n+ *\tgit --git-dir=/some/where/else bla\n+ *\n+ * default to the current working directory for the work-tree root.\n+ */\n+const char* set_work_tree(const char *dir)\n {\n-\tif (!strcmp(var, \"core.worktree\")) {\n-\t\tif (gitworktree_config)\n-\t\t\tstrlcpy(gitworktree_config, value, PATH_MAX);\n-\t\treturn 0;\n+\tchar dir_buffer[PATH_MAX];\n+\tstatic char buffer[PATH_MAX + 1], *rel;\n+\tint len, postfix_len = strlen(DEFAULT_GIT_DIR_ENVIRONMENT);\n+\n+\tlen = strlen(dir);\n+\tif (len > postfix_len + 1 && dir[len - postfix_len - 1] == '/' &&\n+\t\t\t!strcmp(dir + len - postfix_len,\n+\t\t\t\tDEFAULT_GIT_DIR_ENVIRONMENT))\n+\t\tdir = strncpy(dir_buffer, dir, len - postfix_len - 1);\n+\n+\trel = get_relative_cwd(buffer, sizeof(buffer), dir);\n+\tif (rel && *rel)\n+\t\tstrcat(rel, \"/\");\n+\telse {\n+\t\trel = NULL;\n+\t\tdir = getcwd(buffer, sizeof(buffer));\n \t}\n-\treturn git_default_config(var, value);\n+\tgit_work_tree_cfg = xstrdup(dir);\n+\tinside_work_tree = 1;\n+\n+\treturn rel;\n }\n \n+/*\n+ * We cannot decide in this function whether we are in the work tree or\n+ * not, since the config can only be read _after_ this function was called.\n+ */\n const char *setup_git_directory_gently(int *nongit_ok)\n {\n+\tconst char *work_tree_env = getenv(GIT_WORK_TREE_ENVIRONMENT);\n \tstatic char cwd[PATH_MAX+1];\n-\tchar worktree[PATH_MAX+1], gitdir[PATH_MAX+1];\n-\tconst char *gitdirenv, *gitworktree;\n-\tint wt_rel_gitdir = 0;\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 \tgitdirenv = getenv(GIT_DIR_ENVIRONMENT);\n-\tif (!gitdirenv) {\n-\t\tint len, offset;\n-\n-\t\tif (!getcwd(cwd, sizeof(cwd)-1))\n-\t\t\tdie(\"Unable to read current working directory\");\n-\n-\t\toffset = len = strlen(cwd);\n-\t\tfor (;;) {\n-\t\t\tif (is_git_directory(\".git\"))\n-\t\t\t\tbreak;\n-\t\t\tif (offset == 0) {\n-\t\t\t\toffset = -1;\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t\tchdir(\"..\");\n-\t\t\twhile (cwd[--offset] != '/')\n-\t\t\t\t; /* do nothing */\n-\t\t}\n-\n-\t\tif (offset >= 0) {\n-\t\t\tinside_work_tree = 1;\n-\t\t\tgit_config(git_default_config);\n-\t\t\tif (offset == len) {\n-\t\t\t\tinside_git_dir = 0;\n-\t\t\t\treturn NULL;\n-\t\t\t}\n-\n-\t\t\tcwd[len++] = '/';\n-\t\t\tcwd[len] = '\\0';\n-\t\t\tinside_git_dir = !prefixcmp(cwd + offset + 1, \".git/\");\n-\t\t\treturn cwd + offset + 1;\n-\t\t}\n-\n-\t\tif (chdir(cwd))\n-\t\t\tdie(\"Cannot come back to cwd\");\n-\t\tif (!is_git_directory(\".\")) {\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\");\n-\t\t}\n-\t\tsetenv(GIT_DIR_ENVIRONMENT, cwd, 1);\n-\t\tgitdirenv = getenv(GIT_DIR_ENVIRONMENT);\n-\t\tif (!gitdirenv)\n-\t\t\tdie(\"getenv after setenv failed\");\n-\t}\n-\n-\tif (PATH_MAX - 40 < strlen(gitdirenv)) {\n-\t\tif (nongit_ok) {\n-\t\t\t*nongit_ok = 1;\n+\tif (gitdirenv) {\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\tif (!work_tree_env)\n+\t\t\t\treturn set_work_tree(gitdirenv);\n \t\t\treturn NULL;\n \t\t}\n-\t\tdie(\"$%s too big\", GIT_DIR_ENVIRONMENT);\n-\t}\n-\tif (!is_git_directory(gitdirenv)) {\n \t\tif (nongit_ok) {\n \t\t\t*nongit_ok = 1;\n \t\t\treturn NULL;\n@@ -273,92 +257,53 @@ const char *setup_git_directory_gently(int *nongit_ok)\n \n \tif (!getcwd(cwd, sizeof(cwd)-1))\n \t\tdie(\"Unable to read current working directory\");\n-\tif (chdir(gitdirenv)) {\n-\t\tif (nongit_ok) {\n-\t\t\t*nongit_ok = 1;\n-\t\t\treturn NULL;\n-\t\t}\n-\t\tdie(\"Cannot change directory to $%s '%s'\",\n-\t\t\tGIT_DIR_ENVIRONMENT, gitdirenv);\n-\t}\n-\tif (!getcwd(gitdir, sizeof(gitdir)-1))\n-\t\tdie(\"Unable to read current working directory\");\n-\tif (chdir(cwd))\n-\t\tdie(\"Cannot come back to cwd\");\n \n \t/*\n-\t * In case there is a work tree we may change the directory,\n-\t * therefore make GIT_DIR an absolute path.\n+\t * Test in the following order (relative to the cwd):\n+\t * - .git/\n+\t * - ./ (bare)\n+\t * - ../.git/\n+\t * - ../ (bare)\n+\t * - ../../.git/\n+\t *   etc.\n \t */\n-\tif (gitdirenv[0] != '/') {\n-\t\tsetenv(GIT_DIR_ENVIRONMENT, gitdir, 1);\n-\t\tgitdirenv = getenv(GIT_DIR_ENVIRONMENT);\n-\t\tif (!gitdirenv)\n-\t\t\tdie(\"getenv after setenv failed\");\n-\t\tif (PATH_MAX - 40 < strlen(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(\"$%s too big after expansion to absolute path\",\n-\t\t\t\tGIT_DIR_ENVIRONMENT);\n-\t\t}\n-\t}\n-\n-\tstrcat(cwd, \"/\");\n-\tstrcat(gitdir, \"/\");\n-\tinside_git_dir = !prefixcmp(cwd, gitdir);\n-\n-\tgitworktree = getenv(GIT_WORK_TREE_ENVIRONMENT);\n-\tif (!gitworktree) {\n-\t\tgitworktree_config = worktree;\n-\t\tworktree[0] = '\\0';\n-\t}\n-\tgit_config(git_setup_config);\n-\tif (!gitworktree) {\n-\t\tgitworktree_config = NULL;\n-\t\tif (worktree[0])\n-\t\t\tgitworktree = worktree;\n-\t\tif (gitworktree && gitworktree[0] != '/')\n-\t\t\twt_rel_gitdir = 1;\n-\t}\n-\n-\tif (wt_rel_gitdir && chdir(gitdirenv))\n-\t\tdie(\"Cannot change directory to $%s '%s'\",\n-\t\t\tGIT_DIR_ENVIRONMENT, gitdirenv);\n-\tif (gitworktree && chdir(gitworktree)) {\n-\t\tif (nongit_ok) {\n-\t\t\tif (wt_rel_gitdir && chdir(cwd))\n-\t\t\t\tdie(\"Cannot come back to cwd\");\n-\t\t\t*nongit_ok = 1;\n+\toffset = len = strlen(cwd);\n+\tfor (;;) {\n+\t\tif (is_git_directory(DEFAULT_GIT_DIR_ENVIRONMENT))\n+\t\t\tbreak;\n+\t\tif (is_git_directory(\".\")) {\n+\t\t\tinside_git_dir = 1;\n+\t\t\tif (!work_tree_env)\n+\t\t\t\tinside_work_tree = 0;\n+\t\t\tsetenv(GIT_DIR_ENVIRONMENT, \".\", 1);\n \t\t\treturn NULL;\n \t\t}\n-\t\tif (wt_rel_gitdir)\n-\t\t\tdie(\"Cannot change directory to working tree '%s'\"\n-\t\t\t\t\" from $%s\", gitworktree, GIT_DIR_ENVIRONMENT);\n-\t\telse\n-\t\t\tdie(\"Cannot change directory to working tree '%s'\",\n-\t\t\t\tgitworktree);\n-\t}\n-\tif (!getcwd(worktree, sizeof(worktree)-1))\n-\t\tdie(\"Unable to read current working directory\");\n-\tstrcat(worktree, \"/\");\n-\tinside_work_tree = !prefixcmp(cwd, worktree);\n-\n-\tif (gitworktree && inside_work_tree && !prefixcmp(worktree, gitdir) &&\n-\t    strcmp(worktree, gitdir)) {\n-\t\tinside_git_dir = 0;\n+\t\tchdir(\"..\");\n+\t\tdo {\n+\t\t\tif (!offset) {\n+\t\t\t\tif (nongit_ok) {\n+\t\t\t\t\tif (chdir(cwd))\n+\t\t\t\t\t\tdie(\"Cannot come back to cwd\");\n+\t\t\t\t\t*nongit_ok = 1;\n+\t\t\t\t\treturn NULL;\n+\t\t\t\t}\n+\t\t\t\tdie(\"Not a git repository\");\n+\t\t\t}\n+\t\t} while (cwd[--offset] != '/');\n \t}\n \n-\tif (!inside_work_tree) {\n-\t\tif (chdir(cwd))\n-\t\t\tdie(\"Cannot come back to cwd\");\n+\tinside_git_dir = 0;\n+\tif (!work_tree_env)\n+\t\tinside_work_tree = 1;\n+\tgit_work_tree_cfg = xstrndup(cwd, offset);\n+\tif (offset == len)\n \t\treturn NULL;\n-\t}\n \n-\tif (!strcmp(cwd, worktree))\n-\t\treturn NULL;\n-\treturn cwd+strlen(worktree);\n+\t/* Make \"offset\" point to past the '/', and add a '/' at the end */\n+\toffset++;\n+\tcwd[len++] = '/';\n+\tcwd[len] = 0;\n+\treturn cwd + offset;\n }\n \n int git_config_perm(const char *var, const char *value)\n@@ -382,11 +327,17 @@ int git_config_perm(const char *var, const char *value)\n \n int check_repository_format_version(const char *var, const char *value)\n {\n-       if (strcmp(var, \"core.repositoryformatversion\") == 0)\n-               repository_format_version = git_config_int(var, value);\n+\tif (strcmp(var, \"core.repositoryformatversion\") == 0)\n+\t\trepository_format_version = git_config_int(var, value);\n \telse if (strcmp(var, \"core.sharedrepository\") == 0)\n \t\tshared_repository = git_config_perm(var, value);\n-       return 0;\n+\telse if (strcmp(var, \"core.worktree\") == 0) {\n+\t\tif (git_work_tree_cfg)\n+\t\t\tfree(git_work_tree_cfg);\n+\t\tgit_work_tree_cfg = xstrdup(value);\n+\t\tinside_work_tree = -1;\n+\t}\n+\treturn 0;\n }\n \n int check_repository_format(void)\n@@ -402,5 +353,14 @@ const char *setup_git_directory(void)\n {\n \tconst char *retval = setup_git_directory_gently(NULL);\n \tcheck_repository_format();\n+\n+\t/* If the work tree is not the default one, recompute prefix */\n+\tif (inside_work_tree < 0) {\n+\t\tstatic char buffer[PATH_MAX + 1];\n+\t\tchar *rel = get_relative_cwd(buffer, PATH_MAX,\n+\t\t\t\tget_git_work_tree());\n+\t\treturn rel && *rel ? strcat(rel, \"/\") : NULL;\n+\t}\n+\n \treturn retval;\n }\n-- \n1.5.3.rc3.18.g49a1\n"},{"id":"48815","messageId":"Pine.LNX.4.64.0707271957070.14781@racer.site","threadId":"9263","inReplyTo":"Pine.LNX.4.64.0707271851370.14781@racer.site","subject":"[PATCH 4/8] Add set_git_dir() function","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-07-27T18:57:18Z","receivedAt":"2007-07-27T18:57:18Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"\nWith the function set_git_dir() you can reset the path that will\nbe used for git_path(), git_dir() and friends.\n\nThe responsibility to close files and throw away information from the\nold git_dir lies with the caller.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n\n\tThis is just ripped out from the branch--new-workdir topic\n\tI was working on, just that it has a shorter name now.\n\n\tAh, and just to be sure, it xstrdup()s the path.\n\n cache.h       |    1 +\n environment.c |    8 ++++++++\n 2 files changed, 9 insertions(+), 0 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex c0cab34..36963f2 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -216,6 +216,7 @@ extern char *get_refs_directory(void);\n extern char *get_index_file(void);\n extern char *get_graft_file(void);\n extern const char *get_git_work_tree(void);\n+extern int set_git_dir(const char *path);\n \n #define ALTERNATE_DB_ENVIRONMENT \"GIT_ALTERNATE_OBJECT_DIRECTORIES\"\n \ndiff --git a/environment.c b/environment.c\nindex cb112a4..33c0f90 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -121,3 +121,11 @@ char *get_graft_file(void)\n \t\tsetup_git_env();\n \treturn git_graft_file;\n }\n+\n+int set_git_dir(const char *path)\n+{\n+\tif (setenv(GIT_DIR_ENVIRONMENT, xstrdup(path), 1))\n+\t\treturn error(\"Could not set GIT_DIR to '%s'\", path);\n+\tsetup_git_env();\n+\treturn 0;\n+}\n-- \n1.5.3.rc3.18.g49a1\n"},{"id":"48816","messageId":"Pine.LNX.4.64.0707271957250.14781@racer.site","threadId":"9263","inReplyTo":"Pine.LNX.4.64.0707271851370.14781@racer.site","subject":"[PATCH 5/8] work-trees are allowed inside a git-dir","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-07-27T18:57:46Z","receivedAt":"2007-07-27T18:57:46Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"\nIt is allowed to call\n\n\t$ git --git-dir=../ --work-tree=. bla\n\nwhen you really want to.  In this case, you are both in the git directory\nand in the working tree.\n\nThe earlier handling of this situation was seriously bogus.  For regular\nworking tree operations, it checked if inside git dir.  That makes no\nsense, of course, since the check should be for a work tree, and nothing\nelse.\n\nFix that.\n\nCoincidently, you can omit the \"--work-tree\" now, if your repository knows\nabout the location already.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin-ls-files.c |    8 +++++---\n git-sh-setup.sh    |    3 +--\n git.c              |   11 ++++++++---\n 3 files changed, 14 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin-ls-files.c b/builtin-ls-files.c\nindex 61577ea..d36181a 100644\n--- a/builtin-ls-files.c\n+++ b/builtin-ls-files.c\n@@ -469,9 +469,11 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)\n \t\tbreak;\n \t}\n \n-\tif (require_work_tree &&\n-\t\t\t(!is_inside_work_tree() || is_inside_git_dir()))\n-\t\tdie(\"This operation must be run in a work tree\");\n+\tif (require_work_tree && !is_inside_work_tree()) {\n+\t\tconst char *work_tree = get_git_work_tree();\n+\t\tif (!work_tree || chdir(work_tree))\n+\t\t\tdie(\"This operation must be run in a work tree\");\n+\t}\n \n \tpathspec = get_pathspec(prefix, argv + i);\n \ndiff --git a/git-sh-setup.sh b/git-sh-setup.sh\nindex c51985e..7bef43f 100755\n--- a/git-sh-setup.sh\n+++ b/git-sh-setup.sh\n@@ -59,8 +59,7 @@ cd_to_toplevel () {\n }\n \n require_work_tree () {\n-\ttest $(git rev-parse --is-inside-work-tree) = true &&\n-\ttest $(git rev-parse --is-inside-git-dir) = false ||\n+\ttest $(git rev-parse --is-inside-work-tree) = true ||\n \tdie \"fatal: $0 cannot be used without a working tree.\"\n }\n \ndiff --git a/git.c b/git.c\nindex a647f9c..2433355 100644\n--- a/git.c\n+++ b/git.c\n@@ -272,9 +272,14 @@ static int run_command(struct cmd_struct *p, int argc, const char **argv)\n \t\tprefix = setup_git_directory();\n \tif (p->option & USE_PAGER)\n \t\tsetup_pager();\n-\tif ((p->option & NEED_WORK_TREE) &&\n-\t    (!is_inside_work_tree() || is_inside_git_dir()))\n-\t\tdie(\"%s must be run in a work tree\", p->cmd);\n+\tif (p->option & NEED_WORK_TREE) {\n+\t\tconst char *work_tree = get_git_work_tree();\n+\t\tconst char *git_dir = get_git_dir();\n+\t\tif (!is_absolute_path(git_dir))\n+\t\t\tset_git_dir(make_absolute_path(git_dir));\n+\t\tif (!work_tree || chdir(work_tree))\n+\t\t\tdie(\"%s must be run in a work tree\", p->cmd);\n+\t}\n \ttrace_argv_printf(argv, argc, \"trace: built-in: git\");\n \n \tstatus = p->fn(argc, argv, prefix);\n-- \n1.5.3.rc3.18.g49a1\n"},{"id":"48817","messageId":"Pine.LNX.4.64.0707271958120.14781@racer.site","threadId":"9263","inReplyTo":"Pine.LNX.4.64.0707271851370.14781@racer.site","subject":"[PATCH 6/8] init: use get_git_work_tree() instead of rolling our own","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-07-27T18:58:32Z","receivedAt":"2007-07-27T18:58:32Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n\n\tThis is no change in function, but in readability.\n\n builtin-init-db.c |   48 +++++++++++-------------------------------------\n 1 files changed, 11 insertions(+), 37 deletions(-)\n\ndiff --git a/builtin-init-db.c b/builtin-init-db.c\nindex 66ddaeb..0d9b1e0 100644\n--- a/builtin-init-db.c\n+++ b/builtin-init-db.c\n@@ -174,36 +174,7 @@ static void copy_templates(const char *git_dir, int len, const char *template_di\n \tclosedir(dir);\n }\n \n-/*\n- * Get the full path to the working tree specified in $GIT_WORK_TREE\n- * or NULL if no working tree is specified.\n- */\n-static const char *get_work_tree(void)\n-{\n-\tconst char *git_work_tree;\n-\tchar cwd[PATH_MAX];\n-\tstatic char worktree[PATH_MAX];\n-\n-\tgit_work_tree = getenv(GIT_WORK_TREE_ENVIRONMENT);\n-\tif (!git_work_tree)\n-\t\treturn NULL;\n-\tif (!getcwd(cwd, sizeof(cwd)))\n-\t\tdie(\"Unable to read current working directory\");\n-\tif (chdir(git_work_tree))\n-\t\tdie(\"Cannot change directory to specified working tree '%s'\",\n-\t\t\tgit_work_tree);\n-\tif (git_work_tree[0] != '/') {\n-\t\tif (!getcwd(worktree, sizeof(worktree)))\n-\t\t\tdie(\"Unable to read current working directory\");\n-\t\tgit_work_tree = worktree;\n-\t}\n-\tif (chdir(cwd))\n-\t\tdie(\"Cannot come back to cwd\");\n-\treturn git_work_tree;\n-}\n-\n-static int create_default_files(const char *git_dir, const char *git_work_tree,\n-\tconst char *template_path)\n+static int create_default_files(const char *git_dir, const char *template_path)\n {\n \tunsigned len = strlen(git_dir);\n \tstatic char path[PATH_MAX];\n@@ -282,16 +253,16 @@ static int create_default_files(const char *git_dir, const char *git_work_tree,\n \t}\n \tgit_config_set(\"core.filemode\", filemode ? \"true\" : \"false\");\n \n-\tif (is_bare_repository() && !git_work_tree) {\n+\tif (is_bare_repository())\n \t\tgit_config_set(\"core.bare\", \"true\");\n-\t}\n \telse {\n+\t\tconst char *work_tree = get_git_work_tree();\n \t\tgit_config_set(\"core.bare\", \"false\");\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\tif (work_tree != git_work_tree_cfg)\n+\t\t\tgit_config_set(\"core.worktree\", work_tree);\n \t}\n \treturn reinit;\n }\n@@ -308,7 +279,6 @@ 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@@ -329,7 +299,11 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)\n \t\t\tusage(init_db_usage);\n \t}\n \n-\tgit_work_tree = get_work_tree();\n+\tgit_work_tree_cfg = xcalloc(PATH_MAX, 1);\n+\tif (!getcwd(git_work_tree_cfg, PATH_MAX))\n+\t\tdie (\"Cannot access current working directory.\");\n+\tif (access(get_git_work_tree(), X_OK))\n+\t\tdie (\"Cannot access work tree '%s'\", get_git_work_tree());\n \n \t/*\n \t * Set up the default .git directory contents\n@@ -346,7 +320,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)\n \t */\n \tcheck_repository_format();\n \n-\treinit = create_default_files(git_dir, git_work_tree, template_dir);\n+\treinit = create_default_files(git_dir, template_dir);\n \n \t/*\n \t * And set up the object store.\n-- \n1.5.3.rc3.18.g49a1\n"},{"id":"48818","messageId":"Pine.LNX.4.64.0707271958370.14781@racer.site","threadId":"9263","inReplyTo":"Pine.LNX.4.64.0707271851370.14781@racer.site","subject":"[PATCH 7/8] Make t1501 a little saner, and fix it","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-07-27T18:58:49Z","receivedAt":"2007-07-27T18:58:49Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"\nt1501 is still a PITA to debug, but less so than before.  This patch\nfixes also the tests which tested for the wrong (old) work-tree behavior.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/t1501-worktree.sh |  161 +++++++++++++++++++++++++++++----------------------\n 1 files changed, 92 insertions(+), 69 deletions(-)\n\ndiff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh\nindex aadeeab..fad9a9e 100755\n--- a/t/t1501-worktree.sh\n+++ b/t/t1501-worktree.sh\n@@ -4,89 +4,112 @@ test_description='test separate work tree'\n . ./test-lib.sh\n \n test_rev_parse() {\n-\tname=$1\n-\tshift\n-\n-\ttest_expect_success \"$name: is-bare-repository\" \\\n-\t\"test '$1' = \\\"\\$(git rev-parse --is-bare-repository)\\\"\"\n-\tshift\n-\t[ $# -eq 0 ] && return\n-\n-\ttest_expect_success \"$name: is-inside-git-dir\" \\\n-\t\"test '$1' = \\\"\\$(git rev-parse --is-inside-git-dir)\\\"\"\n-\tshift\n-\t[ $# -eq 0 ] && return\n-\n-\ttest_expect_success \"$name: is-inside-work-tree\" \\\n-\t\"test '$1' = \\\"\\$(git rev-parse --is-inside-work-tree)\\\"\"\n-\tshift\n-\t[ $# -eq 0 ] && return\n-\n-\ttest_expect_success \"$name: prefix\" \\\n-\t\"test '$1' = \\\"\\$(git rev-parse --show-prefix)\\\"\"\n-\tshift\n-\t[ $# -eq 0 ] && return\n+\tname=\"$1\"\n+\tfor option in --is-bare-repository --is-inside-git-dir \\\n+\t\t--is-inside-work-tree --show-prefix\n+\tdo\n+\t\tshift\n+\t\ttest_expect_success \"$name: $option\" \\\n+\t\t\t\"test '$1' = \\\"\\$(git rev-parse $option)\\\"\"\n+\t\ttest $# -eq 1 && return\n+\tdone\n }\n \n-mkdir -p work/sub/dir || exit 1\n-mv .git repo.git || exit 1\n+# usage: set_repo <working directory> [<git dir> [<work tree> [env]]]\n+set_repo () {\n+\tcd \"$1\"\n+\tsay \"switching to $(pwd) with GIT_DIR $2\"\n+\n+\ttest -z \"$2\" || {\n+\t\tGIT_DIR=\"$2\"\n+\t\tGIT_CONFIG=\"$2\"/config\n+\t\texport GIT_DIR GIT_CONFIG\n+\t}\n+\n+\ttest -z \"$3\" ||\n+\tcase \"$4\" in\n+\tenv)\n+\t\tGIT_WORK_TREE=\"$3\"\n+\t\texport GIT_WORK_TREE\n+\t\tgit config core.workTree non-existent\n+\t;;\n+\t*)\n+\t\tgit config core.workTree \"$3\"\n+\tesac\n+}\n+\n+test_expect_success 'setup' '\n+\tmkdir -p work/sub/dir &&\n+\tmv .git repo.git\n+'\n \n say \"core.worktree = relative path\"\n-export GIT_DIR=repo.git\n-export GIT_CONFIG=$GIT_DIR/config\n-unset GIT_WORK_TREE\n-git config core.worktree ../work\n-test_rev_parse 'outside'      false false false\n-cd work || exit 1\n-export GIT_DIR=../repo.git\n-export GIT_CONFIG=$GIT_DIR/config\n-test_rev_parse 'inside'       false false true ''\n-cd sub/dir || exit 1\n-export GIT_DIR=../../../repo.git\n-export GIT_CONFIG=$GIT_DIR/config\n+\n+set_repo . repo.git ../work\n+test_rev_parse 'outside git dir' false false false\n+\n+set_repo work ../repo.git\n+test_rev_parse 'inside git dir' false false true ''\n+\n+set_repo sub/dir ../../../repo.git\n test_rev_parse 'subdirectory' false false true sub/dir/\n-cd ../../.. || exit 1\n+cd ../../..\n \n say \"core.worktree = absolute path\"\n-export GIT_DIR=$(pwd)/repo.git\n-export GIT_CONFIG=$GIT_DIR/config\n-git config core.worktree \"$(pwd)/work\"\n-test_rev_parse 'outside'      false false false\n-cd work || exit 1\n-test_rev_parse 'inside'       false false true ''\n-cd sub/dir || exit 1\n+set_repo . $(pwd)/repo.git $(pwd)/work\n+test_rev_parse 'outside git dir' false false false\n+\n+set_repo work\n+test_rev_parse 'inside git dir' false false true ''\n+\n+set_repo sub/dir\n test_rev_parse 'subdirectory' false false true sub/dir/\n-cd ../../.. || exit 1\n+cd ../../..\n \n say \"GIT_WORK_TREE=relative path (override core.worktree)\"\n-export GIT_DIR=$(pwd)/repo.git\n-export GIT_CONFIG=$GIT_DIR/config\n-git config core.worktree non-existent\n-export GIT_WORK_TREE=work\n-test_rev_parse 'outside'      false false false\n-cd work || exit 1\n-export GIT_WORK_TREE=.\n-test_rev_parse 'inside'       false false true ''\n-cd sub/dir || exit 1\n-export GIT_WORK_TREE=../..\n+\n+set_repo . $(pwd)/repo.git work env\n+test_rev_parse 'outside git dir' false false false\n+\n+set_repo work \"\" . env\n+test_rev_parse 'inside git dir' false false true ''\n+\n+set_repo sub/dir \"\" ../../ env\n test_rev_parse 'subdirectory' false false true sub/dir/\n cd ../../.. || exit 1\n \n+say \"GIT_WORK_TREE=absolute path, work tree below git dir\"\n+\n mv work repo.git/work\n \n-say \"GIT_WORK_TREE=absolute path, work tree below git dir\"\n-export GIT_DIR=$(pwd)/repo.git\n-export GIT_CONFIG=$GIT_DIR/config\n-export GIT_WORK_TREE=$(pwd)/repo.git/work\n-test_rev_parse 'outside'              false false false\n-cd repo.git || exit 1\n-test_rev_parse 'in repo.git'              false true  false\n-cd objects || exit 1\n-test_rev_parse 'in repo.git/objects'      false true  false\n-cd ../work || exit 1\n-test_rev_parse 'in repo.git/work'         false false true ''\n-cd sub/dir || exit 1\n-test_rev_parse 'in repo.git/sub/dir' false false true sub/dir/\n-cd ../../../.. || exit 1\n+set_repo . $(pwd)/repo.git $(pwd)/repo.git/work env\n+test_rev_parse 'outside git dir' false false false\n+\n+set_repo repo.git\n+test_rev_parse 'in repo.git' false true false\n+\n+set_repo objects\n+test_rev_parse 'in repo.git/objects' false true  false\n+\n+set_repo ../work\n+test_rev_parse 'in repo.git/work' false true true ''\n+\n+set_repo sub/dir\n+test_rev_parse 'in repo.git/sub/dir' false true true sub/dir/\n+cd ../../../..\n+\n+test_expect_success 'repo finds its work tree' '\n+\t(cd repo.git &&\n+\t : > work/sub/dir/untracked &&\n+\t test sub/dir/untracked = \"$(git ls-files --others)\")\n+'\n+\n+test_expect_success 'repo finds its work tree from work tree, too' '\n+\t(cd repo.git/work/sub/dir &&\n+\t : > tracked &&\n+\t git --git-dir=../../.. add tracked &&\n+\t cd ../../.. &&\n+\t test sub/dir/tracked = \"$(git ls-files)\")\n+'\n \n test_done\n-- \n1.5.3.rc3.18.g49a1\n"},{"id":"48819","messageId":"Pine.LNX.4.64.0707271958590.14781@racer.site","threadId":"9263","inReplyTo":"Pine.LNX.4.64.0707271851370.14781@racer.site","subject":"[PATCH 8/8] Fix t1500 for sane work-tree behavior","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-07-27T18:59:11Z","receivedAt":"2007-07-27T18:59:11Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"\nWhen GIT_DIR=../.git, and no worktree is specified, it is reasonable\nto assume that the repository is not bare, that the work tree is \"..\"\nand that the prefix is the basename of the current directory.\n\nThis is the sane behavior.\n\nt1500 tested for the old behavior, which was plain wrong.  And this\npatch fixes it minimally.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n\tYeah, I broke down.  But fixing t1501's style was painful enough.\n\n t/t1500-rev-parse.sh |   16 ++++++++--------\n 1 files changed, 8 insertions(+), 8 deletions(-)\n\ndiff --git a/t/t1500-rev-parse.sh b/t/t1500-rev-parse.sh\nindex ec49966..6e792b6 100755\n--- a/t/t1500-rev-parse.sh\n+++ b/t/t1500-rev-parse.sh\n@@ -31,9 +31,9 @@ test_rev_parse() {\n test_rev_parse toplevel false false true ''\n \n cd .git || exit 1\n-test_rev_parse .git/ false true true .git/\n+test_rev_parse .git/ true true false ''\n cd objects || exit 1\n-test_rev_parse .git/objects/ false true true .git/objects/\n+test_rev_parse .git/objects/ true true false ''\n cd ../.. || exit 1\n \n mkdir -p sub/dir || exit 1\n@@ -42,7 +42,7 @@ test_rev_parse subdirectory false false true sub/dir/\n cd ../.. || exit 1\n \n git config core.bare true\n-test_rev_parse 'core.bare = true' true false true\n+test_rev_parse 'core.bare = true' false false true\n \n git config --unset core.bare\n test_rev_parse 'core.bare undefined' false false true\n@@ -53,13 +53,13 @@ export GIT_DIR=../.git\n export GIT_CONFIG=\"$GIT_DIR\"/config\n \n git config core.bare false\n-test_rev_parse 'GIT_DIR=../.git, core.bare = false' false false true ''\n+test_rev_parse 'GIT_DIR=../.git, core.bare = false' false false true work/\n \n git config core.bare true\n-test_rev_parse 'GIT_DIR=../.git, core.bare = true' true false true ''\n+test_rev_parse 'GIT_DIR=../.git, core.bare = true' false false true work/\n \n git config --unset core.bare\n-test_rev_parse 'GIT_DIR=../.git, core.bare undefined' false false true ''\n+test_rev_parse 'GIT_DIR=../.git, core.bare undefined' false false true work/\n \n mv ../.git ../repo.git || exit 1\n export GIT_DIR=../repo.git\n@@ -69,9 +69,9 @@ git config core.bare false\n test_rev_parse 'GIT_DIR=../repo.git, core.bare = false' false false true ''\n \n git config core.bare true\n-test_rev_parse 'GIT_DIR=../repo.git, core.bare = true' true false true ''\n+test_rev_parse 'GIT_DIR=../repo.git, core.bare = true' false false true ''\n \n git config --unset core.bare\n-test_rev_parse 'GIT_DIR=../repo.git, core.bare undefined' true false true ''\n+test_rev_parse 'GIT_DIR=../repo.git, core.bare undefined' false false true ''\n \n test_done\n-- \n1.5.3.rc3.18.g49a1\n"},{"id":"48836","messageId":"7vvec5y3i0.fsf@assigned-by-dhcp.cox.net","threadId":"9263","inReplyTo":"Pine.LNX.4.64.0707271955450.14781@racer.site","subject":"Re: [PATCH 1/8] Add is_absolute_path() and make_absolute_path()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-07-27T20:51:19Z","receivedAt":"2007-07-27T20:51:19Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> diff --git a/path.c b/path.c\n> index c4ce962..0f7012f 100644\n> --- a/path.c\n> +++ b/path.c\n> @@ -292,3 +292,65 @@ int adjust_shared_perm(const char *path)\n>  \t\treturn -2;\n>  \treturn 0;\n>  }\n> +\n> +/* We allow \"recursive\" symbolic links. Only within reason, though. */\n> +#define MAXDEPTH 5\n> +\n> +const char *make_absolute_path(const char *path)\n> +{\n> +\tstatic char bufs[2][PATH_MAX + 1], *buf = bufs[0], *next_buf = bufs[1];\n> +\tchar cwd[1024] = \"\";\n> +\tint buf_index = 1, len;\n> +\n> +\tint depth = MAXDEPTH;\n> +\tchar *last_elem = NULL;\n> +\tstruct stat st;\n> +\n> +\tif (strlcpy(buf, path, PATH_MAX) >= PATH_MAX)\n> +\t\tdie (\"Too long path: %.*s\", 60, path);\n> +\n> +\twhile (depth--) {\n> +\t\tif (stat(buf, &st) || !S_ISDIR(st.st_mode)) {\n> +\t\t\tchar *last_slash = strrchr(buf, '/');\n> +\t\t\t*last_slash = '\\0';\n> +\t\t\tlast_elem = xstrdup(last_slash + 1);\n\nWhat happens when incoming path is just \"abc\"?  Does your test\nscript checks that case?\n"},{"id":"48838","messageId":"7vps2dy3hb.fsf@assigned-by-dhcp.cox.net","threadId":"9263","inReplyTo":"Pine.LNX.4.64.0707271956140.14781@racer.site","subject":"Re: [PATCH 2/8] Add functions get_relative_cwd() and is_inside_dir()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-07-27T20:51:44Z","receivedAt":"2007-07-27T20:51:44Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> +char *get_relative_cwd(char *buffer, int size, const char *dir)\n> +{\n> +\tchar *cwd = buffer;\n> +\n> +\tif (!dir)\n> +\t\treturn 0;\n> +\n> +\tif (!getcwd(buffer, PATH_MAX))\n> +\t\treturn 0;\n\nCan size be less than PATH_MAX?\n"},{"id":"48837","messageId":"7vk5sly3h9.fsf@assigned-by-dhcp.cox.net","threadId":"9263","inReplyTo":"Pine.LNX.4.64.0707271956420.14781@racer.site","subject":"Re: [PATCH 3/8] Clean up work-tree handling","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-07-27T20:51:46Z","receivedAt":"2007-07-27T20:51:46Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> \tNot only because of ohloh am I proud that in spite of removing\n> \tmore lines than I added, there were more comments added than\n> \tremoved...\n\n> diff --git a/builtin-rev-parse.c b/builtin-rev-parse.c\n> index 497903a..3f787a8 100644\n> --- a/builtin-rev-parse.c\n> +++ b/builtin-rev-parse.c\n> @@ -320,15 +320,9 @@ 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, \"--show-cdup\")) {\n> -\t\t\t\tconst char *pfx = prefix;\n> -\t\t\t\twhile (pfx) {\n> -\t\t\t\t\tpfx = strchr(pfx, '/');\n> -\t\t\t\t\tif (pfx) {\n> -\t\t\t\t\t\tpfx++;\n> -\t\t\t\t\t\tprintf(\"../\");\n> -\t\t\t\t\t}\n> -\t\t\t\t}\n> -\t\t\t\tputchar('\\n');\n> +\t\t\t\tconst char *work_tree = get_git_work_tree();\n> +\t\t\t\tif (work_tree)\n> +\t\t\t\t\tprintf(\"%s\\n\", work_tree);\n>  \t\t\t\tcontinue;\n\nThis changes semantics, I think.\n\nIt used to be relative \"up\" path when no funny work-tree stuff\nis used, but get_git_work_tree() now seems to return absolute,\nhence this option as well.  If it introduces regression to\nexisting callers is up to what the caller does to the resulting\npath, though.  If it only is used to prefix other things\n(i.e. path=\"$(git rev-parse --show-cdup)$1\"), the caller would\nbe safe, but if the caller counted number of ../ in the return\nvalue to see how deep it is, or if the caller expected to see\nempty string in order to see if the process is at the toplevel,\nthis change would become a regression.\n\n> @@ -62,15 +66,8 @@ static void setup_git_env(void)\n>  \n>  int is_bare_repository(void)\n>  {\n> +\t/* if core.bare is not 'false', let's see if there is a work tree */\n> +\treturn is_bare_repository_cfg && !get_git_work_tree();\n>  }\n\nI thought about making core.bare a tertiary, true/false/depends,\nbut I think this makes more sense.\n"},{"id":"48839","messageId":"7vejity3h8.fsf@assigned-by-dhcp.cox.net","threadId":"9263","inReplyTo":"Pine.LNX.4.64.0707271957250.14781@racer.site","subject":"Re: [PATCH 5/8] work-trees are allowed inside a git-dir","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-07-27T20:51:47Z","receivedAt":"2007-07-27T20:51:47Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> It is allowed to call\n>\n> \t$ git --git-dir=../ --work-tree=. bla\n>\n> when you really want to.  In this case, you are both in the git directory\n> and in the working tree.\n>\n> The earlier handling of this situation was seriously bogus.  For regular\n> working tree operations, it checked if inside git dir.  That makes no\n> sense, of course, since the check should be for a work tree, and nothing\n> else.\n>\n> Fix that.\n\nI do not doubt this patch makes the above command line to work\nbetter, but I have to wonder how that layout is useful.  Care to\ngive a use case or two in the commit log message?\n"},{"id":"48840","messageId":"7v8x91y3h7.fsf@assigned-by-dhcp.cox.net","threadId":"9263","inReplyTo":"Pine.LNX.4.64.0707271958590.14781@racer.site","subject":"Re: [PATCH 8/8] Fix t1500 for sane work-tree behavior","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-07-27T20:51:48Z","receivedAt":"2007-07-27T20:51:48Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> When GIT_DIR=../.git, and no worktree is specified, it is reasonable\n> to assume that the repository is not bare, that the work tree is \"..\"\n> and that the prefix is the basename of the current directory.\n>\n> This is the sane behavior.\n\nThat is a bit too strong blanket statement, while being weak on\nexact conditions, giving only one example.\n\nIt makes me wonder...\n\n  * When GIT_DIR=../../.git, and no worktree is specified, the\n    same holds true, with worktree is \"../..\"? (probably yes)\n\n  * \"GIT_DIR=../../foo/.git\"? (I dunno)\n\n  * \"GIT_DIR=../foo.git\"? (probably not)\n\nI am assuming that you meant something like this:\n\n    When no worktree is specified, and GIT_DIR (or --git-dir=) is\n    zero or more \"../\" followed by \".git\" after stripping trailing\n    and/or redundant slashes, it is reasonable to assume that the\n    repository is not bare, and the work tree is the parent\n    directory of the GIT_DIR directory.\n\nbut that requires guesswork if you give only one example and let\nthe readers to guess.\n"},{"id":"48849","messageId":"Pine.LNX.4.64.0707280115370.14781@racer.site","threadId":"9263","inReplyTo":"7vk5sly3h9.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH 3/8] Clean up work-tree handling","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-07-28T00:21:57Z","receivedAt":"2007-07-28T00:21:57Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Fri, 27 Jul 2007, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> > \tNot only because of ohloh am I proud that in spite of removing\n> > \tmore lines than I added, there were more comments added than\n> > \tremoved...\n> \n> > diff --git a/builtin-rev-parse.c b/builtin-rev-parse.c\n> > index 497903a..3f787a8 100644\n> > --- a/builtin-rev-parse.c\n> > +++ b/builtin-rev-parse.c\n> > @@ -320,15 +320,9 @@ 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, \"--show-cdup\")) {\n> > -\t\t\t\tconst char *pfx = prefix;\n> > -\t\t\t\twhile (pfx) {\n> > -\t\t\t\t\tpfx = strchr(pfx, '/');\n> > -\t\t\t\t\tif (pfx) {\n> > -\t\t\t\t\t\tpfx++;\n> > -\t\t\t\t\t\tprintf(\"../\");\n> > -\t\t\t\t\t}\n> > -\t\t\t\t}\n> > -\t\t\t\tputchar('\\n');\n> > +\t\t\t\tconst char *work_tree = get_git_work_tree();\n> > +\t\t\t\tif (work_tree)\n> > +\t\t\t\t\tprintf(\"%s\\n\", work_tree);\n> >  \t\t\t\tcontinue;\n> \n> This changes semantics, I think.\n> \n> It used to be relative \"up\" path when no funny work-tree stuff\n> is used, but get_git_work_tree() now seems to return absolute,\n> hence this option as well.  If it introduces regression to\n> existing callers is up to what the caller does to the resulting\n> path, though.  If it only is used to prefix other things\n> (i.e. path=\"$(git rev-parse --show-cdup)$1\"), the caller would\n> be safe, but if the caller counted number of ../ in the return\n> value to see how deep it is, or if the caller expected to see\n> empty string in order to see if the process is at the toplevel,\n> this change would become a regression.\n\nI am somewhat negative on keeping _that_ much backwards compatibility.  \nScripts which depend on show-cdup being a relative path _will_ be broken \nby work-tree.  Is it worth it to detect those errors late?\n\n> > @@ -62,15 +66,8 @@ static void setup_git_env(void)\n> >  \n> >  int is_bare_repository(void)\n> >  {\n> > +\t/* if core.bare is not 'false', let's see if there is a work tree */\n> > +\treturn is_bare_repository_cfg && !get_git_work_tree();\n> >  }\n> \n> I thought about making core.bare a tertiary, true/false/depends,\n> but I think this makes more sense.\n\nActually, you made me think again, and I am more along those lines now:\n\n\treturn is_bare_repository_cfg >= 0 ?\n\t\tis_bare_repository_cfg : !get_git_work_tree();\n\nand according patch to get_git_work_tree to return NULL if \nis_bare_repository_cfg == 1.\n\nCiao,\nDscho\n"},{"id":"48850","messageId":"Pine.LNX.4.64.0707280122160.14781@racer.site","threadId":"9263","inReplyTo":"7vejity3h8.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH 5/8] work-trees are allowed inside a git-dir","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-07-28T00:38:25Z","receivedAt":"2007-07-28T00:38:25Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Fri, 27 Jul 2007, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> > It is allowed to call\n> >\n> > \t$ git --git-dir=../ --work-tree=. bla\n> >\n> > when you really want to.  In this case, you are both in the git directory\n> > and in the working tree.\n> >\n> > The earlier handling of this situation was seriously bogus.  For regular\n> > working tree operations, it checked if inside git dir.  That makes no\n> > sense, of course, since the check should be for a work tree, and nothing\n> > else.\n> >\n> > Fix that.\n> \n> I do not doubt this patch makes the above command line to work\n> better, but I have to wonder how that layout is useful.  Care to\n> give a use case or two in the commit log message?\n\nIn the commit log message?  Better somewhere else.  Only git developers \nread the commit message.\n\nBut yes, I can point to a use case.  AFAIR Martin Krafft brought up the \nissue to track different components of the home directory in different \nrepositories.\n\nI have a similar scenario here, which does not involve a home directory, \nbut rather a directory where I should not put anything into (I could, but \nif the admin was anything akin to competent, I could not).\n\nThere are files in that directory (and all of its subdirectories) of a \ncertain type, which are the only ones which are human generated, and \ntherefore precious.  I like to add them, and inspect them, with\n\n\tgit --git-dir=$HOME/x.git add\n\nand\n\n\tgit --git-dir=$HOME/x.git diff\n\nAnother similar scenario is a network drive on Losedows, where the locking \nalways fails.  So I do not _want_ a repo there, even if I _could_.\n\nCiao,\nDscho\n"},{"id":"48851","messageId":"7vejitwe8m.fsf@assigned-by-dhcp.cox.net","threadId":"9263","inReplyTo":"Pine.LNX.4.64.0707280115370.14781@racer.site","subject":"Re: [PATCH 3/8] Clean up work-tree handling","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-07-28T00:42:17Z","receivedAt":"2007-07-28T00:42:17Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> This changes semantics, I think.\n>> \n>> It used to be relative \"up\" path when no funny work-tree stuff\n>> is used, but get_git_work_tree() now seems to return absolute,\n>> hence this option as well.  If it introduces regression to\n>> existing callers is up to what the caller does to the resulting\n>> path, though.  If it only is used to prefix other things\n>> (i.e. path=\"$(git rev-parse --show-cdup)$1\"), the caller would\n>> be safe, but if the caller counted number of ../ in the return\n>> value to see how deep it is, or if the caller expected to see\n>> empty string in order to see if the process is at the toplevel,\n>> this change would become a regression.\n>\n> I am somewhat negative on keeping _that_ much backwards compatibility.  \n> Scripts which depend on show-cdup being a relative path _will_ be broken \n> by work-tree.  Is it worth it to detect those errors late?\n\nWell, one of the conditions to accept the worktree stuff was not\nto break anybody who never ever uses worktree.  So if we can\nkeep the UP-ness of cdup, it would be much better.\n"},{"id":"48852","messageId":"Pine.LNX.4.64.0707280140161.14781@racer.site","threadId":"9263","inReplyTo":"7v8x91y3h7.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH 8/8] Fix t1500 for sane work-tree behavior","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-07-28T00:46:12Z","receivedAt":"2007-07-28T00:46:12Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Fri, 27 Jul 2007, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> > When GIT_DIR=../.git, and no worktree is specified, it is reasonable\n> > to assume that the repository is not bare, that the work tree is \"..\"\n> > and that the prefix is the basename of the current directory.\n> >\n> > This is the sane behavior.\n> \n> That is a bit too strong blanket statement, while being weak on\n> exact conditions, giving only one example.\n\nOkay, let me defend it.\n\n> It makes me wonder...\n> \n>   * When GIT_DIR=../../.git, and no worktree is specified, the\n>     same holds true, with worktree is \"../..\"? (probably yes)\n\nYou meant with \"GIT_DIR=../..\"? No.  In that case, I'd assume a bare \nrepository, and we're inside the git directory, and unless the user \nspecified a working tree, assume that we have none.\n\n>   * \"GIT_DIR=../../foo/.git\"? (I dunno)\n\nUnless ../../foo == .. no.  When we're outside, we're outside.\n\n>   * \"GIT_DIR=../foo.git\"? (probably not)\n\nUnless \"$(basename \"$(pwd)\")\" == foo.git, no.\n\n> I am assuming that you meant something like this:\n> \n>     When no worktree is specified, and GIT_DIR (or --git-dir=) is\n>     zero or more \"../\" followed by \".git\" after stripping trailing\n>     and/or redundant slashes, it is reasonable to assume that the\n>     repository is not bare, and the work tree is the parent\n>     directory of the GIT_DIR directory.\n> \n> but that requires guesswork if you give only one example and let\n> the readers to guess.\n\nYour explanation is really much more coherent than mine.  Please replace \nmine.\n\nCiao,\nDscho\n"},{"id":"48853","messageId":"7vabthwdyg.fsf@assigned-by-dhcp.cox.net","threadId":"9263","inReplyTo":"Pine.LNX.4.64.0707280122160.14781@racer.site","subject":"Re: [PATCH 5/8] work-trees are allowed inside a git-dir","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-07-28T00:48:23Z","receivedAt":"2007-07-28T00:48:23Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n>> \n>> > It is allowed to call\n>> >\n>> > \t$ git --git-dir=../ --work-tree=. bla\n>> >\n>> > when you really want to.  In this case, you are both in the git directory\n>> > and in the working tree.\n> ...\n> There are files in that directory (and all of its subdirectories) of a \n> certain type, which are the only ones which are human generated, and \n> therefore precious.  I like to add them, and inspect them, with\n>\n> \tgit --git-dir=$HOME/x.git add\n>\n> and\n>\n> \tgit --git-dir=$HOME/x.git diff\n\nI understand the --git-dir=$HOME/x.git to keep track of\nsomething in $HOME/foo/bar example.\n\nBut that is not the issue you described in the original message.\nI was asking about this (which is the way I read your original\nmessage):\n\n    $ GIT_DIR=$HOME/x.git git init\n    $ mkdir $HOME/x.git/workroot\n    $ cd $HOME/x.git/workroot\n    $ git --git-dir=../ --work-tree=. \n\nThat is, $HOME/x.git/ is the GIT_DIR that has HEAD, index and\nrefs/, and you are keeping track of contents whose rootlevel is\nat $HOME/x.git/workroot\n"},{"id":"48856","messageId":"Pine.LNX.4.64.0707280152120.14781@racer.site","threadId":"9263","inReplyTo":"7vejitwe8m.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH 3/8] Clean up work-tree handling","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-07-28T00:56:23Z","receivedAt":"2007-07-28T00:56:23Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Fri, 27 Jul 2007, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> >> This changes semantics, I think.\n> >> \n> >> It used to be relative \"up\" path when no funny work-tree stuff\n> >> is used, but get_git_work_tree() now seems to return absolute,\n> >> hence this option as well.  If it introduces regression to\n> >> existing callers is up to what the caller does to the resulting\n> >> path, though.  If it only is used to prefix other things\n> >> (i.e. path=\"$(git rev-parse --show-cdup)$1\"), the caller would\n> >> be safe, but if the caller counted number of ../ in the return\n> >> value to see how deep it is, or if the caller expected to see\n> >> empty string in order to see if the process is at the toplevel,\n> >> this change would become a regression.\n> >\n> > I am somewhat negative on keeping _that_ much backwards compatibility.  \n> > Scripts which depend on show-cdup being a relative path _will_ be broken \n> > by work-tree.  Is it worth it to detect those errors late?\n> \n> Well, one of the conditions to accept the worktree stuff was not\n> to break anybody who never ever uses worktree.  So if we can\n> keep the UP-ness of cdup, it would be much better.\n\nOne could record if the work tree was changed from the default one, and \ndo the old thing in that case.\n\nBut I really have to wonder what other use people concocted for \n\"--show-cdup\"?  Potentially some directory-counting?  But --show-prefix \nwould be much better at that.\n\nI'll try to flange something into the code to detect unchanged working \ntree, but that is rather ugly, so I'd prefer not to.\n\nCiao,\nDscho\n"},{"id":"48857","messageId":"Pine.LNX.4.64.0707280157100.14781@racer.site","threadId":"9263","inReplyTo":"7vabthwdyg.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH 5/8] work-trees are allowed inside a git-dir","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-07-28T01:01:18Z","receivedAt":"2007-07-28T01:01:18Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Fri, 27 Jul 2007, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> >> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> >> \n> >> > It is allowed to call\n> >> >\n> >> > \t$ git --git-dir=../ --work-tree=. bla\n> >> >\n> >> > when you really want to.  In this case, you are both in the git directory\n> >> > and in the working tree.\n> > ...\n> > There are files in that directory (and all of its subdirectories) of a \n> > certain type, which are the only ones which are human generated, and \n> > therefore precious.  I like to add them, and inspect them, with\n> >\n> > \tgit --git-dir=$HOME/x.git add\n> >\n> > and\n> >\n> > \tgit --git-dir=$HOME/x.git diff\n> \n> I understand the --git-dir=$HOME/x.git to keep track of\n> something in $HOME/foo/bar example.\n> \n> But that is not the issue you described in the original message.\n> I was asking about this (which is the way I read your original\n> message):\n> \n>     $ GIT_DIR=$HOME/x.git git init\n>     $ mkdir $HOME/x.git/workroot\n>     $ cd $HOME/x.git/workroot\n>     $ git --git-dir=../ --work-tree=. \n> \n> That is, $HOME/x.git/ is the GIT_DIR that has HEAD, index and\n> refs/, and you are keeping track of contents whose rootlevel is\n> at $HOME/x.git/workroot\n\nAh!  But I have a really nice use case for that, too.  I track a \n.git/refs/exclude in one of my branches, because I do not want anybody \nelse to have those excludes.  They only apply to me.\n\nAnother example would be a temporary checkout+change+checkin to some \nbranch that is not currently checked out in the default working tree.  (I \ndo that, too, and had to work around that by cloning with \"-l -n -s\")  \nWhat I do there is to keep a checkout of some often-rsync'ed (actually \nwget'ed) state in the current working tree, automatically committing when \nupstream changes, and tracking upstream _releases_ in a different branch.\n\nCiao,\nDscho\n"},{"id":"48858","messageId":"Pine.LNX.4.64.0707280202260.14781@racer.site","threadId":"9263","inReplyTo":"7vvec5y3i0.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH 1/8] Add is_absolute_path() and make_absolute_path()","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-07-28T01:03:01Z","receivedAt":"2007-07-28T01:03:01Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Fri, 27 Jul 2007, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> > diff --git a/path.c b/path.c\n> > index c4ce962..0f7012f 100644\n> > --- a/path.c\n> > +++ b/path.c\n> > @@ -292,3 +292,65 @@ int adjust_shared_perm(const char *path)\n> >  \t\treturn -2;\n> >  \treturn 0;\n> >  }\n> > +\n> > +/* We allow \"recursive\" symbolic links. Only within reason, though. */\n> > +#define MAXDEPTH 5\n> > +\n> > +const char *make_absolute_path(const char *path)\n> > +{\n> > +\tstatic char bufs[2][PATH_MAX + 1], *buf = bufs[0], *next_buf = bufs[1];\n> > +\tchar cwd[1024] = \"\";\n> > +\tint buf_index = 1, len;\n> > +\n> > +\tint depth = MAXDEPTH;\n> > +\tchar *last_elem = NULL;\n> > +\tstruct stat st;\n> > +\n> > +\tif (strlcpy(buf, path, PATH_MAX) >= PATH_MAX)\n> > +\t\tdie (\"Too long path: %.*s\", 60, path);\n> > +\n> > +\twhile (depth--) {\n> > +\t\tif (stat(buf, &st) || !S_ISDIR(st.st_mode)) {\n> > +\t\t\tchar *last_slash = strrchr(buf, '/');\n> > +\t\t\t*last_slash = '\\0';\n> > +\t\t\tlast_elem = xstrdup(last_slash + 1);\n> \n> What happens when incoming path is just \"abc\"?  Does your test\n> script checks that case?\n\nNo, and you already guessed it: there will be a segmentation fault.\n\nWill fix.\n\nCiao,\nDscho\n"},{"id":"48859","messageId":"Pine.LNX.4.64.0707280203110.14781@racer.site","threadId":"9263","inReplyTo":"7vps2dy3hb.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH 2/8] Add functions get_relative_cwd() and is_inside_dir()","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-07-28T01:03:21Z","receivedAt":"2007-07-28T01:03:21Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Fri, 27 Jul 2007, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> > +char *get_relative_cwd(char *buffer, int size, const char *dir)\n> > +{\n> > +\tchar *cwd = buffer;\n> > +\n> > +\tif (!dir)\n> > +\t\treturn 0;\n> > +\n> > +\tif (!getcwd(buffer, PATH_MAX))\n> > +\t\treturn 0;\n> \n> Can size be less than PATH_MAX?\n\nThanks.  Will fix.\n\nCiao,\nDscho\n"},{"id":"48865","messageId":"7vlkd1umwf.fsf@assigned-by-dhcp.cox.net","threadId":"9263","inReplyTo":"Pine.LNX.4.64.0707280152120.14781@racer.site","subject":"Re: [PATCH 3/8] Clean up work-tree handling","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-07-28T05:18:08Z","receivedAt":"2007-07-28T05:18:08Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> Well, one of the conditions to accept the worktree stuff was not\n>> to break anybody who never ever uses worktree.  So if we can\n>> keep the UP-ness of cdup, it would be much better.\n>\n> One could record if the work tree was changed from the default one, and \n> do the old thing in that case.\n\nThis really should not be something you have to bend over with\nspecial code to support.  One thing I think people's scripts\nexpect is that cdup is what the name suggests, \"how much do I go\n*up* in order to go to the top of the working tree\", and if the\nanswer is \"nothing\", they can tell that they are already at the\ntop of the tree.\n\nNow, I think it is fair to say that if your worktree is\nsomewhere totally unrelated to your cwd, no amount of going up\nwill take you to the top.  IOW, you have to come down after\ngoing up some levels.  In such a case, it is easier to code the\nimplementation of --show-cdup to give an absolute path.\n\nBut in that case you are not even in the working tree to begin\nwith, aren't you?  Does git need to support that?  What should\n\"prefix = setup_git_dir()\" do and return, in order to come up\nwith the string to prepend to paths relative to the current\ndirectory the users give us?  I would say if your cwd is not\ninside your working tree, then --show-cdup and --show-prefix\nshould error out, saying \"Not in the working tree\".  These\noptions are about translating paths relative to your cwd to\nrelative to the top of the working tree, so if you are outside a\nworking tree, they do not make much sense.\n\nAlso I think the implementation of --show-prefix needs to work\nin terms of relative relationship between cwd and the top\nalready, so I am not sure where your aversion of keeping the\ncurrent cdup behaviour is coming from.\n\nI was hoping that --show-cdup is rarely used, but unfortunately\ncd_to_toplevel() in git-sh-setup.sh is not even the only in-tree\nuser of --show-cdup; it checks if it is empty to avoid chdir()\nunnecessarily.  There are others:\n\n - emacs/git.el uses it as part of expand-file-name, so I think\n   giving an absolute path back is Ok.\n\n - contrib/fast-import/git-p4 gives it to os.chdir() after\n   checking if the length is positive; this should be Ok\n   although it would involve an unnecessary chdir() if the\n   process is already at the top with this change.\n\n - contrib/p4import/git-p4import.py: the same story as git-p4.\n\n - git-svn.perl: the same story as above.\n"},{"id":"48887","messageId":"Pine.LNX.4.64.0707280956510.14781@racer.site","threadId":"9263","inReplyTo":"7vlkd1umwf.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH 3/8] Clean up work-tree handling","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-07-28T09:01:08Z","receivedAt":"2007-07-28T09:01:08Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Fri, 27 Jul 2007, Junio C Hamano wrote:\n\n> Now, I think it is fair to say that if your worktree is somewhere \n> totally unrelated to your cwd, no amount of going up will take you to \n> the top.  IOW, you have to come down after going up some levels.  In \n> such a case, it is easier to code the implementation of --show-cdup to \n> give an absolute path.\n> \n> But in that case you are not even in the working tree to begin\n> with, aren't you?  Does git need to support that?\n\nI'd say yes.\n\nIt is utterly _inconvenient_ to have to cd to the working tree when you \njust want to check the status, for example.  And git already knows about \nthe work-tree!\n\nBut you got me convinced about the relative path: it is true that nobody \nwho has not set core.worktree should be affected.\n\nSo I will do something like\n\n\tif (!inside_work_tree()) {\n\t\tputs(get_git_work_tree());\n\t\tcontinue;\n\t}\n\t[do the old thing of outputting ../../[...]]\n\nIn fact, I had this in an unpublished version of the patch, and decided \nthat I could remove more lines without breaking the test suite.\n\nHeck, I'll even add a test case to make sure that behavior is maintained.  \nOkay?\n\nCiao,\nDscho\n\nP.S.: I'll be offline for a few hours, but then come back to finish it up.\n"},{"id":"48896","messageId":"7vd4ycsrrt.fsf@assigned-by-dhcp.cox.net","threadId":"9263","inReplyTo":"Pine.LNX.4.64.0707280956510.14781@racer.site","subject":"Re: [PATCH 3/8] Clean up work-tree handling","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-07-28T11:15:50Z","receivedAt":"2007-07-28T11:15:50Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> Now, I think it is fair to say that if your worktree is somewhere \n>> totally unrelated to your cwd, no amount of going up will take you to \n>> the top.  IOW, you have to come down after going up some levels.  In \n>> such a case, it is easier to code the implementation of --show-cdup to \n>> give an absolute path.\n>> \n>> But in that case you are not even in the working tree to begin\n>> with, aren't you?  Does git need to support that?\n>\n> I'd say yes.\n>\n> It is utterly _inconvenient_ to have to cd to the working tree when you \n> just want to check the status, for example.  And git already knows about \n> the work-tree!\n\nThat is a bit different issue. In such a case, I would agree it\nwould still be sensible for \"git diff\" to show the whole tree\ndiff, for example.  In other words, my \"does git need to support\nthat\" is not about \"even when the location of a worktree is\nknown, operations that require a work tree should fail when\ninvoked from outside of it\".\n\nThink about what the sensible thing to do is for \"git diff .\"\nWithin a work tree, it instructs git to behave as if the user\nissued the command from the toplevel with prefix as the\nargument.  And scripts that want to mimick that behaviour would\nuse --show-prefix to obtain the prefix string, and --show-cdup\nto obtain how to move to the toplevel.\n\nOutside of a work tree, I think the only two semi-sensible\nbehaviours exist.  Either tell the user that we cannot\nunderstand what \".\" should mean in that context and error out\n(IOW, \"Not inside a work tree\"), or assume that the user meant\n\"from the top\".  So in such a case, if we do not want to error\nout to make things more \"convenient\", one possibility would be:\n\n * give empty as prefix;\n\n * give absolute or cwd relative path to the work tree for cdup\n   (it would not be a sequence of ../ anyway in this case).\n\nI think this is in line with the traditional behaviour when\nGIT_DIR is explicitly given.  We assume the cwd is the toplevel,\nand return empty prefix and empty cdup.\n\nHaving said that, I am not convinced that \"assume toplevel\noutside of a work tree\" is a win for the end users.  If the\ncommand errors out with a message telling the user that relative\npath does not make sense from outside a work tree, the user\nwould understand.  If the command does not error out but always\nworks relative to the toplevel without explanation, it might\nconfuse the user more until the he realizes \"assume toplevel\noutside of a work tree\" is the rule that is applying to his\ncase.\n"},{"id":"48925","messageId":"Pine.LNX.4.64.0707282033120.14781@racer.site","threadId":"9263","inReplyTo":"7vd4ycsrrt.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH 3/8] Clean up work-tree handling","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-07-28T19:38:29Z","receivedAt":"2007-07-28T19:38:29Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Sat, 28 Jul 2007, Junio C Hamano wrote:\n\n> Outside of a work tree, I think the only two semi-sensible behaviours \n> exist.  Either tell the user that we cannot understand what \".\" should \n> mean in that context and error out (IOW, \"Not inside a work tree\"), or \n> assume that the user meant \"from the top\".  So in such a case, if we do \n> not want to error out to make things more \"convenient\", one possibility \n> would be:\n> \n>  * give empty as prefix;\n> \n>  * give absolute or cwd relative path to the work tree for cdup\n>    (it would not be a sequence of ../ anyway in this case).\n\nI am happy that you agree with the way I implemented it...\n\n> I think this is in line with the traditional behaviour when GIT_DIR is \n> explicitly given.  We assume the cwd is the toplevel, and return empty \n> prefix and empty cdup.\n\nYes, I want that behaviour.\n\n> Having said that, I am not convinced that \"assume toplevel outside of a \n> work tree\" is a win for the end users.  If the command errors out with a \n> message telling the user that relative path does not make sense from \n> outside a work tree, the user would understand.  If the command does not \n> error out but always works relative to the toplevel without explanation, \n> it might confuse the user more until the he realizes \"assume toplevel \n> outside of a work tree\" is the rule that is applying to his case.\n\nThere are two reasons against that...\n\n- it is really convenient to be able to say \"git add .vimrc\" (think Martin \n  Krafft's desired setup).  Let's just put some uppercase warning at the \n  side of --work-tree in git-init.txt to tell the user about the \n  behaviour.\n\n- the implementation of \"you are not in the worktree\" would not be \n  elegant: \"git log\" should succeed, \"git log dir/file\" should not.\n\nCiao,\nDscho\n"},{"id":"48989","messageId":"Pine.LNX.4.64.0707291645580.14781@racer.site","threadId":"9263","inReplyTo":"7vlkd1umwf.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH 3/8] Clean up work-tree handling","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-07-29T15:53:16Z","receivedAt":"2007-07-29T15:53:16Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nI still have a problem with what should happen if both \"core.bare == true\" \nand \"core.worktree = /some/where/over/the/rainbow\".  Should it be bare, or \nshould it have a working tree?\n\nSo here is what I plan to support so far:\n\n--work-tree= overrides GIT_WORK_TREE, which overrides core.worktree, which \noverrides core.bare, which overrides GIT_DIR/.. when GIT_DIR ends in \n/.git, which overrides the directory in which .git/ was found.\n\nDoes that look okay?\n\nCiao,\nDscho\n"},{"id":"49006","messageId":"7vodhvm1dg.fsf@assigned-by-dhcp.cox.net","threadId":"9263","inReplyTo":"Pine.LNX.4.64.0707291645580.14781@racer.site","subject":"Re: [PATCH 3/8] Clean up work-tree handling","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-07-29T19:54:51Z","receivedAt":"2007-07-29T19:54:51Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> I still have a problem with what should happen if both \"core.bare == true\" \n> and \"core.worktree = /some/where/over/the/rainbow\".  Should it be bare, or \n> should it have a working tree?\n\nThey sound contradicting with each other to me.  Isn't that a\nclear configuration error?\n"},{"id":"49007","messageId":"Pine.LNX.4.64.0707292100500.14781@racer.site","threadId":"9263","inReplyTo":"7vodhvm1dg.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH 3/8] Clean up work-tree handling","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-07-29T20:02:56Z","receivedAt":"2007-07-29T20:02:56Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Sun, 29 Jul 2007, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> > I still have a problem with what should happen if both \"core.bare == true\" \n> > and \"core.worktree = /some/where/over/the/rainbow\".  Should it be bare, or \n> > should it have a working tree?\n> \n> They sound contradicting with each other to me.  Isn't that a\n> clear configuration error?\n\nYes.  But why not play nice?\n\nOkay, the real reason I do not want to catch this error is because it \ncomplicates my code.\n\nBut really, why not say \"worktree takes precedence\"?\n\nBTW I realised that callers of setup_git_directory_gently() might forget \nthe check for the repository format version...\n\nCiao,\nDscho\n"}]}