{"thread":{"id":"8411","subject":"[RFC] GIT_WORK_TREE","startedAt":"2007-06-03T14:44:01Z","lastAt":"2007-06-06T21:29:59Z","messageCount":22,"participants":["Matthias Lederhofer","Sergio","Junio C Hamano","Johannes Schindelin"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"43873","messageId":"20070603144401.GA9518@moooo.ath.cx","threadId":"8411","inReplyTo":null,"subject":"[RFC] GIT_WORK_TREE","fromName":"Matthias Lederhofer","fromEmail":"matled@gmx.net","sentAt":"2007-06-03T14:44:01Z","receivedAt":"2007-06-03T14:44:01Z","isPatch":false,"sender":{"key":"matled@gmx.net","avatar":null},"body":"Nguyen Thai Ngoc Duy <pclouds@gmail.com> wrote:\n> I think it's a valid use case. Anyone remember why Matthias' patchset\n> was dropped?\n> It was last mentioned in\n> http://article.gmane.org/gmane.comp.version-control.git/43041\n> \n> Junio, Matthias? May I help?\n\nThanks for reminding me, I just did not finish the patch and then\nthere was an exam which took all my time.  But I took another look at\nit and made a new series, including the missing test cases.\nIf you want to help please test it, check the source for errors, make\ncomments etc.\n\nThis series introduces the GIT_WORK_TREE environment variable (and\ncore.worktree config option) to specify the working tree that should\nbe used with the repository (not for repositories found as .git\ndirectory).  This allows to separate the repository and working tree.\n\nExample use cases:\n- you don't want to put the repository in the checkout (e.g. the\n  checkout is publicly available but the history shouldn't)\n- you want to track a read-only directory with git (e.g. track\n  configuration files as normal user that are modified by other people\n  or by yourself as superuser)\n- there is a directory many people are working in and you can track\n  the changes made by yourself and others without placing the .git\n  directory in the directory\n- checkout multiple repositories into the same directory\n- see the mail form nguyen (Message-ID:\n  <fcaeb9bf0705300742u22b54c78vccbc037fb553141f@mail.gmail.com>)\n\nThe patches are also available from git://igit.ath.cx/~matled/git in\nbranch worktree (I might change this branch later) or as tag\nworktree1.\n\n[PATCH] rev-parse: document --is-inside-git-dir\n[PATCH] rev-parse: introduce --is-bare-repository\n[PATCH] test git rev-parse\n[PATCH] introduce GIT_WORK_TREE to specify the work tree\n[PATCH] use new semantics of is_bare/inside_git_dir/inside_work_tree\n[PATCH] extend rev-parse test for --is-inside-work-tree\n[PATCH] test GIT_WORK_TREE\n\nThere are also a few things which are not addressed in this series:\n- The documentation needs updates on what bare means.\n- is_bare_repository should ignore trailing slashes when guessing if\n  the repository is bare (/path/to/.git is not bare, /path/to/.git/ is\n  bare if core.bare is unspecified).  Perhaps we can also set GIT_DIR\n  to the path returned by getcwd which would solve this too.\n- Aliases using --git-dir and/or --work-tree cause problems (also\n  before this patch).  git should probably exec itself if an alias\n  uses --git-dir or --work-tree.\n- Calls to git_config(git_default_config) can be removed in many\n  places because setup_git_directory_gently always reads the\n  configuration.\n- git init could set core.worktree if GIT_WORK_TREE is set.\n"},{"id":"43874","messageId":"20070603144604.GA20061@moooo.ath.cx","threadId":"8411","inReplyTo":"20070603144401.GA9518@moooo.ath.cx","subject":"[PATCH 1/7] rev-parse: document --is-inside-git-dir","fromName":"Matthias Lederhofer","fromEmail":"matled@gmx.net","sentAt":"2007-06-03T14:46:04Z","receivedAt":"2007-06-03T14:46:04Z","isPatch":true,"sender":{"key":"matled@gmx.net","avatar":null},"body":"Signed-off-by: Matthias Lederhofer <matled@gmx.net>\n---\n Documentation/git-rev-parse.txt |    4 ++++\n 1 files changed, 4 insertions(+), 0 deletions(-)\n\ndiff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt\nindex 7757abe..5fcec19 100644\n--- a/Documentation/git-rev-parse.txt\n+++ b/Documentation/git-rev-parse.txt\n@@ -89,6 +89,10 @@ 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 --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\n-- \n1.5.0.3\n"},{"id":"43877","messageId":"20070603144636.GB20061@moooo.ath.cx","threadId":"8411","inReplyTo":"20070603144401.GA9518@moooo.ath.cx","subject":"[PATCH 2/7] rev-parse: introduce --is-bare-repository","fromName":"Matthias Lederhofer","fromEmail":"matled@gmx.net","sentAt":"2007-06-03T14:46:36Z","receivedAt":"2007-06-03T14:46:36Z","isPatch":true,"sender":{"key":"matled@gmx.net","avatar":null},"body":"Signed-off-by: Matthias Lederhofer <matled@gmx.net>\n---\n Documentation/git-rev-parse.txt |    3 +++\n builtin-rev-parse.c             |    5 +++++\n git-sh-setup.sh                 |    6 +-----\n git-svn.perl                    |    3 +--\n 4 files changed, 10 insertions(+), 7 deletions(-)\n\ndiff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt\nindex 5fcec19..c817d16 100644\n--- a/Documentation/git-rev-parse.txt\n+++ b/Documentation/git-rev-parse.txt\n@@ -93,6 +93,9 @@ OPTIONS\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 e350061..e3a5cbb 100755\n--- a/git-svn.perl\n+++ b/git-svn.perl\n@@ -594,8 +594,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-\treturn if $bare eq 'true';\n+\treturn if command_oneline(qw/rev-parse --is-bare-repository/) 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 \tprint STDERR \"Checked out HEAD:\\n  \",\n-- \n1.5.0.3\n"},{"id":"43876","messageId":"20070603144700.GC20061@moooo.ath.cx","threadId":"8411","inReplyTo":"20070603144401.GA9518@moooo.ath.cx","subject":"[PATCH 3/7] test git rev-parse","fromName":"Matthias Lederhofer","fromEmail":"matled@gmx.net","sentAt":"2007-06-03T14:47:00Z","receivedAt":"2007-06-03T14:47:00Z","isPatch":true,"sender":{"key":"matled@gmx.net","avatar":null},"body":"Signed-off-by: Matthias Lederhofer <matled@gmx.net>\n---\n t/t1500-rev-parse.sh |   58 ++++++++++++++++++++++++++++++++++++++++++++++++++\n 1 files changed, 58 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..a180309\n--- /dev/null\n+++ b/t/t1500-rev-parse.sh\n@@ -0,0 +1,58 @@\n+#!/bin/sh\n+\n+test_description='test git rev-parse'\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: prefix\" \\\n+\t\"test '$1' = \\\"\\$(git rev-parse --show-prefix)\\\"\"\n+\tshift\n+\t[ $# -eq 0 ] && return\n+}\n+\n+test_rev_parse toplevel false false ''\n+\n+cd .git || exit 1\n+test_rev_parse .git/ false true .git/\n+cd objects || exit 1\n+test_rev_parse .git/objects/ false true .git/objects/\n+cd ../.. || exit 1\n+\n+mkdir -p sub/dir || exit 1\n+cd sub/dir || exit 1\n+test_rev_parse subdirectory false false sub/dir/\n+cd ../.. || exit 1\n+\n+git config core.bare true\n+test_rev_parse 'core.bare = true' true\n+\n+git config --unset core.bare\n+test_rev_parse 'core.bare undefined' false\n+\n+mv .git foo.git || exit 1\n+export GIT_DIR=foo.git\n+export GIT_CONFIG=foo.git/config\n+\n+git config core.bare true\n+test_rev_parse 'GIT_DIR=foo.git, core.bare = true' true\n+\n+git config core.bare false\n+test_rev_parse 'GIT_DIR=foo.git, core.bare = false' false\n+\n+git config --unset core.bare\n+test_rev_parse 'GIT_DIR=foo.git, core.bare undefined' true\n+\n+test_done\n-- \n1.5.0.3\n"},{"id":"43875","messageId":"20070603144714.GD20061@moooo.ath.cx","threadId":"8411","inReplyTo":"20070603144401.GA9518@moooo.ath.cx","subject":"[PATCH 4/7] introduce GIT_WORK_TREE to specify the work tree","fromName":"Matthias Lederhofer","fromEmail":"matled@gmx.net","sentAt":"2007-06-03T14:47:14Z","receivedAt":"2007-06-03T14:47:14Z","isPatch":true,"sender":{"key":"matled@gmx.net","avatar":null},"body":"setup_gdg is used as abbreviation for setup_git_directory_gently.\n\nThe work tree can be specified using the environment variable\nGIT_WORK_TREE and the config option core.worktree (the environment\nvariable has precendence over the config option).  Additionally\nthere is a command line option --work-tree which sets the\nenvironment variable.\n\nsetup_gdg does the following now:\n\nGIT_DIR unspecified\nrepository in .git directory\n    parent directory of the .git directory is used as work tree,\n    GIT_WORK_TREE is ignored\n\nGIT_DIR unspecified\nrepository in cwd\n    GIT_DIR is set to cwd\n    see the cases with GIT_DIR specified what happens next and\n    also see the note below\n\nGIT_DIR specified\nGIT_WORK_TREE/core.worktree unspecified\nrepository is bare (config or guessing)\n    no work tree is used\n\nGIT_DIR specified\nGIT_WORK_TREE/core.worktree unspecified\nrepository is not bare (config or guessing)\n    cwd is used as work tree\n\nGIT_DIR specified\nGIT_WORK_TREE/core.worktree specified\n    the specified work tree is used\n\nNote on the case where GIT_DIR is unspecified and repository is in cwd:\n    GIT_WORK_TREE is used but is_inside_git_dir is always true.\n    I did it this way because setup_gdg might be called multiple\n    times (e.g. when doing alias expansion) and in successive calls\n    setup_gdg should do the same thing every time.\n\nMeaning of is_bare/is_inside_work_tree/is_inside_git_dir:\n\n(1) is_bare_repository\n    A repository is bare if core.bare is true or core.bare is\n    unspecified and the name suggests it is bare (directory not\n    named .git).  In general a bare repository is intended to be\n    used without a work tree.  If such a repository is used with a\n    work tree anyway some protection mechanisms which are useful\n    with a work tree are disabled.  Currently this changes if a\n    repository is bare:\n        updates of HEAD are allowed\n        git gc packs the refs\n        the reflog is disabled by default\n        cwd is not used as fallback work tree\n\n(2) is_inside_work_tree\n    True if the cwd is inside the associated working tree (if there\n    is one), false otherwise.\n\n(3) is_inside_git_dir\n    True if the cwd is inside the git directory, false otherwise.\n    Before this patch is_inside_git_dir was always true for bare\n    repositories.\n\nWhen setup_gdg finds a repository git_config(git_default_config) is\nalways called.  This ensure that is_bare_repository makes use of\ncore.bare and does not guess even though core.bare is specified.\n\ninside_work_tree and inside_git_dir are set if setup_gdg finds a\nrepository.  The is_inside_work_tree and is_inside_git_dir functions\nwill die if they are called before a successful call to setup_gdg.\n\nSigned-off-by: Matthias Lederhofer <matled@gmx.net>\n---\n Documentation/config.txt        |    7 ++\n Documentation/git-rev-parse.txt |    4 +\n Documentation/git.txt           |   18 +++-\n builtin-rev-parse.c             |    5 +\n cache.h                         |    2 +\n connect.c                       |    1 +\n git.c                           |   12 ++-\n setup.c                         |  217 +++++++++++++++++++++++++++++----------\n t/test-lib.sh                   |    1 +\n 9 files changed, 210 insertions(+), 57 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 5868d58..4d0bd37 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -172,6 +172,13 @@ 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+\tSet the path to the working tree.  The value will not be\n+\tused in combination with repositories found automatically in\n+\ta .git directory (i.e. $GIT_DIR is not set).\n+\tThis can be overriden by the GIT_WORK_TREE environment\n+\tvariable and the '--work-tree' command line option.\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-rev-parse.txt b/Documentation/git-rev-parse.txt\nindex c817d16..6e4d158 100644\n--- a/Documentation/git-rev-parse.txt\n+++ b/Documentation/git-rev-parse.txt\n@@ -93,6 +93,10 @@ OPTIONS\n \tWhen the current working directory is below the repository\n \tdirectory print \"true\", otherwise \"false\".\n \n+--is-inside-work-tree::\n+\tWhen the current working directory is inside the work tree of the\n+\trepository print \"true\", otherwise \"false\".\n+\n --is-bare-repository::\n \tWhen the repository is bare print \"true\", otherwise \"false\".\n \ndiff --git a/Documentation/git.txt b/Documentation/git.txt\nindex 98860af..4b567d8 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@@ -101,6 +102,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 not be\n+\tused in combination with repositories found automatically in\n+\ta .git directory (i.e. $GIT_DIR is not set).\n+\tThis can also be controlled by setting the GIT_WORK_TREE\n+\tenvironment variable and the core.worktree configuration\n+\tvariable.\n+\n --bare::\n \tSame as --git-dir=`pwd`.\n \n@@ -345,6 +354,13 @@ 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 not be\n+\tused in combination with repositories found automatically in\n+\ta .git directory (i.e. $GIT_DIR is not set).\n+\tThis can also be controlled by the '--work-tree' command line\n+\toption and the core.worktree configuration variable.\n+\n git Commits\n ~~~~~~~~~~~\n 'GIT_AUTHOR_NAME'::\ndiff --git a/builtin-rev-parse.c b/builtin-rev-parse.c\nindex 71d5162..497903a 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-inside-work-tree\")) {\n+\t\t\t\tprintf(\"%s\\n\", is_inside_work_tree() ? \"true\"\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\");\ndiff --git a/cache.h b/cache.h\nindex 8a9d1f3..ae1990a 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -192,6 +192,7 @@ enum object_type {\n };\n \n #define GIT_DIR_ENVIRONMENT \"GIT_DIR\"\n+#define GIT_WORK_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@@ -207,6 +208,7 @@ 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 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);\ndiff --git a/connect.c b/connect.c\nindex 8cbda88..aafa416 100644\n--- a/connect.c\n+++ b/connect.c\n@@ -589,6 +589,7 @@ pid_t git_connect(int fd[2], char *url, const char *prog, int flags)\n \t\t\tunsetenv(ALTERNATE_DB_ENVIRONMENT);\n \t\t\tunsetenv(DB_ENVIRONMENT);\n \t\t\tunsetenv(GIT_DIR_ENVIRONMENT);\n+\t\t\tunsetenv(GIT_WORK_TREE_ENVIRONMENT);\n \t\t\tunsetenv(GRAFT_ENVIRONMENT);\n \t\t\tunsetenv(INDEX_ENVIRONMENT);\n \t\t\texeclp(\"sh\", \"sh\", \"-c\", command, NULL);\ndiff --git a/git.c b/git.c\nindex 29b55a1..05a391b 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@@ -69,6 +69,16 @@ static int handle_options(const char*** argv, int* argc)\n \t\t\thandled++;\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_WORK_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_WORK_TREE_ENVIRONMENT, cmd + 12, 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..4856232 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -174,41 +174,93 @@ static int inside_git_dir = -1;\n \n int is_inside_git_dir(void)\n {\n-\tif (inside_git_dir < 0) {\n-\t\tchar buffer[1024];\n-\n-\t\tif (is_bare_repository())\n-\t\t\treturn (inside_git_dir = 1);\n-\t\tif (getcwd(buffer, sizeof(buffer))) {\n-\t\t\tconst char *git_dir = get_git_dir(), *cwd = buffer;\n-\t\t\twhile (*git_dir && *git_dir == *cwd) {\n-\t\t\t\tgit_dir++;\n-\t\t\t\tcwd++;\n-\t\t\t}\n-\t\t\tinside_git_dir = !*git_dir;\n-\t\t} else\n-\t\t\tinside_git_dir = 0;\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+}\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+}\n+\n+static char *gitworktree_config;\n+\n+static int git_setup_config(const char *var, const char *value)\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 \t}\n-\treturn inside_git_dir;\n+\treturn git_default_config(var, value);\n }\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+\tchar worktree[PATH_MAX+1], gitdir[PATH_MAX+1];\n+\tconst char *gitdirenv, *gitworktree;\n+\tint wt_rel_gitdir = 0;\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\tif (PATH_MAX - 40 < strlen(gitdirenv))\n-\t\t\tdie(\"'$%s' too big\", GIT_DIR_ENVIRONMENT);\n-\t\tif (is_git_directory(gitdirenv))\n+\tif (!gitdirenv) {\n+\t\tint len, offset;\n+\n+\t\tif (!getcwd(cwd, sizeof(cwd)-1) || cwd[0] != '/')\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}\n+\n+\tif (PATH_MAX - 40 < strlen(gitdirenv)) {\n+\t\tif (nongit_ok) {\n+\t\t\t*nongit_ok = 1;\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@@ -218,41 +270,96 @@ const char *setup_git_directory_gently(int *nongit_ok)\n \n \tif (!getcwd(cwd, sizeof(cwd)-1) || cwd[0] != '/')\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) || gitdir[0] != '/')\n+\t\tdie(\"Unable to read current working directory\");\n+\tif (chdir(cwd))\n+\t\tdie(\"Cannot come back to cwd\");\n \n-\toffset = len = strlen(cwd);\n-\tfor (;;) {\n-\t\tif (is_git_directory(\".git\"))\n-\t\t\tbreak;\n-\t\tchdir(\"..\");\n-\t\tdo {\n-\t\t\tif (!offset) {\n-\t\t\t\tif (is_git_directory(cwd)) {\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\tsetenv(GIT_DIR_ENVIRONMENT, cwd, 1);\n-\t\t\t\t\tinside_git_dir = 1;\n-\t\t\t\t\treturn NULL;\n-\t\t\t\t}\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/*\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 */\n+\tif (gitdirenv[0] != '/') {\n+\t\tsetenv(GIT_DIR_ENVIRONMENT, gitdir, 1);\n+\t\tgitdirenv = getenv(GIT_DIR_ENVIRONMENT);\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} while (cwd[--offset] != '/');\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 (offset == len)\n+\t/* stop if the repository is bare and does not have a work tree */\n+\tif (!gitworktree && is_bare_repository()) {\n+\t\tinside_work_tree = 0;\n \t\treturn NULL;\n+\t}\n \n-\t/* Make \"offset\" point to past the '/', and add a '/' at the end */\n-\toffset++;\n-\tcwd[len++] = '/';\n-\tcwd[len] = 0;\n-\tinside_git_dir = !prefixcmp(cwd + offset, \".git/\");\n-\treturn cwd + offset;\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+\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) || worktree[0] != '/')\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}\n+\n+\tif (!inside_work_tree) {\n+\t\tif (chdir(cwd))\n+\t\t\tdie(\"Cannot come back to cwd\");\n+\t\treturn NULL;\n+\t}\n+\n+\tif (!strcmp(cwd, worktree))\n+\t\treturn NULL;\n+\treturn cwd+strlen(worktree);\n }\n \n int git_config_perm(const char *var, const char *value)\ndiff --git a/t/test-lib.sh b/t/test-lib.sh\nindex dee3ad7..b61e1d5 100644\n--- a/t/test-lib.sh\n+++ b/t/test-lib.sh\n@@ -26,6 +26,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.3\n"},{"id":"43879","messageId":"20070603144816.GE20061@moooo.ath.cx","threadId":"8411","inReplyTo":"20070603144401.GA9518@moooo.ath.cx","subject":"Re: [RFC] GIT_WORK_TREE","fromName":"Matthias Lederhofer","fromEmail":"matled@gmx.net","sentAt":"2007-06-03T14:48:16Z","receivedAt":"2007-06-03T14:48:16Z","isPatch":false,"sender":{"key":"matled@gmx.net","avatar":null},"body":"Up to now to check for a working tree this was used:\n\t!is_bare && !inside_git_dir\n(the check for bare is redundant because is_inside_git_dir\nreturned already 1 for bare repositories).\nNow the check is:\n\tinside_work_tree && !inside_git_dir\n\nSigned-off-by: Matthias Lederhofer <matled@gmx.net>\n---\n builtin-ls-files.c |    2 +-\n git-sh-setup.sh    |    2 +-\n git-svn.perl       |    2 +-\n git.c              |   20 ++++++++++----------\n setup.c            |    2 +-\n 5 files changed, 14 insertions(+), 14 deletions(-)\n\ndiff --git a/builtin-ls-files.c b/builtin-ls-files.c\nindex f7c066b..48a3135 100644\n--- a/builtin-ls-files.c\n+++ b/builtin-ls-files.c\n@@ -470,7 +470,7 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)\n \t}\n \n \tif (require_work_tree &&\n-\t\t\t(is_bare_repository() || is_inside_git_dir()))\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 \n \tpathspec = get_pathspec(prefix, argv + i);\ndiff --git a/git-sh-setup.sh b/git-sh-setup.sh\nindex 9ac657a..0de49e8 100755\n--- a/git-sh-setup.sh\n+++ b/git-sh-setup.sh\n@@ -44,7 +44,7 @@ cd_to_toplevel () {\n }\n \n require_work_tree () {\n-\ttest $(is_bare_repository) = false &&\n+\ttest $(git-rev-parse --is-inside-work-tree) = true &&\n \ttest $(git-rev-parse --is-inside-git-dir) = false ||\n \tdie \"fatal: $0 cannot be used without a working tree.\"\n }\ndiff --git a/git-svn.perl b/git-svn.perl\nindex e3a5cbb..886b898 100755\n--- a/git-svn.perl\n+++ b/git-svn.perl\n@@ -594,7 +594,7 @@ sub post_fetch_checkout {\n \tmy $index = $ENV{GIT_INDEX_FILE} || \"$ENV{GIT_DIR}/index\";\n \treturn if -f $index;\n \n-\treturn if command_oneline(qw/rev-parse --is-bare-repository/) eq 'true';\n+\treturn if command_oneline(qw/rev-parse --is-inside-work-tree/) eq 'false';\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 \tprint STDERR \"Checked out HEAD:\\n  \",\ndiff --git a/git.c b/git.c\nindex 05a391b..cd3910a 100644\n--- a/git.c\n+++ b/git.c\n@@ -224,7 +224,7 @@ const char git_version_string[] = GIT_VERSION;\n  * require working tree to be present -- anything uses this needs\n  * RUN_SETUP for reading from the configuration file.\n  */\n-#define NOT_BARE \t(1<<2)\n+#define NEED_WORK_TREE\t(1<<2)\n \n static void handle_internal_command(int argc, const char **argv, char **envp)\n {\n@@ -234,7 +234,7 @@ static void handle_internal_command(int argc, const char **argv, char **envp)\n \t\tint (*fn)(int, const char **, const char *);\n \t\tint option;\n \t} commands[] = {\n-\t\t{ \"add\", cmd_add, RUN_SETUP | NOT_BARE },\n+\t\t{ \"add\", cmd_add, RUN_SETUP | NEED_WORK_TREE },\n \t\t{ \"annotate\", cmd_annotate, RUN_SETUP | USE_PAGER },\n \t\t{ \"apply\", cmd_apply },\n \t\t{ \"archive\", cmd_archive },\n@@ -244,9 +244,9 @@ static void handle_internal_command(int argc, const char **argv, char **envp)\n \t\t{ \"cat-file\", cmd_cat_file, RUN_SETUP },\n \t\t{ \"checkout-index\", cmd_checkout_index, RUN_SETUP },\n \t\t{ \"check-ref-format\", cmd_check_ref_format },\n-\t\t{ \"check-attr\", cmd_check_attr, RUN_SETUP | NOT_BARE },\n+\t\t{ \"check-attr\", cmd_check_attr, RUN_SETUP | NEED_WORK_TREE },\n \t\t{ \"cherry\", cmd_cherry, RUN_SETUP },\n-\t\t{ \"cherry-pick\", cmd_cherry_pick, RUN_SETUP | NOT_BARE },\n+\t\t{ \"cherry-pick\", cmd_cherry_pick, RUN_SETUP | NEED_WORK_TREE },\n \t\t{ \"commit-tree\", cmd_commit_tree, RUN_SETUP },\n \t\t{ \"config\", cmd_config },\n \t\t{ \"count-objects\", cmd_count_objects, RUN_SETUP },\n@@ -274,7 +274,7 @@ static void handle_internal_command(int argc, const char **argv, char **envp)\n \t\t{ \"mailsplit\", cmd_mailsplit },\n \t\t{ \"merge-base\", cmd_merge_base, RUN_SETUP },\n \t\t{ \"merge-file\", cmd_merge_file },\n-\t\t{ \"mv\", cmd_mv, RUN_SETUP | NOT_BARE },\n+\t\t{ \"mv\", cmd_mv, RUN_SETUP | NEED_WORK_TREE },\n \t\t{ \"name-rev\", cmd_name_rev, RUN_SETUP },\n \t\t{ \"pack-objects\", cmd_pack_objects, RUN_SETUP },\n \t\t{ \"pickaxe\", cmd_blame, RUN_SETUP | USE_PAGER },\n@@ -287,9 +287,9 @@ static void handle_internal_command(int argc, const char **argv, char **envp)\n \t\t{ \"rerere\", cmd_rerere, RUN_SETUP },\n \t\t{ \"rev-list\", cmd_rev_list, RUN_SETUP },\n \t\t{ \"rev-parse\", cmd_rev_parse, RUN_SETUP },\n-\t\t{ \"revert\", cmd_revert, RUN_SETUP | NOT_BARE },\n-\t\t{ \"rm\", cmd_rm, RUN_SETUP | NOT_BARE },\n-\t\t{ \"runstatus\", cmd_runstatus, RUN_SETUP | NOT_BARE },\n+\t\t{ \"revert\", cmd_revert, RUN_SETUP | NEED_WORK_TREE },\n+\t\t{ \"rm\", cmd_rm, RUN_SETUP | NEED_WORK_TREE },\n+\t\t{ \"runstatus\", cmd_runstatus, RUN_SETUP | NEED_WORK_TREE },\n \t\t{ \"shortlog\", cmd_shortlog, RUN_SETUP | USE_PAGER },\n \t\t{ \"show-branch\", cmd_show_branch, RUN_SETUP },\n \t\t{ \"show\", cmd_show, RUN_SETUP | USE_PAGER },\n@@ -326,8 +326,8 @@ static void handle_internal_command(int argc, const char **argv, char **envp)\n \t\t\tprefix = setup_git_directory();\n \t\tif (p->option & USE_PAGER)\n \t\t\tsetup_pager();\n-\t\tif ((p->option & NOT_BARE) &&\n-\t\t\t\t(is_bare_repository() || is_inside_git_dir()))\n+\t\tif ((p->option & NEED_WORK_TREE) &&\n+\t\t\t\t(!is_inside_work_tree() || is_inside_git_dir()))\n \t\t\tdie(\"%s must be run in a work tree\", cmd);\n \t\ttrace_argv_printf(argv, argc, \"trace: built-in: git\");\n \ndiff --git a/setup.c b/setup.c\nindex 4856232..ddf4013 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -95,7 +95,7 @@ void verify_non_filename(const char *prefix, const char *arg)\n \tconst char *name;\n \tstruct stat st;\n \n-\tif (is_inside_git_dir())\n+\tif (!is_inside_work_tree() || is_inside_git_dir())\n \t\treturn;\n \tif (*arg == '-')\n \t\treturn; /* flag */\n-- \n1.5.0.3\n"},{"id":"43878","messageId":"20070603144846.GF20061@moooo.ath.cx","threadId":"8411","inReplyTo":"20070603144401.GA9518@moooo.ath.cx","subject":"[PATCH 6/7] extend rev-parse test for --is-inside-work-tree","fromName":"Matthias Lederhofer","fromEmail":"matled@gmx.net","sentAt":"2007-06-03T14:48:46Z","receivedAt":"2007-06-03T14:48:46Z","isPatch":true,"sender":{"key":"matled@gmx.net","avatar":null},"body":"Signed-off-by: Matthias Lederhofer <matled@gmx.net>\n---\n t/t1500-rev-parse.sh |   33 +++++++++++++++++++--------------\n 1 files changed, 19 insertions(+), 14 deletions(-)\n\ndiff --git a/t/t1500-rev-parse.sh b/t/t1500-rev-parse.sh\nindex a180309..44cb141 100755\n--- a/t/t1500-rev-parse.sh\n+++ b/t/t1500-rev-parse.sh\n@@ -17,42 +17,47 @@ test_rev_parse() {\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 }\n \n-test_rev_parse toplevel false false ''\n+test_rev_parse toplevel false false true ''\n \n cd .git || exit 1\n-test_rev_parse .git/ false true .git/\n+test_rev_parse .git/ false true true .git/\n cd objects || exit 1\n-test_rev_parse .git/objects/ false true .git/objects/\n+test_rev_parse .git/objects/ false true true .git/objects/\n cd ../.. || exit 1\n \n mkdir -p sub/dir || exit 1\n cd sub/dir || exit 1\n-test_rev_parse subdirectory false false sub/dir/\n+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\n+test_rev_parse 'core.bare = true' true false true\n \n git config --unset core.bare\n-test_rev_parse 'core.bare undefined' false\n+test_rev_parse 'core.bare undefined' false false true\n \n-mv .git foo.git || exit 1\n-export GIT_DIR=foo.git\n-export GIT_CONFIG=foo.git/config\n-\n-git config core.bare true\n-test_rev_parse 'GIT_DIR=foo.git, core.bare = true' true\n+mv .git repo.git || exit 1\n+export GIT_DIR=repo.git\n+export GIT_CONFIG=repo.git/config\n \n git config core.bare false\n-test_rev_parse 'GIT_DIR=foo.git, core.bare = false' 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 false\n \n git config --unset core.bare\n-test_rev_parse 'GIT_DIR=foo.git, core.bare undefined' true\n+test_rev_parse 'GIT_DIR=repo.git, core.bare undefined' true false false\n \n test_done\n-- \n1.5.0.3\n"},{"id":"43880","messageId":"20070603144925.GG20061@moooo.ath.cx","threadId":"8411","inReplyTo":"20070603144401.GA9518@moooo.ath.cx","subject":"[PATCH 7/7] test GIT_WORK_TREE","fromName":"Matthias Lederhofer","fromEmail":"matled@gmx.net","sentAt":"2007-06-03T14:49:25Z","receivedAt":"2007-06-03T14:49:25Z","isPatch":true,"sender":{"key":"matled@gmx.net","avatar":null},"body":"Signed-off-by: Matthias Lederhofer <matled@gmx.net>\n---\n t/t1501-worktree.sh |  119 +++++++++++++++++++++++++++++++++++++++++++++++++++\n 1 files changed, 119 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..d9d9e4a\n--- /dev/null\n+++ b/t/t1501-worktree.sh\n@@ -0,0 +1,119 @@\n+#!/bin/sh\n+\n+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+}\n+\n+mkdir -p work/sub/dir || exit 1\n+\n+say \"fallback work tree (name ending in .git)\"\n+cd work || exit 1\n+export GIT_DIR=../.git\n+export GIT_CONFIG=$GIT_DIR/config\n+unset GIT_WORK_TREE\n+git config core.bare true\n+test_rev_parse 'core.bare = true'    true  false false\n+git config --unset core.bare\n+test_rev_parse 'core.bare undefined' false false true\n+git config core.bare false\n+test_rev_parse 'core.bare = false'   false false true ''\n+cd .. || exit 1\n+\n+mv .git repo.git || exit 1\n+\n+say \"fallback work tree (name ending in repo.git)\"\n+cd work || exit 1\n+export GIT_DIR=../repo.git\n+export GIT_CONFIG=$GIT_DIR/config\n+unset GIT_WORK_TREE\n+git config core.bare true\n+test_rev_parse 'core.bare = true'    true  false false\n+git config --unset core.bare\n+test_rev_parse 'core.bare undefined' true  false false\n+git config core.bare false\n+test_rev_parse 'core.bare = false'   false false true ''\n+cd .. || exit 1\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+test_rev_parse 'subdirectory' false false true sub/dir/\n+cd ../../.. || exit 1\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+test_rev_parse 'subdirectory' false false true sub/dir/\n+cd ../../.. || exit 1\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+test_rev_parse 'subdirectory' false false true sub/dir/\n+cd ../../.. || exit 1\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+\n+test_done\n-- \n1.5.0.3\n"},{"id":"43881","messageId":"20070603145159.GA21003@moooo.ath.cx","threadId":"8411","inReplyTo":"20070603144816.GE20061@moooo.ath.cx","subject":"Re: [RFC] GIT_WORK_TREE","fromName":"Matthias Lederhofer","fromEmail":"matled@gmx.net","sentAt":"2007-06-03T14:51:59Z","receivedAt":"2007-06-03T14:51:59Z","isPatch":false,"sender":{"key":"matled@gmx.net","avatar":null},"body":"Subject should have been:\n[PATCH] use new semantics of is_bare/inside_git_dir/inside_work_tree\n"},{"id":"43888","messageId":"loom.20070603T175743-376@post.gmane.org","threadId":"8411","inReplyTo":"20070603144401.GA9518@moooo.ath.cx","subject":"Re: [RFC] GIT_WORK_TREE","fromName":"Sergio","fromEmail":"sergio.callegari@gmail.com","sentAt":"2007-06-03T16:02:29Z","receivedAt":"2007-06-03T16:02:29Z","isPatch":false,"sender":{"key":"sergio.callegari@gmail.com","avatar":"https://gravatar.com/avatar/c98f41317e0422c1e630385de0e3970227b8e5ad15f35ba8586066467cc833bc?d=mp&s=160"},"body":"Matthias Lederhofer <matled <at> gmx.net> writes:\n \n> This series introduces the GIT_WORK_TREE environment variable (and\n> core.worktree config option) to specify the working tree that should\n> be used with the repository (not for repositories found as .git\n> directory).  This allows to separate the repository and working tree.\n\nHi,\n\na question regarding GIT_WORK_TREE and (possibly) a suggestion...\n\nIf I am not wrong, with this we detach the WT from the REPO by letting git know\nour working tree if the working tree does not include a repo (.git) directory.\nAnd this is done either:\n- by setting the GIT_WORK_TREE environment variable whenever needed\n- by passing the --work-tree parameter to git when needed\n- by setting the core.worktree config option in the git repo, so that the\nrepository knows where its default work tree is...\n\nIs this correct? or am I missing some other ways?\n\nWould it make sense to make the _WT_ know where its repo is?\n\nI.e. having something like a .git-repo file a the top dir of a WT, so that when\ngit is invoked within the WT it can scan up the WT until it finds the .git-repo\nfile and automatically decide that GIT_WORK_TREE is at the dir containing that\n.git-repo file and that GIT_DIR is at the file pointed by that .git-repo?\n\nThanks,\n\nSergio\n"},{"id":"43900","messageId":"20070603193203.GA24781@moooo.ath.cx","threadId":"8411","inReplyTo":"loom.20070603T175743-376@post.gmane.org","subject":"Re: [RFC] GIT_WORK_TREE","fromName":"Matthias Lederhofer","fromEmail":"matled@gmx.net","sentAt":"2007-06-03T19:32:03Z","receivedAt":"2007-06-03T19:32:03Z","isPatch":false,"sender":{"key":"matled@gmx.net","avatar":null},"body":"Sergio <sergio.callegari@gmail.com> wrote:\n> Matthias Lederhofer <matled <at> gmx.net> writes:\n> If I am not wrong, with this we detach the WT from the REPO by letting git know\n> our working tree if the working tree does not include a repo (.git) directory.\n> And this is done either:\n> - by setting the GIT_WORK_TREE environment variable whenever needed\n> - by passing the --work-tree parameter to git when needed\n> - by setting the core.worktree config option in the git repo, so that the\n> repository knows where its default work tree is...\n> \n> Is this correct? or am I missing some other ways?\n\nThat's right, you'd set GIT_DIR and core.worktree/GIT_WORK_TREE.\n\n> Would it make sense to make the _WT_ know where its repo is?\n>\n> I.e. having something like a .git-repo file a the top dir of a WT, so that when\n> git is invoked within the WT it can scan up the WT until it finds the .git-repo\n> file and automatically decide that GIT_WORK_TREE is at the dir containing that\n> .git-repo file and that GIT_DIR is at the file pointed by that .git-repo?\n\nSymlinking the .git directory is quite similar to this and works\nalready without this patch series.  Anyway I spontaneously can think\nof the following use cases, so it might be interesting to add this\nfeature:\n- The use case Nguyen mentioned, e.g. the filesystem does not support\n  symlinks and for some reason it is not possible to use the git\n  repository next to the working tree.\n- When executing potentially 'dangerous' programs in the working tree\n  it is safer to have a file pointing to the repository than placing\n  the repository or a symlink to the repository in the working tree\n  (breaking the .git-repo file might be confusing but is not as bad as\n  breaking the repository).\n- In case of a publicly available working tree it might be ok to\n  publish the path to the repository accidentially (which might happen\n  if the permissions for the .git-repo file are too loose) but there\n  would be no risk that wrong permissions could disclose the\n  repository itself.\n\nWhat I haven't thought through is if it could make sense to honor the\nGIT_WORK_TREE/core.worktree setting when such a .git-repo file is used\nor just use the directory containing the file as work tree.\n"},{"id":"43913","messageId":"loom.20070603T232437-414@post.gmane.org","threadId":"8411","inReplyTo":"20070603193203.GA24781@moooo.ath.cx","subject":"Re: [RFC] GIT_WORK_TREE","fromName":"Sergio","fromEmail":"sergio.callegari@gmail.com","sentAt":"2007-06-03T21:34:04Z","receivedAt":"2007-06-03T21:34:04Z","isPatch":false,"sender":{"key":"sergio.callegari@gmail.com","avatar":"https://gravatar.com/avatar/c98f41317e0422c1e630385de0e3970227b8e5ad15f35ba8586066467cc833bc?d=mp&s=160"},"body":"Matthias Lederhofer <matled <at> gmx.net> writes:\n\n> What I haven't thought through is if it could make sense to honor the\n> GIT_WORK_TREE/core.worktree setting when such a .git-repo file is used\n> or just use the directory containing the file as work tree.\n\nI would do the first... for the following reason...\n\nSuppose that by accident you move the working tree and you cd to some\npoint in the moved WT...\nYou issue a git command...\nBy climbing up the directory hierarchy, git gets to the .git-repo file\nso now it knows where the repo is...\nBut running a command and following the core.worktree config it might\nput  output in the wrong output dir...\n\nBut actually I also see problems the other way round...\n\nSuppose you have project A containing a dir B that is under its own git\ntracking...\nAlso suppose that both A and B have repos separated from WT.\nIf for some reason WT of B misses its .git-repo, then there is trouble\non the way: when issuing a command in B, by climbing up git would find\nthe .git-repo of A, thinking that it is the git-repo of B...\nA weird case, though.\n\nSergio\n"},{"id":"44042","messageId":"7vodjudei2.fsf@assigned-by-dhcp.cox.net","threadId":"8411","inReplyTo":"20070603144714.GD20061@moooo.ath.cx","subject":"Re: [PATCH 4/7] introduce GIT_WORK_TREE to specify the work tree","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-06-05T07:52:53Z","receivedAt":"2007-06-05T07:52:53Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Hmph.\n\nWhen this series is applied on top of 'next' (or whatever\ncontains t7003-filter-branch.sh), this seems to break it quite\nbadly.\n"},{"id":"44080","messageId":"20070605164957.GA12358@moooo.ath.cx","threadId":"8411","inReplyTo":"7vodjudei2.fsf@assigned-by-dhcp.cox.net","subject":"[PATCH] filter-branch: always export GIT_DIR if it is set","fromName":"Matthias Lederhofer","fromEmail":"matled@gmx.net","sentAt":"2007-06-05T16:49:57Z","receivedAt":"2007-06-05T16:49:57Z","isPatch":true,"sender":{"key":"matled@gmx.net","avatar":null},"body":"Currently filter-branch exports GIT_DIR only if it is a\nrelative path but git-sh-setup might also set GIT_DIR to an\nabsolute path that is not exported yet.  Additionally we need\nto export GIT_WORK_TREE with GIT_DIR to ensure that the\ncurrent working directory is used as working tree even for\nbare repositories.\n\nSigned-off-by: Matthias Lederhofer <matled@gmx.net>\n---\nJunio C Hamano <gitster@pobox.com> wrote:\n> Hmph.\n> \n> When this series is applied on top of 'next' (or whatever\n> contains t7003-filter-branch.sh), this seems to break it quite\n> badly.\n\nWith the GIT_WORK_TREE patch series a relative path in GIT_DIR is\nexpanded to an absolute path.  Therefore\n    GIT_DIR=$(GIT_DIR=.git git rev-parse --git-dir)\nin git-sh-setup will give the full path to the repository.\ngit-filter-branch exports GIT_DIR only if the path is relative.  In\nconsequence GIT_DIR was not set at all and the following git commands\nfailed.  Additionally GIT_WORK_TREE has to be exported because to make\nsure that the current directory is used as working tree even for bare\nrepositories.\n\nI merged the worktree branch to next and applied the patch, all tests\npassed.\n\nThis problem reveals a small change which might cause trouble with other\nscripts.  I looked at the git repository and found no other script which\nshould have problems with this series.  With\n    $ git grep -e export --and -e GIT_DIR\nI found:\n    Documentation/install-doc-quick.sh\n    git-clone.sh\n    git-instaweb.sh\n        These do not need a working tree.\n    git-cvsexportcommit.perl\n        git apply is used with GIT_DIR='', this forces git-apply not to\n        use the git repository.\n\nI'm not sure if any other script out there tries to do this.  Perhaps we\nshould just keep the old behaviour and use the current directory as\nworking tree when the repository name ends in /.git even though\ncore.bare is true?\n---\n git-filter-branch.sh |    3 +++\n 1 files changed, 3 insertions(+), 0 deletions(-)\n\ndiff --git a/git-filter-branch.sh b/git-filter-branch.sh\nindex 0c8a7df..f4cfbea 100644\n--- a/git-filter-branch.sh\n+++ b/git-filter-branch.sh\n@@ -313,9 +313,12 @@ workdir=\"$(pwd)\"\n \n case \"$GIT_DIR\" in\n /*)\n+\texport GIT_DIR\n+\texport GIT_WORK_TREE=.\n \t;;\n *)\n \texport GIT_DIR=\"$(pwd)/../../$GIT_DIR\"\n+\texport GIT_WORK_TREE=.\n \t;;\n esac\n \n-- \n1.5.2.1.120.g3877-dirty\n"},{"id":"44088","messageId":"Pine.LNX.4.64.0706051823140.4046@racer.site","threadId":"8411","inReplyTo":"20070605164957.GA12358@moooo.ath.cx","subject":"Re: [PATCH] filter-branch: always export GIT_DIR if it is set","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-06-05T17:27:15Z","receivedAt":"2007-06-05T17:27:15Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Tue, 5 Jun 2007, Matthias Lederhofer wrote:\n\n> diff --git a/git-filter-branch.sh b/git-filter-branch.sh\n> index 0c8a7df..f4cfbea 100644\n> --- a/git-filter-branch.sh\n> +++ b/git-filter-branch.sh\n> @@ -313,9 +313,12 @@ workdir=\"$(pwd)\"\n>  \n>  case \"$GIT_DIR\" in\n>  /*)\n> +\texport GIT_DIR\n> +\texport GIT_WORK_TREE=.\n>  \t;;\n\nDoesn't it strike somebody else as intrusive, if GIT_WORK_TREE has to \ntouch that many places?\n\nIMHO there should be a less intrusive, and possibly simpler, way to do it. \nI am not at all interested in that feature, and I don't want to suffer \nbugs from it either.\n\nCiao,\nDscho\n"},{"id":"44101","messageId":"7v7iqib0f6.fsf@assigned-by-dhcp.cox.net","threadId":"8411","inReplyTo":"Pine.LNX.4.64.0706051823140.4046@racer.site","subject":"Re: [PATCH] filter-branch: always export GIT_DIR if it is set","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-06-05T20:39:57Z","receivedAt":"2007-06-05T20:39:57Z","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> On Tue, 5 Jun 2007, Matthias Lederhofer wrote:\n>\n>> diff --git a/git-filter-branch.sh b/git-filter-branch.sh\n>> index 0c8a7df..f4cfbea 100644\n>> --- a/git-filter-branch.sh\n>> +++ b/git-filter-branch.sh\n>> @@ -313,9 +313,12 @@ workdir=\"$(pwd)\"\n>>  \n>>  case \"$GIT_DIR\" in\n>>  /*)\n>> +\texport GIT_DIR\n>> +\texport GIT_WORK_TREE=.\n>>  \t;;\n>\n> Doesn't it strike somebody else as intrusive, if GIT_WORK_TREE has to \n> touch that many places?\n>\n> IMHO there should be a less intrusive, and possibly simpler, way to do it. \n> I am not at all interested in that feature, and I don't want to suffer \n> bugs from it either.\n\nI suspect \"bug\" might be a bit too strong a word here, but this\ndefinitely shows that work-tree series has a change of behaviour\nthat is subtle on the suface but with a huge impact.\n\nIt _might_ a bug for filter-branch to export GIT_DIR; sh-setup\ndeliberately chooses _not_ to export it.  I haven't really\nthought through the issues, though...\n"},{"id":"44124","messageId":"20070606070121.GA18315@moooo.ath.cx","threadId":"8411","inReplyTo":"20070603144700.GC20061@moooo.ath.cx","subject":"[PATCH 3/7 (amend)] test git rev-parse","fromName":"Matthias Lederhofer","fromEmail":"matled@gmx.net","sentAt":"2007-06-06T07:01:21Z","receivedAt":"2007-06-06T07:01:21Z","isPatch":true,"sender":{"key":"matled@gmx.net","avatar":null},"body":"Signed-off-by: Matthias Lederhofer <matled@gmx.net>\n---\nThe amended version has a new test:\nWhen GIT_DIR is set and the repository is not bare the current working\ndirectory should be used as working tree.\n---\n t/t1500-rev-parse.sh |   72 ++++++++++++++++++++++++++++++++++++++++++++++++++\n 1 files changed, 72 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..66b0e58\n--- /dev/null\n+++ b/t/t1500-rev-parse.sh\n@@ -0,0 +1,72 @@\n+#!/bin/sh\n+\n+test_description='test git rev-parse'\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: prefix\" \\\n+\t\"test '$1' = \\\"\\$(git rev-parse --show-prefix)\\\"\"\n+\tshift\n+\t[ $# -eq 0 ] && return\n+}\n+\n+test_rev_parse toplevel false false ''\n+\n+cd .git || exit 1\n+test_rev_parse .git/ false true .git/\n+cd objects || exit 1\n+test_rev_parse .git/objects/ false true .git/objects/\n+cd ../.. || exit 1\n+\n+mkdir -p sub/dir || exit 1\n+cd sub/dir || exit 1\n+test_rev_parse subdirectory false false sub/dir/\n+cd ../.. || exit 1\n+\n+git config core.bare true\n+test_rev_parse 'core.bare = true' true\n+\n+git config --unset core.bare\n+test_rev_parse 'core.bare undefined' false\n+\n+mkdir work || exit 1\n+cd work || exit 1\n+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 ''\n+\n+git config core.bare true\n+test_rev_parse 'GIT_DIR=../.git, core.bare = true' true\n+\n+git config --unset core.bare\n+test_rev_parse 'GIT_DIR=../.git, core.bare undefined' false false ''\n+\n+mv ../.git ../repo.git || exit 1\n+export GIT_DIR=../repo.git\n+export GIT_CONFIG=\"$GIT_DIR\"/config\n+\n+git config core.bare false\n+test_rev_parse 'GIT_DIR=../repo.git, core.bare = false' false false ''\n+\n+git config core.bare true\n+test_rev_parse 'GIT_DIR=../repo.git, core.bare = true' true\n+\n+git config --unset core.bare\n+test_rev_parse 'GIT_DIR=../repo.git, core.bare undefined' true\n+\n+test_done\n-- \n1.5.2.1.116.g9f308\n"},{"id":"44125","messageId":"20070606071042.GB18315@moooo.ath.cx","threadId":"8411","inReplyTo":"20070603144714.GD20061@moooo.ath.cx","subject":"[PATCH 4/7 (amend)] introduce GIT_WORK_TREE to specify the work tree","fromName":"Matthias Lederhofer","fromEmail":"matled@gmx.net","sentAt":"2007-06-06T07:10:42Z","receivedAt":"2007-06-06T07:10:42Z","isPatch":true,"sender":{"key":"matled@gmx.net","avatar":null},"body":"Dscho, Junio and me discussed about this in #git and it seems that the\nbest way to handle GIT_DIR is to use the current working directory as\nfallback for the working tree always, ignoring if the repository is\nbare.  With this change all scripts that worked before this series\nshould still work as long as the user does not set GIT_WORK_TREE or\ncore.worktree.\n\nWith this series scripts which want to use a specific repository with\na specific working tree should just set GIT_DIR and GIT_WORK_TREE.\nThis tells git explicitly which directory should be used as work tree.\n\nThe problem before this change was:\nSome scripts export GIT_DIR (set by git-sh-setup) and expect that the\ncurrent working directory is used as working tree after this.  This\ndid not work anymore if the repository was bare.  Even before the\npatch series there were cases where this did not work but after this\nchange to the patch the new behaviour should be less strict.\n\n-----8<-----\nintroduce GIT_WORK_TREE to specify the work tree\n\nsetup_gdg is used as abbreviation for setup_git_directory_gently.\n\nThe work tree can be specified using the environment variable\nGIT_WORK_TREE and the config option core.worktree (the environment\nvariable has precendence over the config option).  Additionally\nthere is a command line option --work-tree which sets the\nenvironment variable.\n\nsetup_gdg does the following now:\n\nGIT_DIR unspecified\nrepository in .git directory\n    parent directory of the .git directory is used as work tree,\n    GIT_WORK_TREE is ignored\n\nGIT_DIR unspecified\nrepository in cwd\n    GIT_DIR is set to cwd\n    see the cases with GIT_DIR specified what happens next and\n    also see the note below\n\nGIT_DIR specified\nGIT_WORK_TREE/core.worktree unspecified\n    cwd is used as work tree\n\nGIT_DIR specified\nGIT_WORK_TREE/core.worktree specified\n    the specified work tree is used\n\nNote on the case where GIT_DIR is unspecified and repository is in cwd:\n    GIT_WORK_TREE is used but is_inside_git_dir is always true.\n    I did it this way because setup_gdg might be called multiple\n    times (e.g. when doing alias expansion) and in successive calls\n    setup_gdg should do the same thing every time.\n\nMeaning of is_bare/is_inside_work_tree/is_inside_git_dir:\n\n(1) is_bare_repository\n    A repository is bare if core.bare is true or core.bare is\n    unspecified and the name suggests it is bare (directory not\n    named .git).  The bare option disables a few protective\n    checks which are useful with a working tree.  Currently\n    this changes if a repository is bare:\n        updates of HEAD are allowed\n        git gc packs the refs\n        the reflog is disabled by default\n        cwd is not used as fallback work tree\n\n(2) is_inside_work_tree\n    True if the cwd is inside the associated working tree (if there\n    is one), false otherwise.\n\n(3) is_inside_git_dir\n    True if the cwd is inside the git directory, false otherwise.\n    Before this patch is_inside_git_dir was always true for bare\n    repositories.\n\nWhen setup_gdg finds a repository git_config(git_default_config) is\nalways called.  This ensure that is_bare_repository makes use of\ncore.bare and does not guess even though core.bare is specified.\n\ninside_work_tree and inside_git_dir are set if setup_gdg finds a\nrepository.  The is_inside_work_tree and is_inside_git_dir functions\nwill die if they are called before a successful call to setup_gdg.\n\nSigned-off-by: Matthias Lederhofer <matled@gmx.net>\n---\n Documentation/config.txt        |    7 ++\n Documentation/git-rev-parse.txt |    4 +\n Documentation/git.txt           |   18 +++-\n builtin-rev-parse.c             |    5 +\n cache.h                         |    2 +\n connect.c                       |    1 +\n git.c                           |   12 ++-\n setup.c                         |  211 +++++++++++++++++++++++++++++----------\n t/test-lib.sh                   |    1 +\n 9 files changed, 204 insertions(+), 57 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 5868d58..4d0bd37 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -172,6 +172,13 @@ 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+\tSet the path to the working tree.  The value will not be\n+\tused in combination with repositories found automatically in\n+\ta .git directory (i.e. $GIT_DIR is not set).\n+\tThis can be overriden by the GIT_WORK_TREE environment\n+\tvariable and the '--work-tree' command line option.\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-rev-parse.txt b/Documentation/git-rev-parse.txt\nindex c817d16..6e4d158 100644\n--- a/Documentation/git-rev-parse.txt\n+++ b/Documentation/git-rev-parse.txt\n@@ -93,6 +93,10 @@ OPTIONS\n \tWhen the current working directory is below the repository\n \tdirectory print \"true\", otherwise \"false\".\n \n+--is-inside-work-tree::\n+\tWhen the current working directory is inside the work tree of the\n+\trepository print \"true\", otherwise \"false\".\n+\n --is-bare-repository::\n \tWhen the repository is bare print \"true\", otherwise \"false\".\n \ndiff --git a/Documentation/git.txt b/Documentation/git.txt\nindex 98860af..4b567d8 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@@ -101,6 +102,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 not be\n+\tused in combination with repositories found automatically in\n+\ta .git directory (i.e. $GIT_DIR is not set).\n+\tThis can also be controlled by setting the GIT_WORK_TREE\n+\tenvironment variable and the core.worktree configuration\n+\tvariable.\n+\n --bare::\n \tSame as --git-dir=`pwd`.\n \n@@ -345,6 +354,13 @@ 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 not be\n+\tused in combination with repositories found automatically in\n+\ta .git directory (i.e. $GIT_DIR is not set).\n+\tThis can also be controlled by the '--work-tree' command line\n+\toption and the core.worktree configuration variable.\n+\n git Commits\n ~~~~~~~~~~~\n 'GIT_AUTHOR_NAME'::\ndiff --git a/builtin-rev-parse.c b/builtin-rev-parse.c\nindex 71d5162..497903a 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-inside-work-tree\")) {\n+\t\t\t\tprintf(\"%s\\n\", is_inside_work_tree() ? \"true\"\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\");\ndiff --git a/cache.h b/cache.h\nindex 8a9d1f3..ae1990a 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -192,6 +192,7 @@ enum object_type {\n };\n \n #define GIT_DIR_ENVIRONMENT \"GIT_DIR\"\n+#define GIT_WORK_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@@ -207,6 +208,7 @@ 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 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);\ndiff --git a/connect.c b/connect.c\nindex 8cbda88..aafa416 100644\n--- a/connect.c\n+++ b/connect.c\n@@ -589,6 +589,7 @@ pid_t git_connect(int fd[2], char *url, const char *prog, int flags)\n \t\t\tunsetenv(ALTERNATE_DB_ENVIRONMENT);\n \t\t\tunsetenv(DB_ENVIRONMENT);\n \t\t\tunsetenv(GIT_DIR_ENVIRONMENT);\n+\t\t\tunsetenv(GIT_WORK_TREE_ENVIRONMENT);\n \t\t\tunsetenv(GRAFT_ENVIRONMENT);\n \t\t\tunsetenv(INDEX_ENVIRONMENT);\n \t\t\texeclp(\"sh\", \"sh\", \"-c\", command, NULL);\ndiff --git a/git.c b/git.c\nindex 29b55a1..05a391b 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@@ -69,6 +69,16 @@ static int handle_options(const char*** argv, int* argc)\n \t\t\thandled++;\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_WORK_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_WORK_TREE_ENVIRONMENT, cmd + 12, 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..7e32de2 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -174,41 +174,93 @@ static int inside_git_dir = -1;\n \n int is_inside_git_dir(void)\n {\n-\tif (inside_git_dir < 0) {\n-\t\tchar buffer[1024];\n-\n-\t\tif (is_bare_repository())\n-\t\t\treturn (inside_git_dir = 1);\n-\t\tif (getcwd(buffer, sizeof(buffer))) {\n-\t\t\tconst char *git_dir = get_git_dir(), *cwd = buffer;\n-\t\t\twhile (*git_dir && *git_dir == *cwd) {\n-\t\t\t\tgit_dir++;\n-\t\t\t\tcwd++;\n-\t\t\t}\n-\t\t\tinside_git_dir = !*git_dir;\n-\t\t} else\n-\t\t\tinside_git_dir = 0;\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+}\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+}\n+\n+static char *gitworktree_config;\n+\n+static int git_setup_config(const char *var, const char *value)\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 \t}\n-\treturn inside_git_dir;\n+\treturn git_default_config(var, value);\n }\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+\tchar worktree[PATH_MAX+1], gitdir[PATH_MAX+1];\n+\tconst char *gitdirenv, *gitworktree;\n+\tint wt_rel_gitdir = 0;\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\tif (PATH_MAX - 40 < strlen(gitdirenv))\n-\t\t\tdie(\"'$%s' too big\", GIT_DIR_ENVIRONMENT);\n-\t\tif (is_git_directory(gitdirenv))\n+\tif (!gitdirenv) {\n+\t\tint len, offset;\n+\n+\t\tif (!getcwd(cwd, sizeof(cwd)-1) || cwd[0] != '/')\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}\n+\n+\tif (PATH_MAX - 40 < strlen(gitdirenv)) {\n+\t\tif (nongit_ok) {\n+\t\t\t*nongit_ok = 1;\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@@ -218,41 +270,90 @@ const char *setup_git_directory_gently(int *nongit_ok)\n \n \tif (!getcwd(cwd, sizeof(cwd)-1) || cwd[0] != '/')\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) || gitdir[0] != '/')\n+\t\tdie(\"Unable to read current working directory\");\n+\tif (chdir(cwd))\n+\t\tdie(\"Cannot come back to cwd\");\n \n-\toffset = len = strlen(cwd);\n-\tfor (;;) {\n-\t\tif (is_git_directory(\".git\"))\n-\t\t\tbreak;\n-\t\tchdir(\"..\");\n-\t\tdo {\n-\t\t\tif (!offset) {\n-\t\t\t\tif (is_git_directory(cwd)) {\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\tsetenv(GIT_DIR_ENVIRONMENT, cwd, 1);\n-\t\t\t\t\tinside_git_dir = 1;\n-\t\t\t\t\treturn NULL;\n-\t\t\t\t}\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/*\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 */\n+\tif (gitdirenv[0] != '/') {\n+\t\tsetenv(GIT_DIR_ENVIRONMENT, gitdir, 1);\n+\t\tgitdirenv = getenv(GIT_DIR_ENVIRONMENT);\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} while (cwd[--offset] != '/');\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+\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) || worktree[0] != '/')\n+\t\tdie(\"Unable to read current working directory\");\n+\tstrcat(worktree, \"/\");\n+\tinside_work_tree = !prefixcmp(cwd, worktree);\n \n-\tif (offset == len)\n+\tif (gitworktree && inside_work_tree && !prefixcmp(worktree, gitdir) &&\n+\t    strcmp(worktree, gitdir)) {\n+\t\tinside_git_dir = 0;\n+\t}\n+\n+\tif (!inside_work_tree) {\n+\t\tif (chdir(cwd))\n+\t\t\tdie(\"Cannot come back to cwd\");\n \t\treturn NULL;\n+\t}\n \n-\t/* Make \"offset\" point to past the '/', and add a '/' at the end */\n-\toffset++;\n-\tcwd[len++] = '/';\n-\tcwd[len] = 0;\n-\tinside_git_dir = !prefixcmp(cwd + offset, \".git/\");\n-\treturn cwd + offset;\n+\tif (!strcmp(cwd, worktree))\n+\t\treturn NULL;\n+\treturn cwd+strlen(worktree);\n }\n \n int git_config_perm(const char *var, const char *value)\ndiff --git a/t/test-lib.sh b/t/test-lib.sh\nindex dee3ad7..b61e1d5 100644\n--- a/t/test-lib.sh\n+++ b/t/test-lib.sh\n@@ -26,6 +26,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.2.1.116.g9f308\n"},{"id":"44126","messageId":"20070606071326.GA32642@moooo.ath.cx","threadId":"8411","inReplyTo":"20070603144846.GF20061@moooo.ath.cx","subject":"[PATCH 6/7 (amend)] extend rev-parse test for --is-inside-work-tree","fromName":"Matthias Lederhofer","fromEmail":"matled@gmx.net","sentAt":"2007-06-06T07:13:26Z","receivedAt":"2007-06-06T07:13:26Z","isPatch":true,"sender":{"key":"matled@gmx.net","avatar":null},"body":"Signed-off-by: Matthias Lederhofer <matled@gmx.net>\n---\nNew: tests that cwd is used as working tree when GIT_DIR is set (and\nGIT_WORK_TREE/core.worktree are unspecified).\n---\n t/t1500-rev-parse.sh |   29 +++++++++++++++++------------\n 1 files changed, 17 insertions(+), 12 deletions(-)\n\ndiff --git a/t/t1500-rev-parse.sh b/t/t1500-rev-parse.sh\nindex 66b0e58..ec49966 100755\n--- a/t/t1500-rev-parse.sh\n+++ b/t/t1500-rev-parse.sh\n@@ -17,30 +17,35 @@ test_rev_parse() {\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 }\n \n-test_rev_parse toplevel false false ''\n+test_rev_parse toplevel false false true ''\n \n cd .git || exit 1\n-test_rev_parse .git/ false true .git/\n+test_rev_parse .git/ false true true .git/\n cd objects || exit 1\n-test_rev_parse .git/objects/ false true .git/objects/\n+test_rev_parse .git/objects/ false true true .git/objects/\n cd ../.. || exit 1\n \n mkdir -p sub/dir || exit 1\n cd sub/dir || exit 1\n-test_rev_parse subdirectory false false sub/dir/\n+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\n+test_rev_parse 'core.bare = true' true false true\n \n git config --unset core.bare\n-test_rev_parse 'core.bare undefined' false\n+test_rev_parse 'core.bare undefined' false false true\n \n mkdir work || exit 1\n cd work || exit 1\n@@ -48,25 +53,25 @@ 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 ''\n+test_rev_parse 'GIT_DIR=../.git, core.bare = false' false false true ''\n \n git config core.bare true\n-test_rev_parse 'GIT_DIR=../.git, core.bare = true' true\n+test_rev_parse 'GIT_DIR=../.git, core.bare = true' true false true ''\n \n git config --unset core.bare\n-test_rev_parse 'GIT_DIR=../.git, core.bare undefined' false false ''\n+test_rev_parse 'GIT_DIR=../.git, core.bare undefined' false false true ''\n \n mv ../.git ../repo.git || exit 1\n export GIT_DIR=../repo.git\n export GIT_CONFIG=\"$GIT_DIR\"/config\n \n git config core.bare false\n-test_rev_parse 'GIT_DIR=../repo.git, core.bare = false' false 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\n+test_rev_parse 'GIT_DIR=../repo.git, core.bare = true' true false true ''\n \n git config --unset core.bare\n-test_rev_parse 'GIT_DIR=../repo.git, core.bare undefined' true\n+test_rev_parse 'GIT_DIR=../repo.git, core.bare undefined' true false true ''\n \n test_done\n-- \n1.5.2.1.116.g9f308\n"},{"id":"44127","messageId":"20070606071425.GB32642@moooo.ath.cx","threadId":"8411","inReplyTo":"20070603144925.GG20061@moooo.ath.cx","subject":"[PATCH 7/7 (amend)] test GIT_WORK_TREE","fromName":"Matthias Lederhofer","fromEmail":"matled@gmx.net","sentAt":"2007-06-06T07:14:25Z","receivedAt":"2007-06-06T07:14:25Z","isPatch":true,"sender":{"key":"matled@gmx.net","avatar":null},"body":"Signed-off-by: Matthias Lederhofer <matled@gmx.net>\n---\nRemove test for fallback work tree with GIT_DIR, this is now in\nt1500-rev-parse.sh.\n---\n t/t1501-worktree.sh |   92 +++++++++++++++++++++++++++++++++++++++++++++++++++\n 1 files changed, 92 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..aadeeab\n--- /dev/null\n+++ b/t/t1501-worktree.sh\n@@ -0,0 +1,92 @@\n+#!/bin/sh\n+\n+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+}\n+\n+mkdir -p work/sub/dir || exit 1\n+mv .git repo.git || exit 1\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+test_rev_parse 'subdirectory' false false true sub/dir/\n+cd ../../.. || exit 1\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+test_rev_parse 'subdirectory' false false true sub/dir/\n+cd ../../.. || exit 1\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+test_rev_parse 'subdirectory' false false true sub/dir/\n+cd ../../.. || exit 1\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+\n+test_done\n-- \n1.5.2.1.116.g9f308\n"},{"id":"44128","messageId":"20070606071656.GC32642@moooo.ath.cx","threadId":"8411","inReplyTo":"20070605164957.GA12358@moooo.ath.cx","subject":"[PATCH (amend)] filter-branch: always export GIT_DIR if it is set","fromName":"Matthias Lederhofer","fromEmail":"matled@gmx.net","sentAt":"2007-06-06T07:16:56Z","receivedAt":"2007-06-06T07:16:56Z","isPatch":true,"sender":{"key":"matled@gmx.net","avatar":null},"body":"Currently filter-branch exports GIT_DIR only if it is an\nrelative path but git-sh-setup might also set GIT_DIR to an\nabsolute path that is not exported yet.  Additionally export\nGIT_WORK_TREE with GIT_DIR to ensure that cwd is used as\nworking tree even for bare repositories.\n\nSigned-off-by: Matthias Lederhofer <matled@gmx.net>\n---\nThe last one was a bit bloated :)\n---\n git-filter-branch.sh |    3 ++-\n 1 files changed, 2 insertions(+), 1 deletions(-)\n\ndiff --git a/git-filter-branch.sh b/git-filter-branch.sh\nindex 0c8a7df..acd52bd 100644\n--- a/git-filter-branch.sh\n+++ b/git-filter-branch.sh\n@@ -315,9 +315,10 @@ case \"$GIT_DIR\" in\n /*)\n \t;;\n *)\n-\texport GIT_DIR=\"$(pwd)/../../$GIT_DIR\"\n+\tGIT_DIR=\"$(pwd)/../../$GIT_DIR\"\n \t;;\n esac\n+export GIT_DIR GIT_WORK_TREE=.\n \n export GIT_INDEX_FILE=\"$(pwd)/../index\"\n git-read-tree # seed the index file\n-- \n1.5.2.1.116.g9f308\n"},{"id":"44193","messageId":"20070606212959.GA8800@moooo.ath.cx","threadId":"8411","inReplyTo":"20070603144401.GA9518@moooo.ath.cx","subject":"[PATCH] setup_git_directory: fix segfault if repository is found in cwd","fromName":"Matthias Lederhofer","fromEmail":"matled@gmx.net","sentAt":"2007-06-06T21:29:59Z","receivedAt":"2007-06-06T21:29:59Z","isPatch":true,"sender":{"key":"matled@gmx.net","avatar":null},"body":"Additionally there was a similar part calling setenv and getenv\nin the same way which missed a check if getenv succeeded.\n\nSigned-off-by: Matthias Lederhofer <matled@gmx.net>\n---\nThere seems to be no easy way to test this case.  We'd have to run the\ntest in a directory which never has a .git directory in any parent.\n---\n setup.c |    5 +++++\n 1 files changed, 5 insertions(+), 0 deletions(-)\n\ndiff --git a/setup.c b/setup.c\nindex 14a4d95..dba8012 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -251,6 +251,9 @@ const char *setup_git_directory_gently(int *nongit_ok)\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@@ -290,6 +293,8 @@ const char *setup_git_directory_gently(int *nongit_ok)\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-- \n1.5.2.1.887.ge344-dirty\n"}]}