summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2010-12-28 11:26:55 -0800
committerJunio C Hamano <gitster@pobox.com>2010-12-28 11:26:55 -0800
commitf3bb8b4b8452f1b7add220e787ef56c737ceff6a (patch)
tree9560624c57a06e0a1c24b7e44a9e8ebb9daaab91
parent73e7b2ef6c62b3ec345b557acb71a8da4798c70d (diff)
parent0ed748134748579a13cf27e1e8b3e55371bcd9dc (diff)
downloadgit-f3bb8b4b8452f1b7add220e787ef56c737ceff6a.tar.gz
Merge branch 'nd/setup'
* nd/setup: (47 commits) setup_work_tree: adjust relative $GIT_WORK_TREE after moving cwd git.txt: correct where --work-tree path is relative to Revert "Documentation: always respect core.worktree if set" t0001: test git init when run via an alias Remove all logic from get_git_work_tree() setup: rework setup_explicit_git_dir() setup: clean up setup_discovered_git_dir() t1020-subdirectory: test alias expansion in a subdirectory setup: clean up setup_bare_git_dir() setup: limit get_git_work_tree()'s to explicit setup case only Use git_config_early() instead of git_config() during repo setup Add git_config_early() git-rev-parse.txt: clarify --git-dir t1510: setup case #31 t1510: setup case #30 t1510: setup case #29 t1510: setup case #28 t1510: setup case #27 t1510: setup case #26 t1510: setup case #25 ...
-rw-r--r--.gitignore1
-rw-r--r--Documentation/config.txt23
-rw-r--r--Documentation/git-rev-parse.txt7
-rw-r--r--Documentation/git.txt2
-rw-r--r--Makefile1
-rw-r--r--builtin/init-db.c13
-rw-r--r--cache.h2
-rw-r--r--config.c19
-rw-r--r--environment.c26
-rw-r--r--git.c4
-rw-r--r--setup.c238
-rwxr-xr-xt/t0001-init.sh56
-rwxr-xr-xt/t1020-subdirectory.sh8
-rwxr-xr-xt/t1501-worktree.sh7
-rwxr-xr-xt/t1510-repo-setup.sh4532
-rw-r--r--test-subprocess.c21
-rw-r--r--trace.c42
17 files changed, 4868 insertions, 134 deletions
diff --git a/.gitignore b/.gitignore
index 87b833c9d8..3dd6ef7d25 100644
--- a/.gitignore
+++ b/.gitignore
@@ -177,6 +177,7 @@
/test-sha1
/test-sigchain
/test-string-pool
+/test-subprocess
/test-svn-fe
/test-treap
/common-cmds.h
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 54597f1897..a8759cff80 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -317,24 +317,17 @@ false), while all other repositories are assumed to be bare (bare
= true).
core.worktree::
- Set the path to the root of the work tree.
+ Set the path to the working tree. The value will not be
+ used in combination with repositories found automatically in
+ a .git directory (i.e. $GIT_DIR is not set).
This can be overridden by the GIT_WORK_TREE environment
variable and the '--work-tree' command line option. It can be
- an absolute path or a relative path to the .git directory,
- either specified by --git-dir or GIT_DIR, or automatically
- discovered.
- If --git-dir or GIT_DIR are specified but none of
+ an absolute path or relative path to the directory specified by
+ --git-dir or GIT_DIR.
+ Note: If --git-dir or GIT_DIR are specified but none of
--work-tree, GIT_WORK_TREE and core.worktree is specified,
- the current working directory is regarded as the root of the
- work tree.
-+
-Note that this variable is honored even when set in a configuration
-file in a ".git" subdirectory of a directory, and its value differs
-from the latter directory (e.g. "/path/to/.git/config" has
-core.worktree set to "/different/path"), which is most likely a
-misconfiguration. Running git commands in "/path/to" directory will
-still use "/different/path" as the root of the work tree and can cause
-great confusion to the users.
+ the current working directory is regarded as the top directory
+ of your working tree.
core.logAllRefUpdates::
Enable the reflog. Updates to a ref <ref> is logged to the file
diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt
index 4a27643c1e..ff23cb0219 100644
--- a/Documentation/git-rev-parse.txt
+++ b/Documentation/git-rev-parse.txt
@@ -136,7 +136,12 @@ appending `/{asterisk}`.
directory (typically a sequence of "../", or an empty string).
--git-dir::
- Show `$GIT_DIR` if defined else show the path to the .git directory.
+ Show `$GIT_DIR` if defined. Otherwise show the path to
+ the .git directory, relative to the current directory.
++
+If `$GIT_DIR` is not defined and the current directory
+is not detected to lie in a git repository or work tree
+print a message to stderr and exit with nonzero status.
--is-inside-git-dir::
When the current working directory is below the repository
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 012837145e..72e98aaa0f 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -296,7 +296,7 @@ help ...`.
This can also be controlled by setting the GIT_WORK_TREE
environment variable and the core.worktree configuration
variable. It can be an absolute path or relative path to
- the directory specified by --git-dir or GIT_DIR.
+ current working directory.
Note: If --git-dir or GIT_DIR are specified but none of
--work-tree, GIT_WORK_TREE and core.worktree is specified,
the current working directory is regarded as the top directory
diff --git a/Makefile b/Makefile
index ff35154375..775ee838c3 100644
--- a/Makefile
+++ b/Makefile
@@ -431,6 +431,7 @@ TEST_PROGRAMS_NEED_X += test-run-command
TEST_PROGRAMS_NEED_X += test-sha1
TEST_PROGRAMS_NEED_X += test-sigchain
TEST_PROGRAMS_NEED_X += test-string-pool
+TEST_PROGRAMS_NEED_X += test-subprocess
TEST_PROGRAMS_NEED_X += test-svn-fe
TEST_PROGRAMS_NEED_X += test-treap
TEST_PROGRAMS_NEED_X += test-index-version
diff --git a/builtin/init-db.c b/builtin/init-db.c
index 9d4886c716..e3af9eaa87 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -414,6 +414,7 @@ static const char *const init_db_usage[] = {
int cmd_init_db(int argc, const char **argv, const char *prefix)
{
const char *git_dir;
+ const char *work_tree;
const char *template_dir = NULL;
unsigned int flags = 0;
const struct option init_db_options[] = {
@@ -480,8 +481,8 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
* without --bare. Catch the error early.
*/
git_dir = getenv(GIT_DIR_ENVIRONMENT);
- if ((!git_dir || is_bare_repository_cfg == 1)
- && getenv(GIT_WORK_TREE_ENVIRONMENT))
+ work_tree = getenv(GIT_WORK_TREE_ENVIRONMENT);
+ if ((!git_dir || is_bare_repository_cfg == 1) && work_tree)
die("%s (or --work-tree=<directory>) not allowed without "
"specifying %s (or --git-dir=<directory>)",
GIT_WORK_TREE_ENVIRONMENT,
@@ -510,10 +511,18 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
if (!getcwd(git_work_tree_cfg, PATH_MAX))
die_errno ("Cannot access current working directory");
}
+ if (work_tree)
+ set_git_work_tree(make_absolute_path(work_tree));
+ else
+ set_git_work_tree(git_work_tree_cfg);
if (access(get_git_work_tree(), X_OK))
die_errno ("Cannot access work tree '%s'",
get_git_work_tree());
}
+ else {
+ if (work_tree)
+ set_git_work_tree(make_absolute_path(work_tree));
+ }
set_git_dir(make_absolute_path(git_dir));
diff --git a/cache.h b/cache.h
index 32170c293d..d83d68c859 100644
--- a/cache.h
+++ b/cache.h
@@ -987,6 +987,7 @@ extern int git_config_parse_parameter(const char *text);
extern int git_config_parse_environment(void);
extern int git_config_from_parameters(config_fn_t fn, void *data);
extern int git_config(config_fn_t fn, void *);
+extern int git_config_early(config_fn_t fn, void *, const char *repo_config);
extern int git_parse_ulong(const char *, unsigned long *);
extern int git_config_int(const char *, const char *);
extern unsigned long git_config_ulong(const char *, const char *);
@@ -1066,6 +1067,7 @@ __attribute__((format (printf, 1, 2)))
extern void trace_printf(const char *format, ...);
__attribute__((format (printf, 2, 3)))
extern void trace_argv_printf(const char **argv, const char *format, ...);
+extern void trace_repo_setup(const char *prefix);
/* convert.c */
/* returns 1 if *dst was used */
diff --git a/config.c b/config.c
index d73b090b6a..625e051876 100644
--- a/config.c
+++ b/config.c
@@ -852,10 +852,9 @@ int git_config_from_parameters(config_fn_t fn, void *data)
return 0;
}
-int git_config(config_fn_t fn, void *data)
+int git_config_early(config_fn_t fn, void *data, const char *repo_config)
{
int ret = 0, found = 0;
- char *repo_config = NULL;
const char *home = NULL;
/* Setting $GIT_CONFIG makes git read _only_ the given config file. */
@@ -877,12 +876,10 @@ int git_config(config_fn_t fn, void *data)
free(user_config);
}
- repo_config = git_pathdup("config");
- if (!access(repo_config, R_OK)) {
+ if (repo_config && !access(repo_config, R_OK)) {
ret += git_config_from_file(fn, repo_config, data);
found += 1;
}
- free(repo_config);
ret += git_config_from_parameters(fn, data);
if (config_parameters)
@@ -891,6 +888,18 @@ int git_config(config_fn_t fn, void *data)
return ret == 0 ? found : ret;
}
+int git_config(config_fn_t fn, void *data)
+{
+ char *repo_config = NULL;
+ int ret;
+
+ repo_config = git_pathdup("config");
+ ret = git_config_early(fn, data, repo_config);
+ if (repo_config)
+ free(repo_config);
+ return ret;
+}
+
/*
* Find all the stuff for git_config_set() below.
*/
diff --git a/environment.c b/environment.c
index c79f2a9b56..9564475f42 100644
--- a/environment.c
+++ b/environment.c
@@ -139,30 +139,20 @@ static int git_work_tree_initialized;
*/
void set_git_work_tree(const char *new_work_tree)
{
- if (is_bare_repository_cfg >= 0)
- die("cannot set work tree after initialization");
+ if (git_work_tree_initialized) {
+ new_work_tree = make_absolute_path(new_work_tree);
+ if (strcmp(new_work_tree, work_tree))
+ die("internal error: work tree has already been set\n"
+ "Current worktree: %s\nNew worktree: %s",
+ work_tree, new_work_tree);
+ return;
+ }
git_work_tree_initialized = 1;
- free(work_tree);
work_tree = xstrdup(make_absolute_path(new_work_tree));
- is_bare_repository_cfg = 0;
}
const char *get_git_work_tree(void)
{
- if (!git_work_tree_initialized) {
- work_tree = getenv(GIT_WORK_TREE_ENVIRONMENT);
- /* core.bare = true overrides implicit and config work tree */
- if (!work_tree && is_bare_repository_cfg < 1) {
- work_tree = git_work_tree_cfg;
- /* make_absolute_path also normalizes the path */
- if (work_tree && !is_absolute_path(work_tree))
- work_tree = xstrdup(make_absolute_path(git_path("%s", work_tree)));
- } else if (work_tree)
- work_tree = xstrdup(make_absolute_path(work_tree));
- git_work_tree_initialized = 1;
- if (work_tree)
- is_bare_repository_cfg = 0;
- }
return work_tree;
}
diff --git a/git.c b/git.c
index d532576cdf..68334f6a31 100644
--- a/git.c
+++ b/git.c
@@ -275,6 +275,10 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
use_pager = check_pager_config(p->cmd);
if (use_pager == -1 && p->option & USE_PAGER)
use_pager = 1;
+
+ if ((p->option & (RUN_SETUP | RUN_SETUP_GENTLY)) &&
+ startup_info->have_repository) /* get_git_dir() may set up repo, avoid that */
+ trace_repo_setup(prefix);
}
commit_pager_choice();
diff --git a/setup.c b/setup.c
index 91887a40b7..3d732697af 100644
--- a/setup.c
+++ b/setup.c
@@ -208,24 +208,6 @@ int is_inside_work_tree(void)
return inside_work_tree;
}
-/*
- * set_work_tree() is only ever called if you set GIT_DIR explicitly.
- * The old behaviour (which we retain here) is to set the work tree root
- * to the cwd, unless overridden by the config, the command line, or
- * GIT_WORK_TREE.
- */
-static const char *set_work_tree(const char *dir)
-{
- char buffer[PATH_MAX + 1];
-
- if (!getcwd(buffer, sizeof(buffer)))
- die ("Could not get the current working directory");
- git_work_tree_cfg = xstrdup(buffer);
- inside_work_tree = 1;
-
- return NULL;
-}
-
void setup_work_tree(void)
{
const char *work_tree, *git_dir;
@@ -239,13 +221,33 @@ void setup_work_tree(void)
git_dir = make_absolute_path(git_dir);
if (!work_tree || chdir(work_tree))
die("This operation must be run in a work tree");
+
+ /*
+ * Make sure subsequent git processes find correct worktree
+ * if $GIT_WORK_TREE is set relative
+ */
+ if (getenv(GIT_WORK_TREE_ENVIRONMENT))
+ setenv(GIT_WORK_TREE_ENVIRONMENT, ".", 1);
+
set_git_dir(make_relative_path(git_dir, work_tree));
initialized = 1;
}
-static int check_repository_format_gently(int *nongit_ok)
+static int check_repository_format_gently(const char *gitdir, int *nongit_ok)
{
- git_config(check_repository_format_version, NULL);
+ char repo_config[PATH_MAX+1];
+
+ /*
+ * git_config() can't be used here because it calls git_pathdup()
+ * to get $GIT_CONFIG/config. That call will make setup_git_env()
+ * set git_dir to ".git".
+ *
+ * We are in gitdir setup, no git dir has been found useable yet.
+ * Use a gentler version of git_config() to check if this repo
+ * is a good one.
+ */
+ snprintf(repo_config, PATH_MAX, "%s/config", gitdir);
+ git_config_early(check_repository_format_version, NULL, repo_config);
if (GIT_REPO_VERSION < repository_format_version) {
if (!nongit_ok)
die ("Expected git repo version <= %d, found %d",
@@ -314,64 +316,115 @@ const char *read_gitfile_gently(const char *path)
}
static const char *setup_explicit_git_dir(const char *gitdirenv,
- const char *work_tree_env, int *nongit_ok)
+ char *cwd, int len,
+ int *nongit_ok)
{
- static char buffer[1024 + 1];
- const char *retval;
+ const char *work_tree_env = getenv(GIT_WORK_TREE_ENVIRONMENT);
+ const char *worktree;
+ char *gitfile;
if (PATH_MAX - 40 < strlen(gitdirenv))
die("'$%s' too big", GIT_DIR_ENVIRONMENT);
+
+ gitfile = (char*)read_gitfile_gently(gitdirenv);
+ if (gitfile) {
+ gitfile = xstrdup(gitfile);
+ gitdirenv = gitfile;
+ }
+
if (!is_git_directory(gitdirenv)) {
if (nongit_ok) {
*nongit_ok = 1;
+ free(gitfile);
return NULL;
}
die("Not a git repository: '%s'", gitdirenv);
}
- if (!work_tree_env) {
- retval = set_work_tree(gitdirenv);
- /* config may override worktree */
- if (check_repository_format_gently(nongit_ok))
- return NULL;
- return retval;
+
+ if (check_repository_format_gently(gitdirenv, nongit_ok)) {
+ free(gitfile);
+ return NULL;
}
- if (check_repository_format_gently(nongit_ok))
+
+ /* #3, #7, #11, #15, #19, #23, #27, #31 (see t1510) */
+ if (work_tree_env)
+ set_git_work_tree(work_tree_env);
+ else if (is_bare_repository_cfg > 0) {
+ if (git_work_tree_cfg) /* #22.2, #30 */
+ die("core.bare and core.worktree do not make sense");
+
+ /* #18, #26 */
+ set_git_dir(gitdirenv);
+ free(gitfile);
return NULL;
- retval = get_relative_cwd(buffer, sizeof(buffer) - 1,
- get_git_work_tree());
- if (!retval || !*retval)
+ }
+ else if (git_work_tree_cfg) { /* #6, #14 */
+ if (is_absolute_path(git_work_tree_cfg))
+ set_git_work_tree(git_work_tree_cfg);
+ else {
+ char core_worktree[PATH_MAX];
+ if (chdir(gitdirenv))
+ die_errno("Could not chdir to '%s'", gitdirenv);
+ if (chdir(git_work_tree_cfg))
+ die_errno("Could not chdir to '%s'", git_work_tree_cfg);
+ if (!getcwd(core_worktree, PATH_MAX))
+ die_errno("Could not get directory '%s'", git_work_tree_cfg);
+ if (chdir(cwd))
+ die_errno("Could not come back to cwd");
+ set_git_work_tree(core_worktree);
+ }
+ }
+ else /* #2, #10 */
+ set_git_work_tree(".");
+
+ /* set_git_work_tree() must have been called by now */
+ worktree = get_git_work_tree();
+
+ /* both get_git_work_tree() and cwd are already normalized */
+ if (!strcmp(cwd, worktree)) { /* cwd == worktree */
+ set_git_dir(gitdirenv);
+ free(gitfile);
return NULL;
- set_git_dir(make_absolute_path(gitdirenv));
- if (chdir(work_tree_env) < 0)
- die_errno ("Could not chdir to '%s'", work_tree_env);
- strcat(buffer, "/");
- return retval;
-}
+ }
-static int cwd_contains_git_dir(const char **gitfile_dirp)
-{
- const char *gitfile_dir = read_gitfile_gently(DEFAULT_GIT_DIR_ENVIRONMENT);
- *gitfile_dirp = gitfile_dir;
- if (gitfile_dir) {
- if (set_git_dir(gitfile_dir))
- die("Repository setup failed");
- return 1;
+ if (!prefixcmp(cwd, worktree) &&
+ cwd[strlen(worktree)] == '/') { /* cwd inside worktree */
+ set_git_dir(make_absolute_path(gitdirenv));
+ if (chdir(worktree))
+ die_errno("Could not chdir to '%s'", worktree);
+ cwd[len++] = '/';
+ cwd[len] = '\0';
+ free(gitfile);
+ return cwd + strlen(worktree) + 1;
}
- return is_git_directory(DEFAULT_GIT_DIR_ENVIRONMENT);
+
+ /* cwd outside worktree */
+ set_git_dir(gitdirenv);
+ free(gitfile);
+ return NULL;
}
-static const char *setup_discovered_git_dir(const char *work_tree_env,
- int offset, int len, char *cwd, int *nongit_ok)
+static const char *setup_discovered_git_dir(const char *gitdir,
+ char *cwd, int offset, int len,
+ int *nongit_ok)
{
- int root_len;
+ if (check_repository_format_gently(gitdir, nongit_ok))
+ return NULL;
- inside_git_dir = 0;
- if (!work_tree_env)
- inside_work_tree = 1;
- root_len = offset_1st_component(cwd);
- git_work_tree_cfg = xstrndup(cwd, offset > root_len ? offset : root_len);
- if (check_repository_format_gently(nongit_ok))
+ /* #16.2, #17.2, #20.2, #21.2, #24, #25, #28, #29 (see t1510) */
+ if (is_bare_repository_cfg > 0) {
+ set_git_dir(offset == len ? gitdir : make_absolute_path(gitdir));
+ if (chdir(cwd))
+ die_errno("Could not come back to cwd");
return NULL;
+ }
+
+ /* #0, #1, #5, #8, #9, #12, #13 */
+ set_git_work_tree(".");
+ if (strcmp(gitdir, DEFAULT_GIT_DIR_ENVIRONMENT))
+ set_git_dir(gitdir);
+ inside_git_dir = 0;
+ inside_work_tree = 1;
if (offset == len)
return NULL;
@@ -382,23 +435,25 @@ static const char *setup_discovered_git_dir(const char *work_tree_env,
return cwd + offset;
}
-static const char *setup_bare_git_dir(const char *work_tree_env,
- int offset, int len, char *cwd, int *nongit_ok)
+/* #16.1, #17.1, #20.1, #21.1, #22.1 (see t1510) */
+static const char *setup_bare_git_dir(char *cwd, int offset, int len, int *nongit_ok)
{
int root_len;
+ if (check_repository_format_gently(".", nongit_ok))
+ return NULL;
+
inside_git_dir = 1;
- if (!work_tree_env)
- inside_work_tree = 0;
+ inside_work_tree = 0;
if (offset != len) {
if (chdir(cwd))
die_errno("Cannot come back to cwd");
root_len = offset_1st_component(cwd);
cwd[offset > root_len ? offset : root_len] = '\0';
set_git_dir(cwd);
- } else
+ }
+ else
set_git_dir(".");
- check_repository_format_gently(nongit_ok);
return NULL;
}
@@ -428,11 +483,10 @@ static dev_t get_device_or_die(const char *path, const char *prefix)
*/
static const char *setup_git_directory_gently_1(int *nongit_ok)
{
- const char *work_tree_env = getenv(GIT_WORK_TREE_ENVIRONMENT);
const char *env_ceiling_dirs = getenv(CEILING_DIRECTORIES_ENVIRONMENT);
static char cwd[PATH_MAX+1];
- const char *gitdirenv;
- const char *gitfile_dir;
+ const char *gitdirenv, *ret;
+ char *gitfile;
int len, offset, ceil_offset;
dev_t current_device = 0;
int one_filesystem = 1;
@@ -445,6 +499,10 @@ static const char *setup_git_directory_gently_1(int *nongit_ok)
if (nongit_ok)
*nongit_ok = 0;
+ if (!getcwd(cwd, sizeof(cwd)-1))
+ die_errno("Unable to read current working directory");
+ offset = len = strlen(cwd);
+
/*
* If GIT_DIR is set explicitly, we're not going
* to do any discovery, but we still do repository
@@ -452,10 +510,7 @@ static const char *setup_git_directory_gently_1(int *nongit_ok)
*/
gitdirenv = getenv(GIT_DIR_ENVIRONMENT);
if (gitdirenv)
- return setup_explicit_git_dir(gitdirenv, work_tree_env, nongit_ok);
-
- if (!getcwd(cwd, sizeof(cwd)-1))
- die_errno("Unable to read current working directory");
+ return setup_explicit_git_dir(gitdirenv, cwd, len, nongit_ok);
ceil_offset = longest_ancestor_length(cwd, env_ceiling_dirs);
if (ceil_offset < 0 && has_dos_drive_prefix(cwd))
@@ -472,17 +527,30 @@ static const char *setup_git_directory_gently_1(int *nongit_ok)
* - ../../.git/
* etc.
*/
- offset = len = strlen(cwd);
one_filesystem = !git_env_bool("GIT_DISCOVERY_ACROSS_FILESYSTEM", 0);
if (one_filesystem)
current_device = get_device_or_die(".", NULL);
for (;;) {
- if (cwd_contains_git_dir(&gitfile_dir))
- return setup_discovered_git_dir(work_tree_env, offset,
- len, cwd, nongit_ok);
+ gitfile = (char*)read_gitfile_gently(DEFAULT_GIT_DIR_ENVIRONMENT);
+ if (gitfile)
+ gitdirenv = gitfile = xstrdup(gitfile);
+ else {
+ if (is_git_directory(DEFAULT_GIT_DIR_ENVIRONMENT))
+ gitdirenv = DEFAULT_GIT_DIR_ENVIRONMENT;
+ }
+
+ if (gitdirenv) {
+ ret = setup_discovered_git_dir(gitdirenv,
+ cwd, offset, len,
+ nongit_ok);
+ free(gitfile);
+ return ret;
+ }
+ free(gitfile);
+
if (is_git_directory("."))
- return setup_bare_git_dir(work_tree_env, offset,
- len, cwd, nongit_ok);
+ return setup_bare_git_dir(cwd, offset, len, nongit_ok);
+
while (--offset > ceil_offset && cwd[offset] != '/');
if (offset <= ceil_offset)
return setup_nongit(cwd, nongit_ok);
@@ -592,7 +660,7 @@ int check_repository_format_version(const char *var, const char *value, void *cb
int check_repository_format(void)
{
- return check_repository_format_gently(NULL);
+ return check_repository_format_gently(get_git_dir(), NULL);
}
/*
@@ -603,19 +671,5 @@ int check_repository_format(void)
*/
const char *setup_git_directory(void)
{
- const char *retval = setup_git_directory_gently(NULL);
-
- /* If the work tree is not the default one, recompute prefix */
- if (inside_work_tree < 0) {
- static char buffer[PATH_MAX + 1];
- char *rel;
- if (retval && chdir(retval))
- die_errno ("Could not jump back into original cwd");
- rel = get_relative_cwd(buffer, PATH_MAX, get_git_work_tree());
- if (rel && *rel && chdir(get_git_work_tree()))
- die_errno ("Could not jump to working directory");
- return rel && *rel ? strcat(rel, "/") : NULL;
- }
-
- return retval;
+ return setup_git_directory_gently(NULL);
}
diff --git a/t/t0001-init.sh b/t/t0001-init.sh
index d44194c35f..af8b9c52a9 100755
--- a/t/t0001-init.sh
+++ b/t/t0001-init.sh
@@ -33,6 +33,62 @@ test_expect_success 'plain' '
check_config plain/.git false unset
'
+test_expect_success 'plain nested in bare' '
+ (
+ unset GIT_DIR GIT_WORK_TREE &&
+ git init --bare bare-ancestor.git &&
+ cd bare-ancestor.git &&
+ mkdir plain-nested &&
+ cd plain-nested &&
+ git init
+ ) &&
+ check_config bare-ancestor.git/plain-nested/.git false unset
+'
+
+test_expect_success 'plain through aliased command, outside any git repo' '
+ (
+ unset GIT_DIR GIT_WORK_TREE GIT_CONFIG_NOGLOBAL &&
+ HOME=$(pwd)/alias-config &&
+ export HOME &&
+ mkdir alias-config &&
+ echo "[alias] aliasedinit = init" >alias-config/.gitconfig &&
+
+ GIT_CEILING_DIRECTORIES=$(pwd) &&
+ export GIT_CEILING_DIRECTORIES &&
+
+ mkdir plain-aliased &&
+ cd plain-aliased &&
+ git aliasedinit
+ ) &&
+ check_config plain-aliased/.git false unset
+'
+
+test_expect_failure 'plain nested through aliased command' '
+ (
+ unset GIT_DIR GIT_WORK_TREE &&
+ git init plain-ancestor-aliased &&
+ cd plain-ancestor-aliased &&
+ echo "[alias] aliasedinit = init" >>.git/config &&
+ mkdir plain-nested &&
+ cd plain-nested &&
+ git aliasedinit
+ ) &&
+ check_config plain-ancestor-aliased/plain-nested/.git false unset
+'
+
+test_expect_failure 'plain nested in bare through aliased command' '
+ (
+ unset GIT_DIR GIT_WORK_TREE &&
+ git init --bare bare-ancestor-aliased.git &&
+ cd bare-ancestor-aliased.git &&
+ echo "[alias] aliasedinit = init" >>config &&
+ mkdir plain-nested &&
+ cd plain-nested &&
+ git aliasedinit
+ ) &&
+ check_config bare-ancestor-aliased.git/plain-nested/.git false unset
+'
+
test_expect_success 'plain with GIT_WORK_TREE' '
if (
sane_unset GIT_DIR &&
diff --git a/t/t1020-subdirectory.sh b/t/t1020-subdirectory.sh
index a3ac33801a..1fd187c5eb 100755
--- a/t/t1020-subdirectory.sh
+++ b/t/t1020-subdirectory.sh
@@ -110,6 +110,14 @@ test_expect_success 'read-tree' '
)
'
+test_expect_success 'alias expansion' '
+ (
+ git config alias.ss status &&
+ cd dir &&
+ git status &&
+ git ss
+ )
+'
test_expect_success 'no file/rev ambiguity check inside .git' '
git commit -a -m 1 &&
(
diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh
index 2c8f01f668..f072a8ed48 100755
--- a/t/t1501-worktree.sh
+++ b/t/t1501-worktree.sh
@@ -340,4 +340,11 @@ test_expect_success 'make_relative_path handles double slashes in GIT_DIR' '
git --git-dir="$(pwd)//repo.git" --work-tree="$(pwd)" add dummy_file
'
+test_expect_success 'relative $GIT_WORK_TREE and git subprocesses' '
+ GIT_DIR=repo.git GIT_WORK_TREE=repo.git/work \
+ test-subprocess --setup-work-tree rev-parse --show-toplevel >actual &&
+ echo "$TRASH_DIRECTORY/repo.git/work" >expected &&
+ test_cmp expected actual
+'
+
test_done
diff --git a/t/t1510-repo-setup.sh b/t/t1510-repo-setup.sh
new file mode 100755
index 0000000000..500ffafc22
--- /dev/null
+++ b/t/t1510-repo-setup.sh
@@ -0,0 +1,4532 @@
+#!/bin/sh
+
+test_description='Tests of cwd/prefix/worktree/gitdir setup in all cases'
+
+. ./test-lib.sh
+
+#
+# A few rules for repo setup:
+#
+# 1. GIT_DIR is relative to user's cwd. --git-dir is equivalent to
+# GIT_DIR.
+#
+# 2. .git file is relative to parent directory. .git file is basically
+# symlink in disguise. The directory where .git file points to will
+# become new git_dir.
+#
+# 3. core.worktree is relative to git_dir.
+#
+# 4. GIT_WORK_TREE is relative to user's cwd. --work-tree is
+# equivalent to GIT_WORK_TREE.
+#
+# 5. GIT_WORK_TREE/core.worktree is only effective if GIT_DIR is set
+# Uneffective worktree settings should be warned.
+#
+# 6. Effective GIT_WORK_TREE overrides core.worktree and core.bare
+#
+# 7. Effective core.worktree conflicts with core.bare
+#
+# 8. If GIT_DIR is set but neither worktree nor bare setting is given,
+# original cwd becomes worktree.
+#
+# 9. If .git discovery is done inside a repo, the repo becomes a bare
+# repo. .git discovery is performed if GIT_DIR is not set.
+#
+# 10. If no worktree is available, cwd remains unchanged, prefix is
+# NULL.
+#
+# 11. When user's cwd is outside worktree, cwd remains unchanged,
+# prefix is NULL.
+#
+
+test_repo() {
+ (
+ cd "$1" &&
+ if test -n "$2"; then GIT_DIR="$2" && export GIT_DIR; fi &&
+ if test -n "$3"; then GIT_WORK_TREE="$3" && export GIT_WORK_TREE; fi &&
+ rm -f trace &&
+ GIT_TRACE="`pwd`/trace" git symbolic-ref HEAD >/dev/null &&
+ grep '^setup: ' trace >result &&
+ test_cmp expected result
+ )
+}
+
+# Bit 0 = GIT_WORK_TREE
+# Bit 1 = GIT_DIR
+# Bit 2 = core.worktree
+# Bit 3 = .git is a file
+# Bit 4 = bare repo
+# Case# = encoding of the above 5 bits
+
+#
+# Case #0
+#
+############################################################
+#
+# Input:
+#
+# - GIT_WORK_TREE is not set
+# - GIT_DIR is not set
+# - core.worktree is not set
+# - .git is a directory
+# - core.bare is not set, cwd is outside .git
+#
+# Output:
+#
+# - worktree is .git's parent directory
+# - cwd is at worktree root dir
+# - prefix is calculated
+# - git_dir is set to ".git"
+# - cwd can't be outside worktree
+
+test_expect_success '#0: setup' '
+ unset GIT_DIR GIT_WORK_TREE &&
+ mkdir 0 0/sub &&
+ cd 0 && git init && cd ..
+'
+
+test_expect_success '#0: at root' '
+ cat >0/expected <<EOF &&
+setup: git_dir: .git
+setup: worktree: $TRASH_DIRECTORY/0
+setup: cwd: $TRASH_DIRECTORY/0
+setup: prefix: (null)
+EOF
+ test_repo 0
+'
+
+test_expect_success '#0: in subdir' '
+ cat >0/sub/expected <<EOF &&
+setup: git_dir: .git
+setup: worktree: $TRASH_DIRECTORY/0
+setup: cwd: $TRASH_DIRECTORY/0
+setup: prefix: sub/
+EOF
+ test_repo 0/sub
+'
+
+#
+# case #1
+#
+############################################################
+#
+# Input:
+#
+# - GIT_WORK_TREE is set
+# - GIT_DIR is not set
+# - core.worktree is not set
+# - .git is a directory
+# - core.bare is not set, cwd is outside .git
+#
+# Output:
+#
+# GIT_WORK_TREE is ignored -> #0
+
+test_expect_success '#1: setup' '
+ unset GIT_DIR GIT_WORK_TREE &&
+ mkdir 1 1/sub 1.wt 1.wt/sub 1/wt 1/wt/sub &&
+ cd 1 &&
+ git init &&
+ GIT_WORK_TREE=non-existent &&
+ export GIT_WORK_TREE &&
+ cd ..
+'
+
+test_expect_success '#1: at root' '
+ cat >1/expected <<EOF &&
+setup: git_dir: .git
+setup: worktree: $TRASH_DIRECTORY/1
+setup: cwd: $TRASH_DIRECTORY/1
+setup: prefix: (null)
+EOF
+ test_repo 1
+'
+
+test_expect_success '#1: in subdir' '
+ cat >1/sub/expected <<EOF &&
+setup: git_dir: .git
+setup: worktree: $TRASH_DIRECTORY/1
+setup: cwd: $TRASH_DIRECTORY/1
+setup: prefix: sub/
+EOF
+ test_repo 1/sub
+'
+
+#
+# case #2
+#
+############################################################
+#
+# Input:
+#
+# - GIT_WORK_TREE is not set
+# - GIT_DIR is set
+# - core.worktree is not set
+# - .git is a directory
+# - core.bare is not set, cwd is outside .git
+#
+# Output:
+#
+# - worktree is at original cwd
+# - cwd is unchanged
+# - prefix is NULL
+# - git_dir is set to $GIT_DIR
+# - cwd can't be outside worktree
+
+test_expect_success '#2: setup' '
+ unset GIT_DIR GIT_WORK_TREE &&
+ mkdir 2 2/sub &&
+ cd 2 && git init && cd ..
+'
+
+test_expect_success '#2: at root' '
+ cat >2/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/2/.git
+setup: worktree: $TRASH_DIRECTORY/2
+setup: cwd: $TRASH_DIRECTORY/2
+setup: prefix: (null)
+EOF
+ test_repo 2 "$TRASH_DIRECTORY/2/.git"
+'
+
+test_expect_success '#2: in subdir' '
+ cat >2/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/2/.git
+setup: worktree: $TRASH_DIRECTORY/2/sub
+setup: cwd: $TRASH_DIRECTORY/2/sub
+setup: prefix: (null)
+EOF
+ test_repo 2/sub "$TRASH_DIRECTORY/2/.git"
+'
+
+test_expect_success '#2: relative GIT_DIR at root' '
+ cat >2/expected <<EOF &&
+setup: git_dir: .git
+setup: worktree: $TRASH_DIRECTORY/2
+setup: cwd: $TRASH_DIRECTORY/2
+setup: prefix: (null)
+EOF
+ test_repo 2 .git
+'
+
+test_expect_success '#2: relative GIT_DIR in subdir' '
+ cat >2/sub/expected <<EOF &&
+setup: git_dir: ../.git
+setup: worktree: $TRASH_DIRECTORY/2/sub
+setup: cwd: $TRASH_DIRECTORY/2/sub
+setup: prefix: (null)
+EOF
+ test_repo 2/sub ../.git
+'
+
+#
+# case #3
+#
+############################################################
+#
+# Input:
+#
+# - GIT_WORK_TREE is set
+# - GIT_DIR is set
+# - core.worktree is not set
+# - .git is a directory
+# - core.bare is not set, cwd is outside .git
+#
+# Output:
+#
+# - worktree is set to $GIT_WORK_TREE
+# - cwd is at worktree root
+# - prefix is calculated
+# - git_dir is set to $GIT_DIR
+# - cwd can be outside worktree
+
+test_expect_success '#3: setup' '
+ unset GIT_DIR GIT_WORK_TREE &&
+ mkdir 3 3/sub 3/sub/sub 3.wt 3.wt/sub 3/wt 3/wt/sub &&
+ cd 3 && git init && cd ..
+'
+
+test_expect_success '#3: GIT_DIR(rel), GIT_WORK_TREE=root at root' '
+ cat >3/expected <<EOF &&
+setup: git_dir: .git
+setup: worktree: $TRASH_DIRECTORY/3
+setup: cwd: $TRASH_DIRECTORY/3
+setup: prefix: (null)
+EOF
+ test_repo 3 .git "$TRASH_DIRECTORY/3"
+'
+
+test_expect_success '#3: GIT_DIR(rel), GIT_WORK_TREE=root(rel) at root' '
+ cat >3/expected <<EOF &&
+setup: git_dir: .git
+setup: worktree: $TRASH_DIRECTORY/3
+setup: cwd: $TRASH_DIRECTORY/3
+setup: prefix: (null)
+EOF
+ test_repo 3 .git .
+'
+
+test_expect_success '#3: GIT_DIR, GIT_WORK_TREE=root at root' '
+ cat >3/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/3/.git
+setup: worktree: $TRASH_DIRECTORY/3
+setup: cwd: $TRASH_DIRECTORY/3
+setup: prefix: (null)
+EOF
+ test_repo 3 "$TRASH_DIRECTORY/3/.git" "$TRASH_DIRECTORY/3"
+'
+
+test_expect_success '#3: GIT_DIR, GIT_WORK_TREE=root(rel) at root' '
+ cat >3/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/3/.git
+setup: worktree: $TRASH_DIRECTORY/3
+setup: cwd: $TRASH_DIRECTORY/3
+setup: prefix: (null)
+EOF
+ test_repo 3 "$TRASH_DIRECTORY/3/.git" .
+'
+
+test_expect_success '#3: GIT_DIR(rel), GIT_WORKTREE=root in subdir' '
+ cat >3/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/3/.git
+setup: worktree: $TRASH_DIRECTORY/3
+setup: cwd: $TRASH_DIRECTORY/3
+setup: prefix: sub/sub/
+EOF
+ test_repo 3/sub/sub ../../.git "$TRASH_DIRECTORY/3"
+'
+
+test_expect_success '#3: GIT_DIR(rel), GIT_WORKTREE=root(rel) in subdir' '
+ cat >3/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/3/.git
+setup: worktree: $TRASH_DIRECTORY/3
+setup: cwd: $TRASH_DIRECTORY/3
+setup: prefix: sub/sub/
+EOF
+ test_repo 3/sub/sub ../../.git ../..
+'
+
+test_expect_success '#3: GIT_DIR, GIT_WORKTREE=root in subdir' '
+ cat >3/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/3/.git
+setup: worktree: $TRASH_DIRECTORY/3
+setup: cwd: $TRASH_DIRECTORY/3
+setup: prefix: sub/
+EOF
+ test_repo 3/sub "$TRASH_DIRECTORY/3/.git" "$TRASH_DIRECTORY/3"
+'
+
+test_expect_success '#3: GIT_DIR, GIT_WORKTREE=root(rel) in subdir' '
+ cat >3/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/3/.git
+setup: worktree: $TRASH_DIRECTORY/3
+setup: cwd: $TRASH_DIRECTORY/3
+setup: prefix: sub/sub/
+EOF
+ test_repo 3/sub/sub "$TRASH_DIRECTORY/3/.git" ../..
+'
+
+test_expect_success '#3: GIT_DIR(rel), GIT_WORK_TREE=wt at root' '
+ cat >3/expected <<EOF &&
+setup: git_dir: .git
+setup: worktree: $TRASH_DIRECTORY/3/wt
+setup: cwd: $TRASH_DIRECTORY/3
+setup: prefix: (null)
+EOF
+ test_repo 3 .git "$TRASH_DIRECTORY/3/wt"
+'
+
+test_expect_success '#3: GIT_DIR(rel), GIT_WORK_TREE=wt(rel) at root' '
+ cat >3/expected <<EOF &&
+setup: git_dir: .git
+setup: worktree: $TRASH_DIRECTORY/3/wt
+setup: cwd: $TRASH_DIRECTORY/3
+setup: prefix: (null)
+EOF
+ test_repo 3 .git wt
+'
+
+test_expect_success '#3: GIT_DIR, GIT_WORK_TREE=wt(rel) at root' '
+ cat >3/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/3/.git
+setup: worktree: $TRASH_DIRECTORY/3/wt
+setup: cwd: $TRASH_DIRECTORY/3
+setup: prefix: (null)
+EOF
+ test_repo 3 "$TRASH_DIRECTORY/3/.git" wt
+'
+
+test_expect_success '#3: GIT_DIR, GIT_WORK_TREE=wt at root' '
+ cat >3/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/3/.git
+setup: worktree: $TRASH_DIRECTORY/3/wt
+setup: cwd: $TRASH_DIRECTORY/3
+setup: prefix: (null)
+EOF
+ test_repo 3 "$TRASH_DIRECTORY/3/.git" "$TRASH_DIRECTORY/3/wt"
+'
+
+test_expect_success '#3: GIT_DIR(rel), GIT_WORK_TREE=wt in subdir' '
+ cat >3/sub/sub/expected <<EOF &&
+setup: git_dir: ../../.git
+setup: worktree: $TRASH_DIRECTORY/3/wt
+setup: cwd: $TRASH_DIRECTORY/3/sub/sub
+setup: prefix: (null)
+EOF
+ test_repo 3/sub/sub ../../.git "$TRASH_DIRECTORY/3/wt"
+'
+
+test_expect_success '#3: GIT_DIR(rel), GIT_WORK_TREE=wt(rel) in subdir' '
+ cat >3/sub/sub/expected <<EOF &&
+setup: git_dir: ../../.git
+setup: worktree: $TRASH_DIRECTORY/3/wt
+setup: cwd: $TRASH_DIRECTORY/3/sub/sub
+setup: prefix: (null)
+EOF
+ test_repo 3/sub/sub ../../.git ../../wt
+'
+
+test_expect_success '#3: GIT_DIR, GIT_WORK_TREE=wt(rel) in subdir' '
+ cat >3/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/3/.git
+setup: worktree: $TRASH_DIRECTORY/3/wt
+setup: cwd: $TRASH_DIRECTORY/3/sub/sub
+setup: prefix: (null)
+EOF
+ test_repo 3/sub/sub "$TRASH_DIRECTORY/3/.git" ../../wt
+'
+
+test_expect_success '#3: GIT_DIR, GIT_WORK_TREE=wt in subdir' '
+ cat >3/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/3/.git
+setup: worktree: $TRASH_DIRECTORY/3/wt
+setup: cwd: $TRASH_DIRECTORY/3/sub/sub
+setup: prefix: (null)
+EOF
+ test_repo 3/sub/sub "$TRASH_DIRECTORY/3/.git" "$TRASH_DIRECTORY/3/wt"
+'
+
+test_expect_success '#3: GIT_DIR(rel), GIT_WORK_TREE=.. at root' '
+ cat >3/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/3/.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 3/
+EOF
+ test_repo 3 .git "$TRASH_DIRECTORY"
+'
+
+test_expect_success '#3: GIT_DIR(rel), GIT_WORK_TREE=..(rel) at root' '
+ cat >3/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/3/.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 3/
+EOF
+ test_repo 3 .git ..
+'
+
+test_expect_success '#3: GIT_DIR, GIT_WORK_TREE=..(rel) at root' '
+ cat >3/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/3/.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 3/
+EOF
+ test_repo 3 "$TRASH_DIRECTORY/3/.git" ..
+'
+
+test_expect_success '#3: GIT_DIR, GIT_WORK_TREE=.. at root' '
+ cat >3/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/3/.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 3/
+EOF
+ test_repo 3 "$TRASH_DIRECTORY/3/.git" "$TRASH_DIRECTORY"
+'
+
+test_expect_success '#3: GIT_DIR(rel), GIT_WORK_TREE=.. in subdir' '
+ cat >3/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/3/.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 3/sub/sub/
+EOF
+ test_repo 3/sub/sub ../../.git "$TRASH_DIRECTORY"
+'
+
+test_expect_success '#3: GIT_DIR(rel), GIT_WORK_TREE=..(rel) in subdir' '
+ cat >3/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/3/.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 3/sub/sub/
+EOF
+ test_repo 3/sub/sub ../../.git ../../..
+'
+
+test_expect_success '#3: GIT_DIR, GIT_WORK_TREE=..(rel) in subdir' '
+ cat >3/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/3/.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 3/sub/sub/
+EOF
+ test_repo 3/sub/sub "$TRASH_DIRECTORY/3/.git" ../../../
+'
+
+test_expect_success '#3: GIT_DIR, GIT_WORK_TREE=.. in subdir' '
+ cat >3/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/3/.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 3/sub/sub/
+EOF
+ test_repo 3/sub/sub "$TRASH_DIRECTORY/3/.git" "$TRASH_DIRECTORY"
+'
+
+#
+# case #4
+#
+############################################################
+#
+# Input:
+#
+# - GIT_WORK_TREE is not set
+# - GIT_DIR is not set
+# - core.worktree is set
+# - .git is a directory
+# - core.bare is not set, cwd is outside .git
+#
+# Output:
+#
+# core.worktree is ignored -> #0
+
+test_expect_success '#4: setup' '
+ unset GIT_DIR GIT_WORK_TREE &&
+ mkdir 4 4/sub &&
+ cd 4 &&
+ git init &&
+ git config core.worktree non-existent &&
+ cd ..
+'
+
+test_expect_success '#4: at root' '
+ cat >4/expected <<EOF &&
+setup: git_dir: .git
+setup: worktree: $TRASH_DIRECTORY/4
+setup: cwd: $TRASH_DIRECTORY/4
+setup: prefix: (null)
+EOF
+ test_repo 4
+'
+
+test_expect_success '#4: in subdir' '
+ cat >4/sub/expected <<EOF &&
+setup: git_dir: .git
+setup: worktree: $TRASH_DIRECTORY/4
+setup: cwd: $TRASH_DIRECTORY/4
+setup: prefix: sub/
+EOF
+ test_repo 4/sub
+'
+
+#
+# case #5
+#
+############################################################
+#
+# Input:
+#
+# - GIT_WORK_TREE is set
+# - GIT_DIR is not set
+# - core.worktree is set
+# - .git is a directory
+# - core.bare is not set, cwd is outside .git
+#
+# Output:
+#
+# GIT_WORK_TREE/core.worktree are ignored -> #0
+
+test_expect_success '#5: setup' '
+ unset GIT_DIR GIT_WORK_TREE &&
+ mkdir 5 5/sub &&
+ cd 5 &&
+ git init &&
+ git config core.worktree non-existent &&
+ GIT_WORK_TREE=non-existent-too &&
+ export GIT_WORK_TREE &&
+ cd ..
+'
+
+test_expect_success '#5: at root' '
+ cat >5/expected <<EOF &&
+setup: git_dir: .git
+setup: worktree: $TRASH_DIRECTORY/5
+setup: cwd: $TRASH_DIRECTORY/5
+setup: prefix: (null)
+EOF
+ test_repo 5
+'
+
+test_expect_success '#5: in subdir' '
+ cat >5/sub/expected <<EOF &&
+setup: git_dir: .git
+setup: worktree: $TRASH_DIRECTORY/5
+setup: cwd: $TRASH_DIRECTORY/5
+setup: prefix: sub/
+EOF
+ test_repo 5/sub
+'
+
+#
+# case #6
+#
+############################################################
+#
+# Input:
+#
+# - GIT_WORK_TREE is not set
+# - GIT_DIR is set
+# - core.worktree is set
+# - .git is a directory
+# - core.bare is not set, cwd is outside .git
+#
+# Output:
+#
+# - worktree is at core.worktree
+# - cwd is at worktree root
+# - prefix is calculated
+# - git_dir is at $GIT_DIR
+# - cwd can be outside worktree
+
+test_expect_success '#6: setup' '
+ unset GIT_DIR GIT_WORK_TREE &&
+ mkdir 6 6/sub 6/sub/sub 6.wt 6.wt/sub 6/wt 6/wt/sub &&
+ cd 6 && git init && cd ..
+'
+
+test_expect_success '#6: GIT_DIR(rel), core.worktree=.. at root' '
+ cat >6/expected <<EOF &&
+setup: git_dir: .git
+setup: worktree: $TRASH_DIRECTORY/6
+setup: cwd: $TRASH_DIRECTORY/6
+setup: prefix: (null)
+EOF
+ git config --file="$TRASH_DIRECTORY/6/.git/config" core.worktree "$TRASH_DIRECTORY/6" &&
+ test_repo 6 .git
+'
+
+test_expect_success '#6: GIT_DIR(rel), core.worktree=..(rel) at root' '
+ cat >6/expected <<EOF &&
+setup: git_dir: .git
+setup: worktree: $TRASH_DIRECTORY/6
+setup: cwd: $TRASH_DIRECTORY/6
+setup: prefix: (null)
+EOF
+ git config --file="$TRASH_DIRECTORY/6/.git/config" core.worktree .. &&
+ test_repo 6 .git
+'
+
+test_expect_success '#6: GIT_DIR, core.worktree=.. at root' '
+ cat >6/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/6/.git
+setup: worktree: $TRASH_DIRECTORY/6
+setup: cwd: $TRASH_DIRECTORY/6
+setup: prefix: (null)
+EOF
+ git config --file="$TRASH_DIRECTORY/6/.git/config" core.worktree "$TRASH_DIRECTORY/6" &&
+ test_repo 6 "$TRASH_DIRECTORY/6/.git"
+'
+
+test_expect_success '#6: GIT_DIR, core.worktree=..(rel) at root' '
+ cat >6/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/6/.git
+setup: worktree: $TRASH_DIRECTORY/6
+setup: cwd: $TRASH_DIRECTORY/6
+setup: prefix: (null)
+EOF
+ git config --file="$TRASH_DIRECTORY/6/.git/config" core.worktree .. &&
+ test_repo 6 "$TRASH_DIRECTORY/6/.git"
+'
+
+test_expect_success '#6: GIT_DIR(rel), core.worktree=.. in subdir' '
+ cat >6/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/6/.git
+setup: worktree: $TRASH_DIRECTORY/6
+setup: cwd: $TRASH_DIRECTORY/6
+setup: prefix: sub/sub/
+EOF
+ git config --file="$TRASH_DIRECTORY/6/.git/config" core.worktree "$TRASH_DIRECTORY/6" &&
+ test_repo 6/sub/sub ../../.git
+'
+
+test_expect_success '#6: GIT_DIR(rel), core.worktree=..(rel) in subdir' '
+ cat >6/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/6/.git
+setup: worktree: $TRASH_DIRECTORY/6
+setup: cwd: $TRASH_DIRECTORY/6
+setup: prefix: sub/sub/
+EOF
+ git config --file="$TRASH_DIRECTORY/6/.git/config" core.worktree .. &&
+ test_repo 6/sub/sub ../../.git
+'
+
+test_expect_success '#6: GIT_DIR, core.worktree=.. in subdir' '
+ cat >6/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/6/.git
+setup: worktree: $TRASH_DIRECTORY/6
+setup: cwd: $TRASH_DIRECTORY/6
+setup: prefix: sub/
+EOF
+ git config --file="$TRASH_DIRECTORY/6/.git/config" core.worktree "$TRASH_DIRECTORY/6" &&
+ test_repo 6/sub "$TRASH_DIRECTORY/6/.git"
+'
+
+test_expect_success '#6: GIT_DIR, core.worktree=..(rel) in subdir' '
+ cat >6/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/6/.git
+setup: worktree: $TRASH_DIRECTORY/6
+setup: cwd: $TRASH_DIRECTORY/6
+setup: prefix: sub/sub/
+EOF
+ git config --file="$TRASH_DIRECTORY/6/.git/config" core.worktree .. &&
+ test_repo 6/sub/sub "$TRASH_DIRECTORY/6/.git"
+'
+
+test_expect_success '#6: GIT_DIR(rel), core.worktree=../wt at root' '
+ cat >6/expected <<EOF &&
+setup: git_dir: .git
+setup: worktree: $TRASH_DIRECTORY/6/wt
+setup: cwd: $TRASH_DIRECTORY/6
+setup: prefix: (null)
+EOF
+ git config --file="$TRASH_DIRECTORY/6/.git/config" core.worktree "$TRASH_DIRECTORY/6/wt" &&
+ test_repo 6 .git
+'
+
+test_expect_success '#6: GIT_DIR(rel), core.worktree=../wt(rel) at root' '
+ cat >6/expected <<EOF &&
+setup: git_dir: .git
+setup: worktree: $TRASH_DIRECTORY/6/wt
+setup: cwd: $TRASH_DIRECTORY/6
+setup: prefix: (null)
+EOF
+ git config --file="$TRASH_DIRECTORY/6/.git/config" core.worktree ../wt &&
+ test_repo 6 .git
+'
+
+test_expect_success '#6: GIT_DIR, core.worktree=../wt(rel) at root' '
+ cat >6/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/6/.git
+setup: worktree: $TRASH_DIRECTORY/6/wt
+setup: cwd: $TRASH_DIRECTORY/6
+setup: prefix: (null)
+EOF
+ git config --file="$TRASH_DIRECTORY/6/.git/config" core.worktree ../wt &&
+ test_repo 6 "$TRASH_DIRECTORY/6/.git"
+'
+
+test_expect_success '#6: GIT_DIR, core.worktree=../wt at root' '
+ cat >6/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/6/.git
+setup: worktree: $TRASH_DIRECTORY/6/wt
+setup: cwd: $TRASH_DIRECTORY/6
+setup: prefix: (null)
+EOF
+ git config --file="$TRASH_DIRECTORY/6/.git/config" core.worktree "$TRASH_DIRECTORY/6/wt" &&
+ test_repo 6 "$TRASH_DIRECTORY/6/.git"
+'
+
+test_expect_success '#6: GIT_DIR(rel), core.worktree=../wt in subdir' '
+ cat >6/sub/sub/expected <<EOF &&
+setup: git_dir: ../../.git
+setup: worktree: $TRASH_DIRECTORY/6/wt
+setup: cwd: $TRASH_DIRECTORY/6/sub/sub
+setup: prefix: (null)
+EOF
+ git config --file="$TRASH_DIRECTORY/6/.git/config" core.worktree "$TRASH_DIRECTORY/6/wt" &&
+ test_repo 6/sub/sub ../../.git
+'
+
+test_expect_success '#6: GIT_DIR(rel), core.worktree=../wt(rel) in subdir' '
+ cat >6/sub/sub/expected <<EOF &&
+setup: git_dir: ../../.git
+setup: worktree: $TRASH_DIRECTORY/6/wt
+setup: cwd: $TRASH_DIRECTORY/6/sub/sub
+setup: prefix: (null)
+EOF
+ git config --file="$TRASH_DIRECTORY/6/.git/config" core.worktree ../wt &&
+ test_repo 6/sub/sub ../../.git
+'
+
+test_expect_success '#6: GIT_DIR, core.worktree=../wt(rel) in subdir' '
+ cat >6/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/6/.git
+setup: worktree: $TRASH_DIRECTORY/6/wt
+setup: cwd: $TRASH_DIRECTORY/6/sub/sub
+setup: prefix: (null)
+EOF
+ git config --file="$TRASH_DIRECTORY/6/.git/config" core.worktree ../wt &&
+ test_repo 6/sub/sub "$TRASH_DIRECTORY/6/.git"
+'
+
+test_expect_success '#6: GIT_DIR, core.worktree=../wt in subdir' '
+ cat >6/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/6/.git
+setup: worktree: $TRASH_DIRECTORY/6/wt
+setup: cwd: $TRASH_DIRECTORY/6/sub/sub
+setup: prefix: (null)
+EOF
+ git config --file="$TRASH_DIRECTORY/6/.git/config" core.worktree "$TRASH_DIRECTORY/6/wt" &&
+ test_repo 6/sub/sub "$TRASH_DIRECTORY/6/.git"
+'
+
+test_expect_success '#6: GIT_DIR(rel), core.worktree=../.. at root' '
+ cat >6/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/6/.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 6/
+EOF
+ git config --file="$TRASH_DIRECTORY/6/.git/config" core.worktree "$TRASH_DIRECTORY" &&
+ test_repo 6 .git
+'
+
+test_expect_success '#6: GIT_DIR(rel), core.worktree=../..(rel) at root' '
+ cat >6/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/6/.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 6/
+EOF
+ git config --file="$TRASH_DIRECTORY/6/.git/config" core.worktree ../../ &&
+ test_repo 6 .git
+'
+
+test_expect_success '#6: GIT_DIR, core.worktree=../..(rel) at root' '
+ cat >6/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/6/.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 6/
+EOF
+ git config --file="$TRASH_DIRECTORY/6/.git/config" core.worktree ../../ &&
+ test_repo 6 "$TRASH_DIRECTORY/6/.git"
+'
+
+test_expect_success '#6: GIT_DIR, core.worktree=../.. at root' '
+ cat >6/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/6/.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 6/
+EOF
+ git config --file="$TRASH_DIRECTORY/6/.git/config" core.worktree "$TRASH_DIRECTORY" &&
+ test_repo 6 "$TRASH_DIRECTORY/6/.git"
+'
+
+test_expect_success '#6: GIT_DIR(rel), core.worktree=../.. in subdir' '
+ cat >6/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/6/.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 6/sub/sub/
+EOF
+ git config --file="$TRASH_DIRECTORY/6/.git/config" core.worktree "$TRASH_DIRECTORY" &&
+ test_repo 6/sub/sub ../../.git
+'
+
+test_expect_success '#6: GIT_DIR(rel), core.worktree=../..(rel) in subdir' '
+ cat >6/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/6/.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 6/sub/sub/
+EOF
+ git config --file="$TRASH_DIRECTORY/6/.git/config" core.worktree ../.. &&
+ test_repo 6/sub/sub ../../.git
+'
+
+test_expect_success '#6: GIT_DIR, core.worktree=../..(rel) in subdir' '
+ cat >6/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/6/.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 6/sub/sub/
+EOF
+ git config --file="$TRASH_DIRECTORY/6/.git/config" core.worktree ../.. &&
+ test_repo 6/sub/sub "$TRASH_DIRECTORY/6/.git"
+'
+
+test_expect_success '#6: GIT_DIR, core.worktree=../.. in subdir' '
+ cat >6/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/6/.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 6/sub/sub/
+EOF
+ git config --file="$TRASH_DIRECTORY/6/.git/config" core.worktree "$TRASH_DIRECTORY" &&
+ test_repo 6/sub/sub "$TRASH_DIRECTORY/6/.git"
+'
+
+#
+# case #7
+#
+############################################################
+#
+# Input:
+#
+# - GIT_WORK_TREE is set
+# - GIT_DIR is set
+# - core.worktree is set
+# - .git is a directory
+# - core.bare is not set, cwd is outside .git
+#
+# Output:
+#
+# core.worktree is overridden by GIT_WORK_TREE -> #3
+
+test_expect_success '#7: setup' '
+ unset GIT_DIR GIT_WORK_TREE &&
+ mkdir 7 7/sub 7/sub/sub 7.wt 7.wt/sub 7/wt 7/wt/sub &&
+ cd 7 &&
+ git init &&
+ git config core.worktree non-existent &&
+ cd ..
+'
+
+test_expect_success '#7: GIT_DIR(rel), GIT_WORK_TREE=root at root' '
+ cat >7/expected <<EOF &&
+setup: git_dir: .git
+setup: worktree: $TRASH_DIRECTORY/7
+setup: cwd: $TRASH_DIRECTORY/7
+setup: prefix: (null)
+EOF
+ test_repo 7 .git "$TRASH_DIRECTORY/7"
+'
+
+test_expect_success '#7: GIT_DIR(rel), GIT_WORK_TREE=root(rel) at root' '
+ cat >7/expected <<EOF &&
+setup: git_dir: .git
+setup: worktree: $TRASH_DIRECTORY/7
+setup: cwd: $TRASH_DIRECTORY/7
+setup: prefix: (null)
+EOF
+ test_repo 7 .git .
+'
+
+test_expect_success '#7: GIT_DIR, GIT_WORK_TREE=root at root' '
+ cat >7/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/7/.git
+setup: worktree: $TRASH_DIRECTORY/7
+setup: cwd: $TRASH_DIRECTORY/7
+setup: prefix: (null)
+EOF
+ test_repo 7 "$TRASH_DIRECTORY/7/.git" "$TRASH_DIRECTORY/7"
+'
+
+test_expect_success '#7: GIT_DIR, GIT_WORK_TREE=root(rel) at root' '
+ cat >7/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/7/.git
+setup: worktree: $TRASH_DIRECTORY/7
+setup: cwd: $TRASH_DIRECTORY/7
+setup: prefix: (null)
+EOF
+ test_repo 7 "$TRASH_DIRECTORY/7/.git" .
+'
+
+test_expect_success '#7: GIT_DIR(rel), GIT_WORKTREE=root in subdir' '
+ cat >7/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/7/.git
+setup: worktree: $TRASH_DIRECTORY/7
+setup: cwd: $TRASH_DIRECTORY/7
+setup: prefix: sub/sub/
+EOF
+ test_repo 7/sub/sub ../../.git "$TRASH_DIRECTORY/7"
+'
+
+test_expect_success '#7: GIT_DIR(rel), GIT_WORKTREE=root(rel) in subdir' '
+ cat >7/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/7/.git
+setup: worktree: $TRASH_DIRECTORY/7
+setup: cwd: $TRASH_DIRECTORY/7
+setup: prefix: sub/sub/
+EOF
+ test_repo 7/sub/sub ../../.git ../..
+'
+
+test_expect_success '#7: GIT_DIR, GIT_WORKTREE=root in subdir' '
+ cat >7/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/7/.git
+setup: worktree: $TRASH_DIRECTORY/7
+setup: cwd: $TRASH_DIRECTORY/7
+setup: prefix: sub/
+EOF
+ test_repo 7/sub "$TRASH_DIRECTORY/7/.git" "$TRASH_DIRECTORY/7"
+'
+
+test_expect_success '#7: GIT_DIR, GIT_WORKTREE=root(rel) in subdir' '
+ cat >7/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/7/.git
+setup: worktree: $TRASH_DIRECTORY/7
+setup: cwd: $TRASH_DIRECTORY/7
+setup: prefix: sub/sub/
+EOF
+ test_repo 7/sub/sub "$TRASH_DIRECTORY/7/.git" ../..
+'
+
+test_expect_success '#7: GIT_DIR(rel), GIT_WORK_TREE=wt at root' '
+ cat >7/expected <<EOF &&
+setup: git_dir: .git
+setup: worktree: $TRASH_DIRECTORY/7/wt
+setup: cwd: $TRASH_DIRECTORY/7
+setup: prefix: (null)
+EOF
+ test_repo 7 .git "$TRASH_DIRECTORY/7/wt"
+'
+
+test_expect_success '#7: GIT_DIR(rel), GIT_WORK_TREE=wt(rel) at root' '
+ cat >7/expected <<EOF &&
+setup: git_dir: .git
+setup: worktree: $TRASH_DIRECTORY/7/wt
+setup: cwd: $TRASH_DIRECTORY/7
+setup: prefix: (null)
+EOF
+ test_repo 7 .git wt
+'
+
+test_expect_success '#7: GIT_DIR, GIT_WORK_TREE=wt(rel) at root' '
+ cat >7/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/7/.git
+setup: worktree: $TRASH_DIRECTORY/7/wt
+setup: cwd: $TRASH_DIRECTORY/7
+setup: prefix: (null)
+EOF
+ test_repo 7 "$TRASH_DIRECTORY/7/.git" wt
+'
+
+test_expect_success '#7: GIT_DIR, GIT_WORK_TREE=wt at root' '
+ cat >7/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/7/.git
+setup: worktree: $TRASH_DIRECTORY/7/wt
+setup: cwd: $TRASH_DIRECTORY/7
+setup: prefix: (null)
+EOF
+ test_repo 7 "$TRASH_DIRECTORY/7/.git" "$TRASH_DIRECTORY/7/wt"
+'
+
+test_expect_success '#7: GIT_DIR(rel), GIT_WORK_TREE=wt in subdir' '
+ cat >7/sub/sub/expected <<EOF &&
+setup: git_dir: ../../.git
+setup: worktree: $TRASH_DIRECTORY/7/wt
+setup: cwd: $TRASH_DIRECTORY/7/sub/sub
+setup: prefix: (null)
+EOF
+ test_repo 7/sub/sub ../../.git "$TRASH_DIRECTORY/7/wt"
+'
+
+test_expect_success '#7: GIT_DIR(rel), GIT_WORK_TREE=wt(rel) in subdir' '
+ cat >7/sub/sub/expected <<EOF &&
+setup: git_dir: ../../.git
+setup: worktree: $TRASH_DIRECTORY/7/wt
+setup: cwd: $TRASH_DIRECTORY/7/sub/sub
+setup: prefix: (null)
+EOF
+ test_repo 7/sub/sub ../../.git ../../wt
+'
+
+test_expect_success '#7: GIT_DIR, GIT_WORK_TREE=wt(rel) in subdir' '
+ cat >7/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/7/.git
+setup: worktree: $TRASH_DIRECTORY/7/wt
+setup: cwd: $TRASH_DIRECTORY/7/sub/sub
+setup: prefix: (null)
+EOF
+ test_repo 7/sub/sub "$TRASH_DIRECTORY/7/.git" ../../wt
+'
+
+test_expect_success '#7: GIT_DIR, GIT_WORK_TREE=wt in subdir' '
+ cat >7/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/7/.git
+setup: worktree: $TRASH_DIRECTORY/7/wt
+setup: cwd: $TRASH_DIRECTORY/7/sub/sub
+setup: prefix: (null)
+EOF
+ test_repo 7/sub/sub "$TRASH_DIRECTORY/7/.git" "$TRASH_DIRECTORY/7/wt"
+'
+
+test_expect_success '#7: GIT_DIR(rel), GIT_WORK_TREE=.. at root' '
+ cat >7/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/7/.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 7/
+EOF
+ test_repo 7 .git "$TRASH_DIRECTORY"
+'
+
+test_expect_success '#7: GIT_DIR(rel), GIT_WORK_TREE=..(rel) at root' '
+ cat >7/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/7/.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 7/
+EOF
+ test_repo 7 .git ..
+'
+
+test_expect_success '#7: GIT_DIR, GIT_WORK_TREE=..(rel) at root' '
+ cat >7/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/7/.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 7/
+EOF
+ test_repo 7 "$TRASH_DIRECTORY/7/.git" ..
+'
+
+test_expect_success '#7: GIT_DIR, GIT_WORK_TREE=.. at root' '
+ cat >7/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/7/.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 7/
+EOF
+ test_repo 7 "$TRASH_DIRECTORY/7/.git" "$TRASH_DIRECTORY"
+'
+
+test_expect_success '#7: GIT_DIR(rel), GIT_WORK_TREE=.. in subdir' '
+ cat >7/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/7/.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 7/sub/sub/
+EOF
+ test_repo 7/sub/sub ../../.git "$TRASH_DIRECTORY"
+'
+
+test_expect_success '#7: GIT_DIR(rel), GIT_WORK_TREE=..(rel) in subdir' '
+ cat >7/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/7/.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 7/sub/sub/
+EOF
+ test_repo 7/sub/sub ../../.git ../../..
+'
+
+test_expect_success '#7: GIT_DIR, GIT_WORK_TREE=..(rel) in subdir' '
+ cat >7/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/7/.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 7/sub/sub/
+EOF
+ test_repo 7/sub/sub "$TRASH_DIRECTORY/7/.git" ../../../
+'
+
+test_expect_success '#7: GIT_DIR, GIT_WORK_TREE=.. in subdir' '
+ cat >7/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/7/.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 7/sub/sub/
+EOF
+ test_repo 7/sub/sub "$TRASH_DIRECTORY/7/.git" "$TRASH_DIRECTORY"
+'
+
+#
+# case #8
+#
+############################################################
+#
+# Input:
+#
+# - GIT_WORK_TREE is not set
+# - GIT_DIR is not set
+# - core.worktree is not set
+# - .git is a file
+# - core.bare is not set, cwd is outside .git
+#
+# Output:
+#
+# #0 except that git_dir is set by .git file
+
+test_expect_success '#8: setup' '
+ unset GIT_DIR GIT_WORK_TREE &&
+ mkdir 8 8/sub &&
+ cd 8 &&
+ git init &&
+ mv .git ../8.git &&
+ echo gitdir: ../8.git >.git &&
+ cd ..
+'
+
+test_expect_success '#8: at root' '
+ cat >8/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/8.git
+setup: worktree: $TRASH_DIRECTORY/8
+setup: cwd: $TRASH_DIRECTORY/8
+setup: prefix: (null)
+EOF
+ test_repo 8
+'
+
+test_expect_success '#8: in subdir' '
+ cat >8/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/8.git
+setup: worktree: $TRASH_DIRECTORY/8
+setup: cwd: $TRASH_DIRECTORY/8
+setup: prefix: sub/
+EOF
+ test_repo 8/sub
+'
+
+#
+# case #9
+#
+############################################################
+#
+# Input:
+#
+# - GIT_WORK_TREE is set
+# - GIT_DIR is not set
+# - core.worktree is not set
+# - .git is a file
+# - core.bare is not set, cwd is outside .git
+#
+# Output:
+#
+# #1 except that git_dir is set by .git file
+
+test_expect_success '#9: setup' '
+ unset GIT_DIR GIT_WORK_TREE &&
+ mkdir 9 9/sub 9.wt 9.wt/sub 9/wt 9/wt/sub &&
+ cd 9 &&
+ git init &&
+ mv .git ../9.git &&
+ echo gitdir: ../9.git >.git &&
+ GIT_WORK_TREE=non-existent &&
+ export GIT_WORK_TREE &&
+ cd ..
+'
+
+test_expect_success '#9: at root' '
+ cat >9/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/9.git
+setup: worktree: $TRASH_DIRECTORY/9
+setup: cwd: $TRASH_DIRECTORY/9
+setup: prefix: (null)
+EOF
+ test_repo 9
+'
+
+test_expect_success '#9: in subdir' '
+ cat >9/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/9.git
+setup: worktree: $TRASH_DIRECTORY/9
+setup: cwd: $TRASH_DIRECTORY/9
+setup: prefix: sub/
+EOF
+ test_repo 9/sub
+'
+
+#
+# case #10
+#
+############################################################
+#
+# Input:
+#
+# - GIT_WORK_TREE is not set
+# - GIT_DIR is set
+# - core.worktree is not set
+# - .git is a file
+# - core.bare is not set, cwd is outside .git
+#
+# Output:
+#
+# #2 except that git_dir is set by .git file
+
+test_expect_success '#10: setup' '
+ unset GIT_DIR GIT_WORK_TREE &&
+ mkdir 10 10/sub &&
+ cd 10 &&
+ git init &&
+ mv .git ../10.git &&
+ echo gitdir: ../10.git >.git &&
+ cd ..
+'
+
+test_expect_success '#10: at root' '
+ cat >10/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/10.git
+setup: worktree: $TRASH_DIRECTORY/10
+setup: cwd: $TRASH_DIRECTORY/10
+setup: prefix: (null)
+EOF
+ test_repo 10 "$TRASH_DIRECTORY/10/.git"
+'
+
+test_expect_success '#10: in subdir' '
+ cat >10/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/10.git
+setup: worktree: $TRASH_DIRECTORY/10/sub
+setup: cwd: $TRASH_DIRECTORY/10/sub
+setup: prefix: (null)
+EOF
+ test_repo 10/sub "$TRASH_DIRECTORY/10/.git"
+'
+
+test_expect_success '#10: relative GIT_DIR at root' '
+ cat >10/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/10.git
+setup: worktree: $TRASH_DIRECTORY/10
+setup: cwd: $TRASH_DIRECTORY/10
+setup: prefix: (null)
+EOF
+ test_repo 10 .git
+'
+
+test_expect_success '#10: relative GIT_DIR in subdir' '
+ cat >10/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/10.git
+setup: worktree: $TRASH_DIRECTORY/10/sub
+setup: cwd: $TRASH_DIRECTORY/10/sub
+setup: prefix: (null)
+EOF
+ test_repo 10/sub ../.git
+'
+
+#
+# case #11
+#
+############################################################
+#
+# Input:
+#
+# - GIT_WORK_TREE is set
+# - GIT_DIR is set
+# - core.worktree is not set
+# - .git is a file
+# - core.bare is not set, cwd is outside .git
+#
+# Output:
+#
+# #3 except that git_dir is set by .git file
+
+test_expect_success '#11: setup' '
+ unset GIT_DIR GIT_WORK_TREE &&
+ mkdir 11 11/sub 11/sub/sub 11.wt 11.wt/sub 11/wt 11/wt/sub &&
+ cd 11 &&
+ git init &&
+ mv .git ../11.git &&
+ echo gitdir: ../11.git >.git &&
+ cd ..
+'
+
+test_expect_success '#11: GIT_DIR(rel), GIT_WORK_TREE=root at root' '
+ cat >11/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/11.git
+setup: worktree: $TRASH_DIRECTORY/11
+setup: cwd: $TRASH_DIRECTORY/11
+setup: prefix: (null)
+EOF
+ test_repo 11 .git "$TRASH_DIRECTORY/11"
+'
+
+test_expect_success '#11: GIT_DIR(rel), GIT_WORK_TREE=root(rel) at root' '
+ cat >11/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/11.git
+setup: worktree: $TRASH_DIRECTORY/11
+setup: cwd: $TRASH_DIRECTORY/11
+setup: prefix: (null)
+EOF
+ test_repo 11 .git .
+'
+
+test_expect_success '#11: GIT_DIR, GIT_WORK_TREE=root at root' '
+ cat >11/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/11.git
+setup: worktree: $TRASH_DIRECTORY/11
+setup: cwd: $TRASH_DIRECTORY/11
+setup: prefix: (null)
+EOF
+ test_repo 11 "$TRASH_DIRECTORY/11/.git" "$TRASH_DIRECTORY/11"
+'
+
+test_expect_success '#11: GIT_DIR, GIT_WORK_TREE=root(rel) at root' '
+ cat >11/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/11.git
+setup: worktree: $TRASH_DIRECTORY/11
+setup: cwd: $TRASH_DIRECTORY/11
+setup: prefix: (null)
+EOF
+ test_repo 11 "$TRASH_DIRECTORY/11/.git" .
+'
+
+test_expect_success '#11: GIT_DIR(rel), GIT_WORKTREE=root in subdir' '
+ cat >11/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/11.git
+setup: worktree: $TRASH_DIRECTORY/11
+setup: cwd: $TRASH_DIRECTORY/11
+setup: prefix: sub/sub/
+EOF
+ test_repo 11/sub/sub ../../.git "$TRASH_DIRECTORY/11"
+'
+
+test_expect_success '#11: GIT_DIR(rel), GIT_WORKTREE=root(rel) in subdir' '
+ cat >11/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/11.git
+setup: worktree: $TRASH_DIRECTORY/11
+setup: cwd: $TRASH_DIRECTORY/11
+setup: prefix: sub/sub/
+EOF
+ test_repo 11/sub/sub ../../.git ../..
+'
+
+test_expect_success '#11: GIT_DIR, GIT_WORKTREE=root in subdir' '
+ cat >11/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/11.git
+setup: worktree: $TRASH_DIRECTORY/11
+setup: cwd: $TRASH_DIRECTORY/11
+setup: prefix: sub/
+EOF
+ test_repo 11/sub "$TRASH_DIRECTORY/11/.git" "$TRASH_DIRECTORY/11"
+'
+
+test_expect_success '#11: GIT_DIR, GIT_WORKTREE=root(rel) in subdir' '
+ cat >11/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/11.git
+setup: worktree: $TRASH_DIRECTORY/11
+setup: cwd: $TRASH_DIRECTORY/11
+setup: prefix: sub/sub/
+EOF
+ test_repo 11/sub/sub "$TRASH_DIRECTORY/11/.git" ../..
+'
+
+test_expect_success '#11: GIT_DIR(rel), GIT_WORK_TREE=wt at root' '
+ cat >11/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/11.git
+setup: worktree: $TRASH_DIRECTORY/11/wt
+setup: cwd: $TRASH_DIRECTORY/11
+setup: prefix: (null)
+EOF
+ test_repo 11 .git "$TRASH_DIRECTORY/11/wt"
+'
+
+test_expect_success '#11: GIT_DIR(rel), GIT_WORK_TREE=wt(rel) at root' '
+ cat >11/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/11.git
+setup: worktree: $TRASH_DIRECTORY/11/wt
+setup: cwd: $TRASH_DIRECTORY/11
+setup: prefix: (null)
+EOF
+ test_repo 11 .git wt
+'
+
+test_expect_success '#11: GIT_DIR, GIT_WORK_TREE=wt(rel) at root' '
+ cat >11/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/11.git
+setup: worktree: $TRASH_DIRECTORY/11/wt
+setup: cwd: $TRASH_DIRECTORY/11
+setup: prefix: (null)
+EOF
+ test_repo 11 "$TRASH_DIRECTORY/11/.git" wt
+'
+
+test_expect_success '#11: GIT_DIR, GIT_WORK_TREE=wt at root' '
+ cat >11/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/11.git
+setup: worktree: $TRASH_DIRECTORY/11/wt
+setup: cwd: $TRASH_DIRECTORY/11
+setup: prefix: (null)
+EOF
+ test_repo 11 "$TRASH_DIRECTORY/11/.git" "$TRASH_DIRECTORY/11/wt"
+'
+
+test_expect_success '#11: GIT_DIR(rel), GIT_WORK_TREE=wt in subdir' '
+ cat >11/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/11.git
+setup: worktree: $TRASH_DIRECTORY/11/wt
+setup: cwd: $TRASH_DIRECTORY/11/sub/sub
+setup: prefix: (null)
+EOF
+ test_repo 11/sub/sub ../../.git "$TRASH_DIRECTORY/11/wt"
+'
+
+test_expect_success '#11: GIT_DIR(rel), GIT_WORK_TREE=wt(rel) in subdir' '
+ cat >11/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/11.git
+setup: worktree: $TRASH_DIRECTORY/11/wt
+setup: cwd: $TRASH_DIRECTORY/11/sub/sub
+setup: prefix: (null)
+EOF
+ test_repo 11/sub/sub ../../.git ../../wt
+'
+
+test_expect_success '#11: GIT_DIR, GIT_WORK_TREE=wt(rel) in subdir' '
+ cat >11/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/11.git
+setup: worktree: $TRASH_DIRECTORY/11/wt
+setup: cwd: $TRASH_DIRECTORY/11/sub/sub
+setup: prefix: (null)
+EOF
+ test_repo 11/sub/sub "$TRASH_DIRECTORY/11/.git" ../../wt
+'
+
+test_expect_success '#11: GIT_DIR, GIT_WORK_TREE=wt in subdir' '
+ cat >11/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/11.git
+setup: worktree: $TRASH_DIRECTORY/11/wt
+setup: cwd: $TRASH_DIRECTORY/11/sub/sub
+setup: prefix: (null)
+EOF
+ test_repo 11/sub/sub "$TRASH_DIRECTORY/11/.git" "$TRASH_DIRECTORY/11/wt"
+'
+
+test_expect_success '#11: GIT_DIR(rel), GIT_WORK_TREE=.. at root' '
+ cat >11/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/11.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 11/
+EOF
+ test_repo 11 .git "$TRASH_DIRECTORY"
+'
+
+test_expect_success '#11: GIT_DIR(rel), GIT_WORK_TREE=..(rel) at root' '
+ cat >11/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/11.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 11/
+EOF
+ test_repo 11 .git ..
+'
+
+test_expect_success '#11: GIT_DIR, GIT_WORK_TREE=..(rel) at root' '
+ cat >11/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/11.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 11/
+EOF
+ test_repo 11 "$TRASH_DIRECTORY/11/.git" ..
+'
+
+test_expect_success '#11: GIT_DIR, GIT_WORK_TREE=.. at root' '
+ cat >11/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/11.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 11/
+EOF
+ test_repo 11 "$TRASH_DIRECTORY/11/.git" "$TRASH_DIRECTORY"
+'
+
+test_expect_success '#11: GIT_DIR(rel), GIT_WORK_TREE=.. in subdir' '
+ cat >11/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/11.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 11/sub/sub/
+EOF
+ test_repo 11/sub/sub ../../.git "$TRASH_DIRECTORY"
+'
+
+test_expect_success '#11: GIT_DIR(rel), GIT_WORK_TREE=..(rel) in subdir' '
+ cat >11/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/11.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 11/sub/sub/
+EOF
+ test_repo 11/sub/sub ../../.git ../../..
+'
+
+test_expect_success '#11: GIT_DIR, GIT_WORK_TREE=..(rel) in subdir' '
+ cat >11/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/11.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 11/sub/sub/
+EOF
+ test_repo 11/sub/sub "$TRASH_DIRECTORY/11/.git" ../../../
+'
+
+test_expect_success '#11: GIT_DIR, GIT_WORK_TREE=.. in subdir' '
+ cat >11/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/11.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 11/sub/sub/
+EOF
+ test_repo 11/sub/sub "$TRASH_DIRECTORY/11/.git" "$TRASH_DIRECTORY"
+'
+
+#
+# case #12
+#
+############################################################
+#
+# Input:
+#
+# - GIT_WORK_TREE is not set
+# - GIT_DIR is not set
+# - core.worktree is set
+# - .git is a file
+# - core.bare is not set, cwd is outside .git
+#
+# Output:
+#
+# #4 except that git_dir is set by .git file
+
+
+test_expect_success '#12: setup' '
+ unset GIT_DIR GIT_WORK_TREE &&
+ mkdir 12 12/sub 12/sub/sub 12.wt 12.wt/sub 12/wt 12/wt/sub &&
+ cd 12 &&
+ git init &&
+ git config core.worktree non-existent &&
+ mv .git ../12.git &&
+ echo gitdir: ../12.git >.git &&
+ cd ..
+'
+
+test_expect_success '#12: at root' '
+ cat >12/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/12.git
+setup: worktree: $TRASH_DIRECTORY/12
+setup: cwd: $TRASH_DIRECTORY/12
+setup: prefix: (null)
+EOF
+ test_repo 12
+'
+
+test_expect_success '#12: in subdir' '
+ cat >12/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/12.git
+setup: worktree: $TRASH_DIRECTORY/12
+setup: cwd: $TRASH_DIRECTORY/12
+setup: prefix: sub/
+EOF
+ test_repo 12/sub
+'
+
+#
+# case #13
+#
+############################################################
+#
+# Input:
+#
+# - GIT_WORK_TREE is set
+# - GIT_DIR is not set
+# - core.worktree is set
+# - .git is a file
+# - core.bare is not set, cwd is outside .git
+#
+# Output:
+#
+# #5 except that git_dir is set by .git file
+
+test_expect_success '#13: setup' '
+ unset GIT_DIR GIT_WORK_TREE &&
+ mkdir 13 13/sub 13/sub/sub 13.wt 13.wt/sub 13/wt 13/wt/sub &&
+ cd 13 &&
+ git init &&
+ git config core.worktree non-existent &&
+ GIT_WORK_TREE=non-existent-too &&
+ export GIT_WORK_TREE &&
+ mv .git ../13.git &&
+ echo gitdir: ../13.git >.git &&
+ cd ..
+'
+
+test_expect_success '#13: at root' '
+ cat >13/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/13.git
+setup: worktree: $TRASH_DIRECTORY/13
+setup: cwd: $TRASH_DIRECTORY/13
+setup: prefix: (null)
+EOF
+ test_repo 13
+'
+
+test_expect_success '#13: in subdir' '
+ cat >13/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/13.git
+setup: worktree: $TRASH_DIRECTORY/13
+setup: cwd: $TRASH_DIRECTORY/13
+setup: prefix: sub/
+EOF
+ test_repo 13/sub
+'
+
+#
+# case #14
+#
+############################################################
+#
+# Input:
+#
+# - GIT_WORK_TREE is not set
+# - GIT_DIR is set
+# - core.worktree is set
+# - .git is a file
+# - core.bare is not set, cwd is outside .git
+#
+# Output:
+#
+# #6 except that git_dir is set by .git file
+
+test_expect_success '#14: setup' '
+ unset GIT_DIR GIT_WORK_TREE &&
+ mkdir 14 14/sub 14/sub/sub 14.wt 14.wt/sub 14/wt 14/wt/sub &&
+ cd 14 &&
+ git init &&
+ mv .git ../14.git &&
+ echo gitdir: ../14.git >.git &&
+ cd ..
+'
+
+test_expect_success '#14: GIT_DIR(rel), core.worktree=../14 at root' '
+ cat >14/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/14.git
+setup: worktree: $TRASH_DIRECTORY/14
+setup: cwd: $TRASH_DIRECTORY/14
+setup: prefix: (null)
+EOF
+ git config --file="$TRASH_DIRECTORY/14.git/config" core.worktree "$TRASH_DIRECTORY/14" &&
+ test_repo 14 .git
+'
+
+test_expect_success '#14: GIT_DIR(rel), core.worktree=../14(rel) at root' '
+ cat >14/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/14.git
+setup: worktree: $TRASH_DIRECTORY/14
+setup: cwd: $TRASH_DIRECTORY/14
+setup: prefix: (null)
+EOF
+ git config --file="$TRASH_DIRECTORY/14.git/config" core.worktree ../14 &&
+ test_repo 14 .git
+'
+
+test_expect_success '#14: GIT_DIR, core.worktree=../14 at root' '
+ cat >14/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/14.git
+setup: worktree: $TRASH_DIRECTORY/14
+setup: cwd: $TRASH_DIRECTORY/14
+setup: prefix: (null)
+EOF
+ git config --file="$TRASH_DIRECTORY/14.git/config" core.worktree "$TRASH_DIRECTORY/14" &&
+ test_repo 14 "$TRASH_DIRECTORY/14/.git"
+'
+
+test_expect_success '#14: GIT_DIR, core.worktree=../14(rel) at root' '
+ cat >14/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/14.git
+setup: worktree: $TRASH_DIRECTORY/14
+setup: cwd: $TRASH_DIRECTORY/14
+setup: prefix: (null)
+EOF
+ git config --file="$TRASH_DIRECTORY/14.git/config" core.worktree ../14 &&
+ test_repo 14 "$TRASH_DIRECTORY/14/.git"
+'
+
+test_expect_success '#14: GIT_DIR(rel), core.worktree=../14 in subdir' '
+ cat >14/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/14.git
+setup: worktree: $TRASH_DIRECTORY/14
+setup: cwd: $TRASH_DIRECTORY/14
+setup: prefix: sub/sub/
+EOF
+ git config --file="$TRASH_DIRECTORY/14.git/config" core.worktree "$TRASH_DIRECTORY/14" &&
+ test_repo 14/sub/sub ../../.git
+'
+
+test_expect_success '#14: GIT_DIR(rel), core.worktree=../14(rel) in subdir' '
+ cat >14/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/14.git
+setup: worktree: $TRASH_DIRECTORY/14
+setup: cwd: $TRASH_DIRECTORY/14
+setup: prefix: sub/sub/
+EOF
+ git config --file="$TRASH_DIRECTORY/14.git/config" core.worktree ../14 &&
+ test_repo 14/sub/sub ../../.git
+'
+
+test_expect_success '#14: GIT_DIR, core.worktree=../14 in subdir' '
+ cat >14/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/14.git
+setup: worktree: $TRASH_DIRECTORY/14
+setup: cwd: $TRASH_DIRECTORY/14
+setup: prefix: sub/
+EOF
+ git config --file="$TRASH_DIRECTORY/14.git/config" core.worktree "$TRASH_DIRECTORY/14" &&
+ test_repo 14/sub "$TRASH_DIRECTORY/14/.git"
+'
+
+test_expect_success '#14: GIT_DIR, core.worktree=../14(rel) in subdir' '
+ cat >14/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/14.git
+setup: worktree: $TRASH_DIRECTORY/14
+setup: cwd: $TRASH_DIRECTORY/14
+setup: prefix: sub/sub/
+EOF
+ git config --file="$TRASH_DIRECTORY/14.git/config" core.worktree ../14 &&
+ test_repo 14/sub/sub "$TRASH_DIRECTORY/14/.git"
+'
+
+test_expect_success '#14: GIT_DIR(rel), core.worktree=../14/wt at root' '
+ cat >14/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/14.git
+setup: worktree: $TRASH_DIRECTORY/14/wt
+setup: cwd: $TRASH_DIRECTORY/14
+setup: prefix: (null)
+EOF
+ git config --file="$TRASH_DIRECTORY/14.git/config" core.worktree "$TRASH_DIRECTORY/14/wt" &&
+ test_repo 14 .git
+'
+
+test_expect_success '#14: GIT_DIR(rel), core.worktree=../14/wt(rel) at root' '
+ cat >14/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/14.git
+setup: worktree: $TRASH_DIRECTORY/14/wt
+setup: cwd: $TRASH_DIRECTORY/14
+setup: prefix: (null)
+EOF
+ git config --file="$TRASH_DIRECTORY/14.git/config" core.worktree ../14/wt &&
+ test_repo 14 .git
+'
+
+test_expect_success '#14: GIT_DIR, core.worktree=../14/wt(rel) at root' '
+ cat >14/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/14.git
+setup: worktree: $TRASH_DIRECTORY/14/wt
+setup: cwd: $TRASH_DIRECTORY/14
+setup: prefix: (null)
+EOF
+ git config --file="$TRASH_DIRECTORY/14.git/config" core.worktree ../14/wt &&
+ test_repo 14 "$TRASH_DIRECTORY/14/.git"
+'
+
+test_expect_success '#14: GIT_DIR, core.worktree=../14/wt at root' '
+ cat >14/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/14.git
+setup: worktree: $TRASH_DIRECTORY/14/wt
+setup: cwd: $TRASH_DIRECTORY/14
+setup: prefix: (null)
+EOF
+ git config --file="$TRASH_DIRECTORY/14.git/config" core.worktree "$TRASH_DIRECTORY/14/wt" &&
+ test_repo 14 "$TRASH_DIRECTORY/14/.git"
+'
+
+test_expect_success '#14: GIT_DIR(rel), core.worktree=../14/wt in subdir' '
+ cat >14/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/14.git
+setup: worktree: $TRASH_DIRECTORY/14/wt
+setup: cwd: $TRASH_DIRECTORY/14/sub/sub
+setup: prefix: (null)
+EOF
+ git config --file="$TRASH_DIRECTORY/14.git/config" core.worktree "$TRASH_DIRECTORY/14/wt" &&
+ test_repo 14/sub/sub ../../.git
+'
+
+test_expect_success '#14: GIT_DIR(rel), core.worktree=../14/wt(rel) in subdir' '
+ cat >14/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/14.git
+setup: worktree: $TRASH_DIRECTORY/14/wt
+setup: cwd: $TRASH_DIRECTORY/14/sub/sub
+setup: prefix: (null)
+EOF
+ git config --file="$TRASH_DIRECTORY/14.git/config" core.worktree ../14/wt &&
+ test_repo 14/sub/sub ../../.git
+'
+
+test_expect_success '#14: GIT_DIR, core.worktree=../14/wt(rel) in subdir' '
+ cat >14/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/14.git
+setup: worktree: $TRASH_DIRECTORY/14/wt
+setup: cwd: $TRASH_DIRECTORY/14/sub/sub
+setup: prefix: (null)
+EOF
+ git config --file="$TRASH_DIRECTORY/14.git/config" core.worktree ../14/wt &&
+ test_repo 14/sub/sub "$TRASH_DIRECTORY/14/.git"
+'
+
+test_expect_success '#14: GIT_DIR, core.worktree=../14/wt in subdir' '
+ cat >14/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/14.git
+setup: worktree: $TRASH_DIRECTORY/14/wt
+setup: cwd: $TRASH_DIRECTORY/14/sub/sub
+setup: prefix: (null)
+EOF
+ git config --file="$TRASH_DIRECTORY/14.git/config" core.worktree "$TRASH_DIRECTORY/14/wt" &&
+ test_repo 14/sub/sub "$TRASH_DIRECTORY/14/.git"
+'
+
+test_expect_success '#14: GIT_DIR(rel), core.worktree=.. at root' '
+ cat >14/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/14.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 14/
+EOF
+ git config --file="$TRASH_DIRECTORY/14.git/config" core.worktree "$TRASH_DIRECTORY" &&
+ test_repo 14 .git
+'
+
+test_expect_success '#14: GIT_DIR(rel), core.worktree=..(rel) at root' '
+ cat >14/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/14.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 14/
+EOF
+ git config --file="$TRASH_DIRECTORY/14.git/config" core.worktree .. &&
+ test_repo 14 .git
+'
+
+test_expect_success '#14: GIT_DIR, core.worktree=..(rel) at root' '
+ cat >14/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/14.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 14/
+EOF
+ git config --file="$TRASH_DIRECTORY/14.git/config" core.worktree .. &&
+ test_repo 14 "$TRASH_DIRECTORY/14/.git"
+'
+
+test_expect_success '#14: GIT_DIR, core.worktree=.. at root' '
+ cat >14/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/14.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 14/
+EOF
+ git config --file="$TRASH_DIRECTORY/14.git/config" core.worktree "$TRASH_DIRECTORY" &&
+ test_repo 14 "$TRASH_DIRECTORY/14/.git"
+'
+
+test_expect_success '#14: GIT_DIR(rel), core.worktree=.. in subdir' '
+ cat >14/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/14.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 14/sub/sub/
+EOF
+ git config --file="$TRASH_DIRECTORY/14.git/config" core.worktree "$TRASH_DIRECTORY" &&
+ test_repo 14/sub/sub ../../.git
+'
+
+test_expect_success '#14: GIT_DIR(rel), core.worktree=..(rel) in subdir' '
+ cat >14/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/14.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 14/sub/sub/
+EOF
+ git config --file="$TRASH_DIRECTORY/14.git/config" core.worktree .. &&
+ test_repo 14/sub/sub ../../.git
+'
+
+test_expect_success '#14: GIT_DIR, core.worktree=..(rel) in subdir' '
+ cat >14/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/14.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 14/sub/sub/
+EOF
+ git config --file="$TRASH_DIRECTORY/14.git/config" core.worktree .. &&
+ test_repo 14/sub/sub "$TRASH_DIRECTORY/14/.git"
+'
+
+test_expect_success '#14: GIT_DIR, core.worktree=.. in subdir' '
+ cat >14/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/14.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 14/sub/sub/
+EOF
+ git config --file="$TRASH_DIRECTORY/14.git/config" core.worktree "$TRASH_DIRECTORY" &&
+ test_repo 14/sub/sub "$TRASH_DIRECTORY/14/.git"
+'
+
+#
+# case #15
+#
+############################################################
+#
+# Input:
+#
+# - GIT_WORK_TREE is set
+# - GIT_DIR is set
+# - core.worktree is set
+# - .git is a file
+# - core.bare is not set, cwd is outside .git
+#
+# Output:
+#
+# #7 except that git_dir is set by .git file
+
+test_expect_success '#15: setup' '
+ unset GIT_DIR GIT_WORK_TREE &&
+ mkdir 15 15/sub 15/sub/sub 15.wt 15.wt/sub 15/wt 15/wt/sub &&
+ cd 15 &&
+ git init &&
+ git config core.worktree non-existent &&
+ mv .git ../15.git &&
+ echo gitdir: ../15.git >.git &&
+ cd ..
+'
+
+test_expect_success '#15: GIT_DIR(rel), GIT_WORK_TREE=root at root' '
+ cat >15/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/15.git
+setup: worktree: $TRASH_DIRECTORY/15
+setup: cwd: $TRASH_DIRECTORY/15
+setup: prefix: (null)
+EOF
+ test_repo 15 .git "$TRASH_DIRECTORY/15"
+'
+
+test_expect_success '#15: GIT_DIR(rel), GIT_WORK_TREE=root(rel) at root' '
+ cat >15/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/15.git
+setup: worktree: $TRASH_DIRECTORY/15
+setup: cwd: $TRASH_DIRECTORY/15
+setup: prefix: (null)
+EOF
+ test_repo 15 .git .
+'
+
+test_expect_success '#15: GIT_DIR, GIT_WORK_TREE=root at root' '
+ cat >15/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/15.git
+setup: worktree: $TRASH_DIRECTORY/15
+setup: cwd: $TRASH_DIRECTORY/15
+setup: prefix: (null)
+EOF
+ test_repo 15 "$TRASH_DIRECTORY/15/.git" "$TRASH_DIRECTORY/15"
+'
+
+test_expect_success '#15: GIT_DIR, GIT_WORK_TREE=root(rel) at root' '
+ cat >15/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/15.git
+setup: worktree: $TRASH_DIRECTORY/15
+setup: cwd: $TRASH_DIRECTORY/15
+setup: prefix: (null)
+EOF
+ test_repo 15 "$TRASH_DIRECTORY/15/.git" .
+'
+
+test_expect_success '#15: GIT_DIR(rel), GIT_WORKTREE=root in subdir' '
+ cat >15/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/15.git
+setup: worktree: $TRASH_DIRECTORY/15
+setup: cwd: $TRASH_DIRECTORY/15
+setup: prefix: sub/sub/
+EOF
+ test_repo 15/sub/sub ../../.git "$TRASH_DIRECTORY/15"
+'
+
+test_expect_success '#15: GIT_DIR(rel), GIT_WORKTREE=root(rel) in subdir' '
+ cat >15/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/15.git
+setup: worktree: $TRASH_DIRECTORY/15
+setup: cwd: $TRASH_DIRECTORY/15
+setup: prefix: sub/sub/
+EOF
+ test_repo 15/sub/sub ../../.git ../..
+'
+
+test_expect_success '#15: GIT_DIR, GIT_WORKTREE=root in subdir' '
+ cat >15/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/15.git
+setup: worktree: $TRASH_DIRECTORY/15
+setup: cwd: $TRASH_DIRECTORY/15
+setup: prefix: sub/
+EOF
+ test_repo 15/sub "$TRASH_DIRECTORY/15/.git" "$TRASH_DIRECTORY/15"
+'
+
+test_expect_success '#15: GIT_DIR, GIT_WORKTREE=root(rel) in subdir' '
+ cat >15/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/15.git
+setup: worktree: $TRASH_DIRECTORY/15
+setup: cwd: $TRASH_DIRECTORY/15
+setup: prefix: sub/sub/
+EOF
+ test_repo 15/sub/sub "$TRASH_DIRECTORY/15/.git" ../..
+'
+
+test_expect_success '#15: GIT_DIR(rel), GIT_WORK_TREE=wt at root' '
+ cat >15/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/15.git
+setup: worktree: $TRASH_DIRECTORY/15/wt
+setup: cwd: $TRASH_DIRECTORY/15
+setup: prefix: (null)
+EOF
+ test_repo 15 .git "$TRASH_DIRECTORY/15/wt"
+'
+
+test_expect_success '#15: GIT_DIR(rel), GIT_WORK_TREE=wt(rel) at root' '
+ cat >15/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/15.git
+setup: worktree: $TRASH_DIRECTORY/15/wt
+setup: cwd: $TRASH_DIRECTORY/15
+setup: prefix: (null)
+EOF
+ test_repo 15 .git wt
+'
+
+test_expect_success '#15: GIT_DIR, GIT_WORK_TREE=wt(rel) at root' '
+ cat >15/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/15.git
+setup: worktree: $TRASH_DIRECTORY/15/wt
+setup: cwd: $TRASH_DIRECTORY/15
+setup: prefix: (null)
+EOF
+ test_repo 15 "$TRASH_DIRECTORY/15/.git" wt
+'
+
+test_expect_success '#15: GIT_DIR, GIT_WORK_TREE=wt at root' '
+ cat >15/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/15.git
+setup: worktree: $TRASH_DIRECTORY/15/wt
+setup: cwd: $TRASH_DIRECTORY/15
+setup: prefix: (null)
+EOF
+ test_repo 15 "$TRASH_DIRECTORY/15/.git" "$TRASH_DIRECTORY/15/wt"
+'
+
+test_expect_success '#15: GIT_DIR(rel), GIT_WORK_TREE=wt in subdir' '
+ cat >15/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/15.git
+setup: worktree: $TRASH_DIRECTORY/15/wt
+setup: cwd: $TRASH_DIRECTORY/15/sub/sub
+setup: prefix: (null)
+EOF
+ test_repo 15/sub/sub ../../.git "$TRASH_DIRECTORY/15/wt"
+'
+
+test_expect_success '#15: GIT_DIR(rel), GIT_WORK_TREE=wt(rel) in subdir' '
+ cat >15/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/15.git
+setup: worktree: $TRASH_DIRECTORY/15/wt
+setup: cwd: $TRASH_DIRECTORY/15/sub/sub
+setup: prefix: (null)
+EOF
+ test_repo 15/sub/sub ../../.git ../../wt
+'
+
+test_expect_success '#15: GIT_DIR, GIT_WORK_TREE=wt(rel) in subdir' '
+ cat >15/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/15.git
+setup: worktree: $TRASH_DIRECTORY/15/wt
+setup: cwd: $TRASH_DIRECTORY/15/sub/sub
+setup: prefix: (null)
+EOF
+ test_repo 15/sub/sub "$TRASH_DIRECTORY/15/.git" ../../wt
+'
+
+test_expect_success '#15: GIT_DIR, GIT_WORK_TREE=wt in subdir' '
+ cat >15/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/15.git
+setup: worktree: $TRASH_DIRECTORY/15/wt
+setup: cwd: $TRASH_DIRECTORY/15/sub/sub
+setup: prefix: (null)
+EOF
+ test_repo 15/sub/sub "$TRASH_DIRECTORY/15/.git" "$TRASH_DIRECTORY/15/wt"
+'
+
+test_expect_success '#15: GIT_DIR(rel), GIT_WORK_TREE=.. at root' '
+ cat >15/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/15.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 15/
+EOF
+ test_repo 15 .git "$TRASH_DIRECTORY"
+'
+
+test_expect_success '#15: GIT_DIR(rel), GIT_WORK_TREE=..(rel) at root' '
+ cat >15/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/15.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 15/
+EOF
+ test_repo 15 .git ..
+'
+
+test_expect_success '#15: GIT_DIR, GIT_WORK_TREE=..(rel) at root' '
+ cat >15/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/15.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 15/
+EOF
+ test_repo 15 "$TRASH_DIRECTORY/15/.git" ..
+'
+
+test_expect_success '#15: GIT_DIR, GIT_WORK_TREE=.. at root' '
+ cat >15/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/15.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 15/
+EOF
+ test_repo 15 "$TRASH_DIRECTORY/15/.git" "$TRASH_DIRECTORY"
+'
+
+test_expect_success '#15: GIT_DIR(rel), GIT_WORK_TREE=.. in subdir' '
+ cat >15/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/15.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 15/sub/sub/
+EOF
+ test_repo 15/sub/sub ../../.git "$TRASH_DIRECTORY"
+'
+
+test_expect_success '#15: GIT_DIR(rel), GIT_WORK_TREE=..(rel) in subdir' '
+ cat >15/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/15.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 15/sub/sub/
+EOF
+ test_repo 15/sub/sub ../../.git ../../..
+'
+
+test_expect_success '#15: GIT_DIR, GIT_WORK_TREE=..(rel) in subdir' '
+ cat >15/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/15.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 15/sub/sub/
+EOF
+ test_repo 15/sub/sub "$TRASH_DIRECTORY/15/.git" ../../../
+'
+
+test_expect_success '#15: GIT_DIR, GIT_WORK_TREE=.. in subdir' '
+ cat >15/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/15.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 15/sub/sub/
+EOF
+ test_repo 15/sub/sub "$TRASH_DIRECTORY/15/.git" "$TRASH_DIRECTORY"
+'
+
+#
+# case #16.1
+#
+############################################################
+#
+# Input:
+#
+# - GIT_WORK_TREE is not set
+# - GIT_DIR is not set
+# - core.worktree is not set
+# - .git is a directory
+# - cwd is inside .git
+#
+# Output:
+#
+# - no worktree
+# - cwd is unchanged
+# - prefix is NULL
+# - git_dir is set
+# - cwd can't be outside worktree
+
+test_expect_success '#16.1: setup' '
+ unset GIT_DIR GIT_WORK_TREE &&
+ mkdir 16 16/sub &&
+ cd 16 &&
+ git init &&
+ mkdir .git/wt .git/wt/sub &&
+ cd ..
+'
+
+test_expect_success '#16.1: at .git' '
+ cat >16/.git/expected <<EOF &&
+setup: git_dir: .
+setup: worktree: (null)
+setup: cwd: $TRASH_DIRECTORY/16/.git
+setup: prefix: (null)
+EOF
+ test_repo 16/.git
+'
+
+test_expect_success '#16.1: in .git/wt' '
+ cat >16/.git/wt/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/16/.git
+setup: worktree: (null)
+setup: cwd: $TRASH_DIRECTORY/16/.git/wt
+setup: prefix: (null)
+EOF
+ test_repo 16/.git/wt
+'
+
+test_expect_success '#16.1: in .git/wt/sub' '
+ cat >16/.git/wt/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/16/.git
+setup: worktree: (null)
+setup: cwd: $TRASH_DIRECTORY/16/.git/wt/sub
+setup: prefix: (null)
+EOF
+ test_repo 16/.git/wt/sub
+'
+
+#
+# case #16.2
+#
+############################################################
+#
+# Input:
+#
+# - GIT_WORK_TREE is not set
+# - GIT_DIR is not set
+# - core.worktree is not set
+# - .git is a directory
+# - core.bare is set
+#
+# Output:
+#
+# - no worktree
+# - cwd is unchanged
+# - prefix is NULL
+# - git_dir is set
+# - cwd can't be outside worktree
+
+test_expect_success '#16.2: setup' '
+ git config --file="$TRASH_DIRECTORY/16/.git/config" core.bare true
+'
+
+test_expect_success '#16.2: at .git' '
+ cat >16/.git/expected <<EOF &&
+setup: git_dir: .
+setup: worktree: (null)
+setup: cwd: $TRASH_DIRECTORY/16/.git
+setup: prefix: (null)
+EOF
+ test_repo 16/.git
+'
+
+test_expect_success '#16.2: in .git/wt' '
+ cat >16/.git/wt/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/16/.git
+setup: worktree: (null)
+setup: cwd: $TRASH_DIRECTORY/16/.git/wt
+setup: prefix: (null)
+EOF
+ test_repo 16/.git/wt
+'
+
+test_expect_success '#16.2: in .git/wt/sub' '
+ cat >16/.git/wt/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/16/.git
+setup: worktree: (null)
+setup: cwd: $TRASH_DIRECTORY/16/.git/wt/sub
+setup: prefix: (null)
+EOF
+ test_repo 16/.git/wt/sub
+'
+
+test_expect_success '#16.2: at root' '
+ cat >16/expected <<EOF &&
+setup: git_dir: .git
+setup: worktree: (null)
+setup: cwd: $TRASH_DIRECTORY/16
+setup: prefix: (null)
+EOF
+ test_repo 16
+'
+
+test_expect_success '#16.2: in subdir' '
+ cat >16/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/16/.git
+setup: worktree: (null)
+setup: cwd: $TRASH_DIRECTORY/16/sub
+setup: prefix: (null)
+EOF
+ test_repo 16/sub
+'
+
+#
+# case #17.1
+#
+############################################################
+#
+# Input:
+#
+# - GIT_WORK_TREE is set
+# - GIT_DIR is not set
+# - core.worktree is not set
+# - .git is a directory
+# - cwd is inside .git
+#
+# Output:
+#
+# GIT_WORK_TREE is ignored -> #16.1 (with warnings perhaps)
+
+test_expect_success '#17.1: setup' '
+ unset GIT_DIR GIT_WORK_TREE &&
+ mkdir 17 17/sub &&
+ cd 17 &&
+ git init &&
+ mkdir .git/wt .git/wt/sub &&
+ GIT_WORK_TREE=non-existent &&
+ export GIT_WORK_TREE &&
+ cd ..
+'
+
+test_expect_success '#17.1: at .git' '
+ cat >17/.git/expected <<EOF &&
+setup: git_dir: .
+setup: worktree: (null)
+setup: cwd: $TRASH_DIRECTORY/17/.git
+setup: prefix: (null)
+EOF
+ test_repo 17/.git
+'
+
+test_expect_success '#17.1: in .git/wt' '
+ cat >17/.git/wt/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/17/.git
+setup: worktree: (null)
+setup: cwd: $TRASH_DIRECTORY/17/.git/wt
+setup: prefix: (null)
+EOF
+ test_repo 17/.git/wt
+'
+
+test_expect_success '#17.1: in .git/wt/sub' '
+ cat >17/.git/wt/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/17/.git
+setup: worktree: (null)
+setup: cwd: $TRASH_DIRECTORY/17/.git/wt/sub
+setup: prefix: (null)
+EOF
+ test_repo 17/.git/wt/sub
+'
+
+#
+# case #17.2
+#
+############################################################
+#
+# Input:
+#
+# - GIT_WORK_TREE is set
+# - GIT_DIR is not set
+# - core.worktree is not set
+# - .git is a directory
+# - core.bare is set
+#
+# Output:
+#
+# GIT_WORK_TREE is ignored -> #16.2 (with warnings perhaps)
+
+test_expect_success '#17.2: setup' '
+ git config --file="$TRASH_DIRECTORY/17/.git/config" core.bare true
+'
+
+test_expect_success '#17.2: at .git' '
+ cat >17/.git/expected <<EOF &&
+setup: git_dir: .
+setup: worktree: (null)
+setup: cwd: $TRASH_DIRECTORY/17/.git
+setup: prefix: (null)
+EOF
+ test_repo 17/.git
+'
+
+test_expect_success '#17.2: in .git/wt' '
+ cat >17/.git/wt/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/17/.git
+setup: worktree: (null)
+setup: cwd: $TRASH_DIRECTORY/17/.git/wt
+setup: prefix: (null)
+EOF
+ test_repo 17/.git/wt
+'
+
+test_expect_success '#17.2: in .git/wt/sub' '
+ cat >17/.git/wt/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/17/.git
+setup: worktree: (null)
+setup: cwd: $TRASH_DIRECTORY/17/.git/wt/sub
+setup: prefix: (null)
+EOF
+ test_repo 17/.git/wt/sub
+'
+
+test_expect_success '#17.2: at root' '
+ cat >17/expected <<EOF &&
+setup: git_dir: .git
+setup: worktree: (null)
+setup: cwd: $TRASH_DIRECTORY/17
+setup: prefix: (null)
+EOF
+ test_repo 17
+'
+
+test_expect_success '#17.2: in subdir' '
+ cat >17/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/17/.git
+setup: worktree: (null)
+setup: cwd: $TRASH_DIRECTORY/17/sub
+setup: prefix: (null)
+EOF
+ test_repo 17/sub
+'
+
+#
+# case #18
+#
+############################################################
+#
+# Input:
+#
+# - GIT_WORK_TREE is not set
+# - GIT_DIR is set
+# - core.worktree is not set
+# - .git is a directory
+# - core.bare is set
+#
+# Output:
+#
+# - no worktree (rule #8)
+# - cwd is unchanged
+# - prefix is NULL
+# - git_dir is set to $GIT_DIR
+# - cwd can't be outside worktree
+
+test_expect_success '#18: setup' '
+ unset GIT_DIR GIT_WORK_TREE &&
+ mkdir 18 18/sub &&
+ cd 18 &&
+ git init &&
+ mkdir .git/wt .git/wt/sub &&
+ git config core.bare true &&
+ cd ..
+'
+
+test_expect_success '#18: (rel) at root' '
+ cat >18/expected <<EOF &&
+setup: git_dir: .git
+setup: worktree: (null)
+setup: cwd: $TRASH_DIRECTORY/18
+setup: prefix: (null)
+EOF
+ test_repo 18 .git
+'
+
+test_expect_success '#18: at root' '
+ cat >18/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/18/.git
+setup: worktree: (null)
+setup: cwd: $TRASH_DIRECTORY/18
+setup: prefix: (null)
+EOF
+ test_repo 18 "$TRASH_DIRECTORY/18/.git"
+'
+
+test_expect_success '#18: (rel) in subdir' '
+ cat >18/sub/expected <<EOF &&
+setup: git_dir: ../.git
+setup: worktree: (null)
+setup: cwd: $TRASH_DIRECTORY/18/sub
+setup: prefix: (null)
+EOF
+ test_repo 18/sub ../.git
+'
+
+test_expect_success '#18: in subdir' '
+ cat >18/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/18/.git
+setup: worktree: (null)
+setup: cwd: $TRASH_DIRECTORY/18/sub
+setup: prefix: (null)
+EOF
+ test_repo 18/sub "$TRASH_DIRECTORY/18/.git"
+'
+
+#
+# case #19
+#
+############################################################
+#
+# Input:
+#
+# - GIT_WORK_TREE is set
+# - GIT_DIR is set
+# - .git is a directory
+# - core.worktree is not set
+# - core.bare is set
+#
+# Output:
+#
+# bare repo is overridden by GIT_WORK_TREE -> #3
+
+test_expect_success '#19: setup' '
+ unset GIT_DIR GIT_WORK_TREE &&
+ mkdir 19 19/sub 19/sub/sub 19.wt 19.wt/sub 19/wt 19/wt/sub &&
+ cd 19 &&
+ git init &&
+ git config core.bare true &&
+ cd ..
+'
+
+test_expect_success '#19: GIT_DIR(rel), GIT_WORK_TREE=root at root' '
+ cat >19/expected <<EOF &&
+setup: git_dir: .git
+setup: worktree: $TRASH_DIRECTORY/19
+setup: cwd: $TRASH_DIRECTORY/19
+setup: prefix: (null)
+EOF
+ test_repo 19 .git "$TRASH_DIRECTORY/19"
+'
+
+test_expect_success '#19: GIT_DIR(rel), GIT_WORK_TREE=root(rel) at root' '
+ cat >19/expected <<EOF &&
+setup: git_dir: .git
+setup: worktree: $TRASH_DIRECTORY/19
+setup: cwd: $TRASH_DIRECTORY/19
+setup: prefix: (null)
+EOF
+ test_repo 19 .git .
+'
+
+test_expect_success '#19: GIT_DIR, GIT_WORK_TREE=root at root' '
+ cat >19/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/19/.git
+setup: worktree: $TRASH_DIRECTORY/19
+setup: cwd: $TRASH_DIRECTORY/19
+setup: prefix: (null)
+EOF
+ test_repo 19 "$TRASH_DIRECTORY/19/.git" "$TRASH_DIRECTORY/19"
+'
+
+test_expect_success '#19: GIT_DIR, GIT_WORK_TREE=root(rel) at root' '
+ cat >19/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/19/.git
+setup: worktree: $TRASH_DIRECTORY/19
+setup: cwd: $TRASH_DIRECTORY/19
+setup: prefix: (null)
+EOF
+ test_repo 19 "$TRASH_DIRECTORY/19/.git" .
+'
+
+test_expect_success '#19: GIT_DIR(rel), GIT_WORKTREE=root in subdir' '
+ cat >19/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/19/.git
+setup: worktree: $TRASH_DIRECTORY/19
+setup: cwd: $TRASH_DIRECTORY/19
+setup: prefix: sub/sub/
+EOF
+ test_repo 19/sub/sub ../../.git "$TRASH_DIRECTORY/19"
+'
+
+test_expect_success '#19: GIT_DIR(rel), GIT_WORKTREE=root(rel) in subdir' '
+ cat >19/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/19/.git
+setup: worktree: $TRASH_DIRECTORY/19
+setup: cwd: $TRASH_DIRECTORY/19
+setup: prefix: sub/sub/
+EOF
+ test_repo 19/sub/sub ../../.git ../..
+'
+
+test_expect_success '#19: GIT_DIR, GIT_WORKTREE=root in subdir' '
+ cat >19/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/19/.git
+setup: worktree: $TRASH_DIRECTORY/19
+setup: cwd: $TRASH_DIRECTORY/19
+setup: prefix: sub/
+EOF
+ test_repo 19/sub "$TRASH_DIRECTORY/19/.git" "$TRASH_DIRECTORY/19"
+'
+
+test_expect_success '#19: GIT_DIR, GIT_WORKTREE=root(rel) in subdir' '
+ cat >19/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/19/.git
+setup: worktree: $TRASH_DIRECTORY/19
+setup: cwd: $TRASH_DIRECTORY/19
+setup: prefix: sub/sub/
+EOF
+ test_repo 19/sub/sub "$TRASH_DIRECTORY/19/.git" ../..
+'
+
+test_expect_success '#19: GIT_DIR(rel), GIT_WORK_TREE=wt at root' '
+ cat >19/expected <<EOF &&
+setup: git_dir: .git
+setup: worktree: $TRASH_DIRECTORY/19/wt
+setup: cwd: $TRASH_DIRECTORY/19
+setup: prefix: (null)
+EOF
+ test_repo 19 .git "$TRASH_DIRECTORY/19/wt"
+'
+
+test_expect_success '#19: GIT_DIR(rel), GIT_WORK_TREE=wt(rel) at root' '
+ cat >19/expected <<EOF &&
+setup: git_dir: .git
+setup: worktree: $TRASH_DIRECTORY/19/wt
+setup: cwd: $TRASH_DIRECTORY/19
+setup: prefix: (null)
+EOF
+ test_repo 19 .git wt
+'
+
+test_expect_success '#19: GIT_DIR, GIT_WORK_TREE=wt(rel) at root' '
+ cat >19/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/19/.git
+setup: worktree: $TRASH_DIRECTORY/19/wt
+setup: cwd: $TRASH_DIRECTORY/19
+setup: prefix: (null)
+EOF
+ test_repo 19 "$TRASH_DIRECTORY/19/.git" wt
+'
+
+test_expect_success '#19: GIT_DIR, GIT_WORK_TREE=wt at root' '
+ cat >19/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/19/.git
+setup: worktree: $TRASH_DIRECTORY/19/wt
+setup: cwd: $TRASH_DIRECTORY/19
+setup: prefix: (null)
+EOF
+ test_repo 19 "$TRASH_DIRECTORY/19/.git" "$TRASH_DIRECTORY/19/wt"
+'
+
+test_expect_success '#19: GIT_DIR(rel), GIT_WORK_TREE=wt in subdir' '
+ cat >19/sub/sub/expected <<EOF &&
+setup: git_dir: ../../.git
+setup: worktree: $TRASH_DIRECTORY/19/wt
+setup: cwd: $TRASH_DIRECTORY/19/sub/sub
+setup: prefix: (null)
+EOF
+ test_repo 19/sub/sub ../../.git "$TRASH_DIRECTORY/19/wt"
+'
+
+test_expect_success '#19: GIT_DIR(rel), GIT_WORK_TREE=wt(rel) in subdir' '
+ cat >19/sub/sub/expected <<EOF &&
+setup: git_dir: ../../.git
+setup: worktree: $TRASH_DIRECTORY/19/wt
+setup: cwd: $TRASH_DIRECTORY/19/sub/sub
+setup: prefix: (null)
+EOF
+ test_repo 19/sub/sub ../../.git ../../wt
+'
+
+test_expect_success '#19: GIT_DIR, GIT_WORK_TREE=wt(rel) in subdir' '
+ cat >19/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/19/.git
+setup: worktree: $TRASH_DIRECTORY/19/wt
+setup: cwd: $TRASH_DIRECTORY/19/sub/sub
+setup: prefix: (null)
+EOF
+ test_repo 19/sub/sub "$TRASH_DIRECTORY/19/.git" ../../wt
+'
+
+test_expect_success '#19: GIT_DIR, GIT_WORK_TREE=wt in subdir' '
+ cat >19/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/19/.git
+setup: worktree: $TRASH_DIRECTORY/19/wt
+setup: cwd: $TRASH_DIRECTORY/19/sub/sub
+setup: prefix: (null)
+EOF
+ test_repo 19/sub/sub "$TRASH_DIRECTORY/19/.git" "$TRASH_DIRECTORY/19/wt"
+'
+
+test_expect_success '#19: GIT_DIR(rel), GIT_WORK_TREE=.. at root' '
+ cat >19/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/19/.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 19/
+EOF
+ test_repo 19 .git "$TRASH_DIRECTORY"
+'
+
+test_expect_success '#19: GIT_DIR(rel), GIT_WORK_TREE=..(rel) at root' '
+ cat >19/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/19/.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 19/
+EOF
+ test_repo 19 .git ..
+'
+
+test_expect_success '#19: GIT_DIR, GIT_WORK_TREE=..(rel) at root' '
+ cat >19/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/19/.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 19/
+EOF
+ test_repo 19 "$TRASH_DIRECTORY/19/.git" ..
+'
+
+test_expect_success '#19: GIT_DIR, GIT_WORK_TREE=.. at root' '
+ cat >19/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/19/.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 19/
+EOF
+ test_repo 19 "$TRASH_DIRECTORY/19/.git" "$TRASH_DIRECTORY"
+'
+
+test_expect_success '#19: GIT_DIR(rel), GIT_WORK_TREE=.. in subdir' '
+ cat >19/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/19/.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 19/sub/sub/
+EOF
+ test_repo 19/sub/sub ../../.git "$TRASH_DIRECTORY"
+'
+
+test_expect_success '#19: GIT_DIR(rel), GIT_WORK_TREE=..(rel) in subdir' '
+ cat >19/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/19/.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 19/sub/sub/
+EOF
+ test_repo 19/sub/sub ../../.git ../../..
+'
+
+test_expect_success '#19: GIT_DIR, GIT_WORK_TREE=..(rel) in subdir' '
+ cat >19/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/19/.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 19/sub/sub/
+EOF
+ test_repo 19/sub/sub "$TRASH_DIRECTORY/19/.git" ../../../
+'
+
+test_expect_success '#19: GIT_DIR, GIT_WORK_TREE=.. in subdir' '
+ cat >19/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/19/.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 19/sub/sub/
+EOF
+ test_repo 19/sub/sub "$TRASH_DIRECTORY/19/.git" "$TRASH_DIRECTORY"
+'
+
+#
+# case #20.1
+#
+############################################################
+#
+# Input:
+#
+# - GIT_WORK_TREE is not set
+# - GIT_DIR is not set
+# - core.worktree is set
+# - .git is a directory
+# - cwd is inside .git
+#
+# Output:
+#
+# core.worktree is ignored -> #16.1
+
+test_expect_success '#20.1: setup' '
+ unset GIT_DIR GIT_WORK_TREE &&
+ mkdir 20 20/sub &&
+ cd 20 &&
+ git init &&
+ git config core.worktree non-existent &&
+ mkdir .git/wt .git/wt/sub &&
+ cd ..
+'
+
+test_expect_success '#20.1: at .git' '
+ cat >20/.git/expected <<EOF &&
+setup: git_dir: .
+setup: worktree: (null)
+setup: cwd: $TRASH_DIRECTORY/20/.git
+setup: prefix: (null)
+EOF
+ test_repo 20/.git
+'
+
+test_expect_success '#20.1: in .git/wt' '
+ cat >20/.git/wt/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/20/.git
+setup: worktree: (null)
+setup: cwd: $TRASH_DIRECTORY/20/.git/wt
+setup: prefix: (null)
+EOF
+ test_repo 20/.git/wt
+'
+
+test_expect_success '#20.1: in .git/wt/sub' '
+ cat >20/.git/wt/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/20/.git
+setup: worktree: (null)
+setup: cwd: $TRASH_DIRECTORY/20/.git/wt/sub
+setup: prefix: (null)
+EOF
+ test_repo 20/.git/wt/sub
+'
+
+#
+# case #20.2
+#
+############################################################
+#
+# Input:
+#
+# - GIT_WORK_TREE is not set
+# - GIT_DIR is not set
+# - core.worktree is set
+# - .git is a directory
+# - core.bare is set
+#
+# Output:
+#
+# core.worktree is ignored -> #16.2
+
+test_expect_success '#20.2: setup' '
+ git config --file="$TRASH_DIRECTORY/20/.git/config" core.bare true
+'
+
+test_expect_success '#20.2: at .git' '
+ cat >20/.git/expected <<EOF &&
+setup: git_dir: .
+setup: worktree: (null)
+setup: cwd: $TRASH_DIRECTORY/20/.git
+setup: prefix: (null)
+EOF
+ test_repo 20/.git
+'
+
+test_expect_success '#20.2: in .git/wt' '
+ cat >20/.git/wt/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/20/.git
+setup: worktree: (null)
+setup: cwd: $TRASH_DIRECTORY/20/.git/wt
+setup: prefix: (null)
+EOF
+ test_repo 20/.git/wt
+'
+
+test_expect_success '#20.2: in .git/wt/sub' '
+ cat >20/.git/wt/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/20/.git
+setup: worktree: (null)
+setup: cwd: $TRASH_DIRECTORY/20/.git/wt/sub
+setup: prefix: (null)
+EOF
+ test_repo 20/.git/wt/sub
+'
+
+test_expect_success '#20.2: at root' '
+ cat >20/expected <<EOF &&
+setup: git_dir: .git
+setup: worktree: (null)
+setup: cwd: $TRASH_DIRECTORY/20
+setup: prefix: (null)
+EOF
+ test_repo 20
+'
+
+test_expect_success '#20.2: in subdir' '
+ cat >20/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/20/.git
+setup: worktree: (null)
+setup: cwd: $TRASH_DIRECTORY/20/sub
+setup: prefix: (null)
+EOF
+ test_repo 20/sub
+'
+
+#
+# case #21.1
+#
+############################################################
+#
+# Input:
+#
+# - GIT_WORK_TREE is set
+# - GIT_DIR is not set
+# - core.worktree is set
+# - .git is a directory
+# - cwd is inside .git
+#
+# Output:
+#
+# GIT_WORK_TREE/core.worktree are ignored -> #20.1
+
+test_expect_success '#21.1: setup' '
+ unset GIT_DIR GIT_WORK_TREE &&
+ mkdir 21 21/sub &&
+ cd 21 &&
+ git init &&
+ git config core.worktree non-existent &&
+ GIT_WORK_TREE=non-existent-too &&
+ export GIT_WORK_TREE &&
+ mkdir .git/wt .git/wt/sub &&
+ cd ..
+'
+
+test_expect_success '#21.1: at .git' '
+ cat >21/.git/expected <<EOF &&
+setup: git_dir: .
+setup: worktree: (null)
+setup: cwd: $TRASH_DIRECTORY/21/.git
+setup: prefix: (null)
+EOF
+ test_repo 21/.git
+'
+
+test_expect_success '#21.1: in .git/wt' '
+ cat >21/.git/wt/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/21/.git
+setup: worktree: (null)
+setup: cwd: $TRASH_DIRECTORY/21/.git/wt
+setup: prefix: (null)
+EOF
+ test_repo 21/.git/wt
+'
+
+test_expect_success '#21.1: in .git/wt/sub' '
+ cat >21/.git/wt/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/21/.git
+setup: worktree: (null)
+setup: cwd: $TRASH_DIRECTORY/21/.git/wt/sub
+setup: prefix: (null)
+EOF
+ test_repo 21/.git/wt/sub
+'
+
+#
+# case #21.2
+#
+############################################################
+#
+# Input:
+#
+# - GIT_WORK_TREE is set
+# - GIT_DIR is not set
+# - core.worktree is set
+# - .git is a directory
+# - core.bare is set
+#
+# Output:
+#
+# GIT_WORK_TREE/core.worktree are ignored -> #20.2
+
+test_expect_success '#21.2: setup' '
+ git config --file="$TRASH_DIRECTORY/21/.git/config" core.bare true
+'
+
+test_expect_success '#21.2: at .git' '
+ cat >21/.git/expected <<EOF &&
+setup: git_dir: .
+setup: worktree: (null)
+setup: cwd: $TRASH_DIRECTORY/21/.git
+setup: prefix: (null)
+EOF
+ test_repo 21/.git
+'
+
+test_expect_success '#21.2: in .git/wt' '
+ cat >21/.git/wt/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/21/.git
+setup: worktree: (null)
+setup: cwd: $TRASH_DIRECTORY/21/.git/wt
+setup: prefix: (null)
+EOF
+ test_repo 21/.git/wt
+'
+
+test_expect_success '#21.2: in .git/wt/sub' '
+ cat >21/.git/wt/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/21/.git
+setup: worktree: (null)
+setup: cwd: $TRASH_DIRECTORY/21/.git/wt/sub
+setup: prefix: (null)
+EOF
+ test_repo 21/.git/wt/sub
+'
+
+test_expect_success '#21.2: at root' '
+ cat >21/expected <<EOF &&
+setup: git_dir: .git
+setup: worktree: (null)
+setup: cwd: $TRASH_DIRECTORY/21
+setup: prefix: (null)
+EOF
+ test_repo 21
+'
+
+test_expect_success '#21.2: in subdir' '
+ cat >21/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/21/.git
+setup: worktree: (null)
+setup: cwd: $TRASH_DIRECTORY/21/sub
+setup: prefix: (null)
+EOF
+ test_repo 21/sub
+'
+
+#
+# case #22.1
+#
+############################################################
+#
+# Input:
+#
+# - GIT_WORK_TREE is not set
+# - GIT_DIR is set
+# - core.worktree is set
+# - .git is a directory
+# - cwd is inside .git
+#
+# Output:
+#
+# bare attribute is ignored
+#
+# - worktree is at core.worktree
+# - cwd is at worktree root
+# - prefix is calculated
+# - git_dir is at $GIT_DIR
+# - cwd can be outside worktree
+
+test_expect_success '#22.1: setup' '
+ unset GIT_DIR GIT_WORK_TREE &&
+ mkdir 22 &&
+ cd 22 &&
+ git init &&
+ mkdir .git/sub .git/wt .git/wt/sub &&
+ cd ..
+'
+
+test_expect_success '#22.1: GIT_DIR(rel), core.worktree=. at .git' '
+ cat >22/.git/expected <<EOF &&
+setup: git_dir: .
+setup: worktree: $TRASH_DIRECTORY/22/.git
+setup: cwd: $TRASH_DIRECTORY/22/.git
+setup: prefix: (null)
+EOF
+ git config --file="$TRASH_DIRECTORY/22/.git/config" core.worktree "$TRASH_DIRECTORY/22/.git" &&
+ test_repo 22/.git .
+'
+
+test_expect_success '#22.1: GIT_DIR(rel), core.worktree=.(rel) at .git' '
+ cat >22/.git/expected <<EOF &&
+setup: git_dir: .
+setup: worktree: $TRASH_DIRECTORY/22/.git
+setup: cwd: $TRASH_DIRECTORY/22/.git
+setup: prefix: (null)
+EOF
+ git config --file="$TRASH_DIRECTORY/22/.git/config" core.worktree . &&
+ test_repo 22/.git .
+'
+
+test_expect_success '#22.1: GIT_DIR, core.worktree=. at .git' '
+ cat >22/.git/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/22/.git
+setup: worktree: $TRASH_DIRECTORY/22/.git
+setup: cwd: $TRASH_DIRECTORY/22/.git
+setup: prefix: (null)
+EOF
+ git config --file="$TRASH_DIRECTORY/22/.git/config" core.worktree "$TRASH_DIRECTORY/22/.git" &&
+ test_repo 22/.git "$TRASH_DIRECTORY/22/.git"
+'
+
+test_expect_success '#22.1: GIT_DIR, core.worktree=.(rel) at root' '
+ cat >22/.git/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/22/.git
+setup: worktree: $TRASH_DIRECTORY/22/.git
+setup: cwd: $TRASH_DIRECTORY/22/.git
+setup: prefix: (null)
+EOF
+ git config --file="$TRASH_DIRECTORY/22/.git/config" core.worktree . &&
+ test_repo 22/.git "$TRASH_DIRECTORY/22/.git"
+'
+
+test_expect_success '#22.1: GIT_DIR(rel), core.worktree=. in .git/sub' '
+ cat >22/.git/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/22/.git
+setup: worktree: $TRASH_DIRECTORY/22/.git
+setup: cwd: $TRASH_DIRECTORY/22/.git
+setup: prefix: sub/
+EOF
+ git config --file="$TRASH_DIRECTORY/22/.git/config" core.worktree "$TRASH_DIRECTORY/22/.git" &&
+ test_repo 22/.git/sub ..
+'
+
+test_expect_success '#22.1: GIT_DIR(rel), core.worktree=.(rel) in .git/sub' '
+ cat >22/.git/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/22/.git
+setup: worktree: $TRASH_DIRECTORY/22/.git
+setup: cwd: $TRASH_DIRECTORY/22/.git
+setup: prefix: sub/
+EOF
+ git config --file="$TRASH_DIRECTORY/22/.git/config" core.worktree . &&
+ test_repo 22/.git/sub/ ..
+'
+
+test_expect_success '#22.1: GIT_DIR, core.worktree=. in .git/sub' '
+ cat >22/.git/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/22/.git
+setup: worktree: $TRASH_DIRECTORY/22/.git
+setup: cwd: $TRASH_DIRECTORY/22/.git
+setup: prefix: sub/
+EOF
+ git config --file="$TRASH_DIRECTORY/22/.git/config" core.worktree "$TRASH_DIRECTORY/22/.git" &&
+ test_repo 22/.git/sub "$TRASH_DIRECTORY/22/.git"
+'
+
+test_expect_success '#22.1: GIT_DIR, core.worktree=.(rel) in .git/sub' '
+ cat >22/.git/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/22/.git
+setup: worktree: $TRASH_DIRECTORY/22/.git
+setup: cwd: $TRASH_DIRECTORY/22/.git
+setup: prefix: sub/
+EOF
+ git config --file="$TRASH_DIRECTORY/22/.git/config" core.worktree . &&
+ test_repo 22/.git/sub "$TRASH_DIRECTORY/22/.git"
+'
+
+test_expect_success '#22.1: GIT_DIR(rel), core.worktree=wt at .git' '
+ cat >22/.git/expected <<EOF &&
+setup: git_dir: .
+setup: worktree: $TRASH_DIRECTORY/22/.git/wt
+setup: cwd: $TRASH_DIRECTORY/22/.git
+setup: prefix: (null)
+EOF
+ git config --file="$TRASH_DIRECTORY/22/.git/config" core.worktree "$TRASH_DIRECTORY/22/.git/wt" &&
+ test_repo 22/.git .
+'
+
+test_expect_success '#22.1: GIT_DIR(rel), core.worktree=wt(rel) at .git' '
+ cat >22/.git/expected <<EOF &&
+setup: git_dir: .
+setup: worktree: $TRASH_DIRECTORY/22/.git/wt
+setup: cwd: $TRASH_DIRECTORY/22/.git
+setup: prefix: (null)
+EOF
+ git config --file="$TRASH_DIRECTORY/22/.git/config" core.worktree wt &&
+ test_repo 22/.git .
+'
+
+test_expect_success '#22.1: GIT_DIR, core.worktree=wt(rel) at .git' '
+ cat >22/.git/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/22/.git
+setup: worktree: $TRASH_DIRECTORY/22/.git/wt
+setup: cwd: $TRASH_DIRECTORY/22/.git
+setup: prefix: (null)
+EOF
+ git config --file="$TRASH_DIRECTORY/22/.git/config" core.worktree wt &&
+ test_repo 22/.git "$TRASH_DIRECTORY/22/.git"
+'
+
+test_expect_success '#22.1: GIT_DIR, core.worktree=wt at .git' '
+ cat >22/.git/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/22/.git
+setup: worktree: $TRASH_DIRECTORY/22/.git/wt
+setup: cwd: $TRASH_DIRECTORY/22/.git
+setup: prefix: (null)
+EOF
+ git config --file="$TRASH_DIRECTORY/22/.git/config" core.worktree "$TRASH_DIRECTORY/22/.git/wt" &&
+ test_repo 22/.git "$TRASH_DIRECTORY/22/.git"
+'
+
+test_expect_success '#22.1: GIT_DIR(rel), core.worktree=wt in .git/sub' '
+ cat >22/.git/sub/expected <<EOF &&
+setup: git_dir: ..
+setup: worktree: $TRASH_DIRECTORY/22/.git/wt
+setup: cwd: $TRASH_DIRECTORY/22/.git/sub
+setup: prefix: (null)
+EOF
+ git config --file="$TRASH_DIRECTORY/22/.git/config" core.worktree "$TRASH_DIRECTORY/22/.git/wt" &&
+ test_repo 22/.git/sub ..
+'
+
+test_expect_success '#22.1: GIT_DIR(rel), core.worktree=wt(rel) in .git/sub' '
+ cat >22/.git/sub/expected <<EOF &&
+setup: git_dir: ..
+setup: worktree: $TRASH_DIRECTORY/22/.git/wt
+setup: cwd: $TRASH_DIRECTORY/22/.git/sub
+setup: prefix: (null)
+EOF
+ git config --file="$TRASH_DIRECTORY/22/.git/config" core.worktree wt &&
+ test_repo 22/.git/sub ..
+'
+
+test_expect_success '#22.1: GIT_DIR, core.worktree=wt(rel) in .git/sub' '
+ cat >22/.git/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/22/.git
+setup: worktree: $TRASH_DIRECTORY/22/.git/wt
+setup: cwd: $TRASH_DIRECTORY/22/.git/sub
+setup: prefix: (null)
+EOF
+ git config --file="$TRASH_DIRECTORY/22/.git/config" core.worktree wt &&
+ test_repo 22/.git/sub "$TRASH_DIRECTORY/22/.git"
+'
+
+test_expect_success '#22.1: GIT_DIR, core.worktree=wt in .git/sub' '
+ cat >22/.git/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/22/.git
+setup: worktree: $TRASH_DIRECTORY/22/.git/wt
+setup: cwd: $TRASH_DIRECTORY/22/.git/sub
+setup: prefix: (null)
+EOF
+ git config --file="$TRASH_DIRECTORY/22/.git/config" core.worktree "$TRASH_DIRECTORY/22/.git/wt" &&
+ test_repo 22/.git/sub "$TRASH_DIRECTORY/22/.git"
+'
+
+test_expect_success '#22.1: GIT_DIR(rel), core.worktree=.. at .git' '
+ cat >22/.git/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/22/.git
+setup: worktree: $TRASH_DIRECTORY/22
+setup: cwd: $TRASH_DIRECTORY/22
+setup: prefix: .git/
+EOF
+ git config --file="$TRASH_DIRECTORY/22/.git/config" core.worktree "$TRASH_DIRECTORY/22" &&
+ test_repo 22/.git .
+'
+
+test_expect_success '#22.1: GIT_DIR(rel), core.worktree=..(rel) at .git' '
+ cat >22/.git/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/22/.git
+setup: worktree: $TRASH_DIRECTORY/22
+setup: cwd: $TRASH_DIRECTORY/22
+setup: prefix: .git/
+EOF
+ git config --file="$TRASH_DIRECTORY/22/.git/config" core.worktree .. &&
+ test_repo 22/.git .
+'
+
+test_expect_success '#22.1: GIT_DIR, core.worktree=..(rel) at .git' '
+ cat >22/.git/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/22/.git
+setup: worktree: $TRASH_DIRECTORY/22
+setup: cwd: $TRASH_DIRECTORY/22
+setup: prefix: .git/
+EOF
+ git config --file="$TRASH_DIRECTORY/22/.git/config" core.worktree .. &&
+ test_repo 22/.git "$TRASH_DIRECTORY/22/.git"
+'
+
+test_expect_success '#22.1: GIT_DIR, core.worktree=.. at .git' '
+ cat >22/.git/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/22/.git
+setup: worktree: $TRASH_DIRECTORY/22
+setup: cwd: $TRASH_DIRECTORY/22
+setup: prefix: .git/
+EOF
+ git config --file="$TRASH_DIRECTORY/22/.git/config" core.worktree "$TRASH_DIRECTORY/22" &&
+ test_repo 22/.git "$TRASH_DIRECTORY/22/.git"
+'
+
+test_expect_success '#22.1: GIT_DIR(rel), core.worktree=.. in .git/sub' '
+ cat >22/.git/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/22/.git
+setup: worktree: $TRASH_DIRECTORY/22
+setup: cwd: $TRASH_DIRECTORY/22
+setup: prefix: .git/sub/
+EOF
+ git config --file="$TRASH_DIRECTORY/22/.git/config" core.worktree "$TRASH_DIRECTORY/22" &&
+ test_repo 22/.git/sub ..
+'
+
+test_expect_success '#22.1: GIT_DIR(rel), core.worktree=..(rel) in .git/sub' '
+ cat >22/.git/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/22/.git
+setup: worktree: $TRASH_DIRECTORY/22
+setup: cwd: $TRASH_DIRECTORY/22
+setup: prefix: .git/sub/
+EOF
+ git config --file="$TRASH_DIRECTORY/22/.git/config" core.worktree .. &&
+ test_repo 22/.git/sub ..
+'
+
+test_expect_success '#22.1: GIT_DIR, core.worktree=..(rel) in .git/sub' '
+ cat >22/.git/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/22/.git
+setup: worktree: $TRASH_DIRECTORY/22
+setup: cwd: $TRASH_DIRECTORY/22
+setup: prefix: .git/sub/
+EOF
+ git config --file="$TRASH_DIRECTORY/22/.git/config" core.worktree .. &&
+ test_repo 22/.git/sub "$TRASH_DIRECTORY/22/.git"
+'
+
+test_expect_success '#22.1: GIT_DIR, core.worktree=.. in .git/sub' '
+ cat >22/.git/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/22/.git
+setup: worktree: $TRASH_DIRECTORY/22
+setup: cwd: $TRASH_DIRECTORY/22
+setup: prefix: .git/sub/
+EOF
+ git config --file="$TRASH_DIRECTORY/22/.git/config" core.worktree "$TRASH_DIRECTORY/22" &&
+ test_repo 22/.git/sub "$TRASH_DIRECTORY/22/.git"
+'
+
+#
+# case #22.2
+#
+############################################################
+#
+# Input:
+#
+# - GIT_WORK_TREE is not set
+# - GIT_DIR is set
+# - core.worktree is set
+# - .git is a directory
+# - core.bare is set
+#
+# Output:
+#
+# core.worktree and core.bare conflict, won't fly.
+
+test_expect_success '#22.2: setup' '
+ git config --file="$TRASH_DIRECTORY/22/.git/config" core.bare true
+'
+
+test_expect_success '#22.2: at .git' '
+ (
+ cd 22/.git &&
+ GIT_DIR=. &&
+ export GIT_DIR &&
+ test_must_fail git symbolic-ref HEAD 2>result &&
+ grep "core.bare and core.worktree do not make sense" result
+ )
+'
+
+test_expect_success '#22.2: at root' '
+ (
+ cd 22 &&
+ GIT_DIR=.git &&
+ export GIT_DIR &&
+ test_must_fail git symbolic-ref HEAD 2>result &&
+ grep "core.bare and core.worktree do not make sense" result
+ )
+'
+
+#
+# case #23
+#
+############################################################
+#
+# Input:
+#
+# - GIT_WORK_TREE is set
+# - GIT_DIR is set
+# - core.worktree is set
+# - .git is a directory
+# - core.bare is set
+#
+# Output:
+#
+# core.worktree is overridden by GIT_WORK_TREE -> #19
+
+test_expect_success '#23: setup' '
+ unset GIT_DIR GIT_WORK_TREE &&
+ mkdir 23 23/sub 23/sub/sub 23.wt 23.wt/sub 23/wt 23/wt/sub &&
+ cd 23 &&
+ git init &&
+ git config core.bare true &&
+ git config core.worktree non-existent &&
+ cd ..
+'
+
+test_expect_success '#23: GIT_DIR(rel), GIT_WORK_TREE=root at root' '
+ cat >23/expected <<EOF &&
+setup: git_dir: .git
+setup: worktree: $TRASH_DIRECTORY/23
+setup: cwd: $TRASH_DIRECTORY/23
+setup: prefix: (null)
+EOF
+ test_repo 23 .git "$TRASH_DIRECTORY/23"
+'
+
+test_expect_success '#23: GIT_DIR(rel), GIT_WORK_TREE=root(rel) at root' '
+ cat >23/expected <<EOF &&
+setup: git_dir: .git
+setup: worktree: $TRASH_DIRECTORY/23
+setup: cwd: $TRASH_DIRECTORY/23
+setup: prefix: (null)
+EOF
+ test_repo 23 .git .
+'
+
+test_expect_success '#23: GIT_DIR, GIT_WORK_TREE=root at root' '
+ cat >23/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/23/.git
+setup: worktree: $TRASH_DIRECTORY/23
+setup: cwd: $TRASH_DIRECTORY/23
+setup: prefix: (null)
+EOF
+ test_repo 23 "$TRASH_DIRECTORY/23/.git" "$TRASH_DIRECTORY/23"
+'
+
+test_expect_success '#23: GIT_DIR, GIT_WORK_TREE=root(rel) at root' '
+ cat >23/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/23/.git
+setup: worktree: $TRASH_DIRECTORY/23
+setup: cwd: $TRASH_DIRECTORY/23
+setup: prefix: (null)
+EOF
+ test_repo 23 "$TRASH_DIRECTORY/23/.git" .
+'
+
+test_expect_success '#23: GIT_DIR(rel), GIT_WORKTREE=root in subdir' '
+ cat >23/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/23/.git
+setup: worktree: $TRASH_DIRECTORY/23
+setup: cwd: $TRASH_DIRECTORY/23
+setup: prefix: sub/sub/
+EOF
+ test_repo 23/sub/sub ../../.git "$TRASH_DIRECTORY/23"
+'
+
+test_expect_success '#23: GIT_DIR(rel), GIT_WORKTREE=root(rel) in subdir' '
+ cat >23/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/23/.git
+setup: worktree: $TRASH_DIRECTORY/23
+setup: cwd: $TRASH_DIRECTORY/23
+setup: prefix: sub/sub/
+EOF
+ test_repo 23/sub/sub ../../.git ../..
+'
+
+test_expect_success '#23: GIT_DIR, GIT_WORKTREE=root in subdir' '
+ cat >23/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/23/.git
+setup: worktree: $TRASH_DIRECTORY/23
+setup: cwd: $TRASH_DIRECTORY/23
+setup: prefix: sub/
+EOF
+ test_repo 23/sub "$TRASH_DIRECTORY/23/.git" "$TRASH_DIRECTORY/23"
+'
+
+test_expect_success '#23: GIT_DIR, GIT_WORKTREE=root(rel) in subdir' '
+ cat >23/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/23/.git
+setup: worktree: $TRASH_DIRECTORY/23
+setup: cwd: $TRASH_DIRECTORY/23
+setup: prefix: sub/sub/
+EOF
+ test_repo 23/sub/sub "$TRASH_DIRECTORY/23/.git" ../..
+'
+
+test_expect_success '#23: GIT_DIR(rel), GIT_WORK_TREE=wt at root' '
+ cat >23/expected <<EOF &&
+setup: git_dir: .git
+setup: worktree: $TRASH_DIRECTORY/23/wt
+setup: cwd: $TRASH_DIRECTORY/23
+setup: prefix: (null)
+EOF
+ test_repo 23 .git "$TRASH_DIRECTORY/23/wt"
+'
+
+test_expect_success '#23: GIT_DIR(rel), GIT_WORK_TREE=wt(rel) at root' '
+ cat >23/expected <<EOF &&
+setup: git_dir: .git
+setup: worktree: $TRASH_DIRECTORY/23/wt
+setup: cwd: $TRASH_DIRECTORY/23
+setup: prefix: (null)
+EOF
+ test_repo 23 .git wt
+'
+
+test_expect_success '#23: GIT_DIR, GIT_WORK_TREE=wt(rel) at root' '
+ cat >23/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/23/.git
+setup: worktree: $TRASH_DIRECTORY/23/wt
+setup: cwd: $TRASH_DIRECTORY/23
+setup: prefix: (null)
+EOF
+ test_repo 23 "$TRASH_DIRECTORY/23/.git" wt
+'
+
+test_expect_success '#23: GIT_DIR, GIT_WORK_TREE=wt at root' '
+ cat >23/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/23/.git
+setup: worktree: $TRASH_DIRECTORY/23/wt
+setup: cwd: $TRASH_DIRECTORY/23
+setup: prefix: (null)
+EOF
+ test_repo 23 "$TRASH_DIRECTORY/23/.git" "$TRASH_DIRECTORY/23/wt"
+'
+
+test_expect_success '#23: GIT_DIR(rel), GIT_WORK_TREE=wt in subdir' '
+ cat >23/sub/sub/expected <<EOF &&
+setup: git_dir: ../../.git
+setup: worktree: $TRASH_DIRECTORY/23/wt
+setup: cwd: $TRASH_DIRECTORY/23/sub/sub
+setup: prefix: (null)
+EOF
+ test_repo 23/sub/sub ../../.git "$TRASH_DIRECTORY/23/wt"
+'
+
+test_expect_success '#23: GIT_DIR(rel), GIT_WORK_TREE=wt(rel) in subdir' '
+ cat >23/sub/sub/expected <<EOF &&
+setup: git_dir: ../../.git
+setup: worktree: $TRASH_DIRECTORY/23/wt
+setup: cwd: $TRASH_DIRECTORY/23/sub/sub
+setup: prefix: (null)
+EOF
+ test_repo 23/sub/sub ../../.git ../../wt
+'
+
+test_expect_success '#23: GIT_DIR, GIT_WORK_TREE=wt(rel) in subdir' '
+ cat >23/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/23/.git
+setup: worktree: $TRASH_DIRECTORY/23/wt
+setup: cwd: $TRASH_DIRECTORY/23/sub/sub
+setup: prefix: (null)
+EOF
+ test_repo 23/sub/sub "$TRASH_DIRECTORY/23/.git" ../../wt
+'
+
+test_expect_success '#23: GIT_DIR, GIT_WORK_TREE=wt in subdir' '
+ cat >23/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/23/.git
+setup: worktree: $TRASH_DIRECTORY/23/wt
+setup: cwd: $TRASH_DIRECTORY/23/sub/sub
+setup: prefix: (null)
+EOF
+ test_repo 23/sub/sub "$TRASH_DIRECTORY/23/.git" "$TRASH_DIRECTORY/23/wt"
+'
+
+test_expect_success '#23: GIT_DIR(rel), GIT_WORK_TREE=.. at root' '
+ cat >23/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/23/.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 23/
+EOF
+ test_repo 23 .git "$TRASH_DIRECTORY"
+'
+
+test_expect_success '#23: GIT_DIR(rel), GIT_WORK_TREE=..(rel) at root' '
+ cat >23/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/23/.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 23/
+EOF
+ test_repo 23 .git ..
+'
+
+test_expect_success '#23: GIT_DIR, GIT_WORK_TREE=..(rel) at root' '
+ cat >23/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/23/.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 23/
+EOF
+ test_repo 23 "$TRASH_DIRECTORY/23/.git" ..
+'
+
+test_expect_success '#23: GIT_DIR, GIT_WORK_TREE=.. at root' '
+ cat >23/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/23/.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 23/
+EOF
+ test_repo 23 "$TRASH_DIRECTORY/23/.git" "$TRASH_DIRECTORY"
+'
+
+test_expect_success '#23: GIT_DIR(rel), GIT_WORK_TREE=.. in subdir' '
+ cat >23/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/23/.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 23/sub/sub/
+EOF
+ test_repo 23/sub/sub ../../.git "$TRASH_DIRECTORY"
+'
+
+test_expect_success '#23: GIT_DIR(rel), GIT_WORK_TREE=..(rel) in subdir' '
+ cat >23/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/23/.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 23/sub/sub/
+EOF
+ test_repo 23/sub/sub ../../.git ../../..
+'
+
+test_expect_success '#23: GIT_DIR, GIT_WORK_TREE=..(rel) in subdir' '
+ cat >23/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/23/.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 23/sub/sub/
+EOF
+ test_repo 23/sub/sub "$TRASH_DIRECTORY/23/.git" ../../../
+'
+
+test_expect_success '#23: GIT_DIR, GIT_WORK_TREE=.. in subdir' '
+ cat >23/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/23/.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 23/sub/sub/
+EOF
+ test_repo 23/sub/sub "$TRASH_DIRECTORY/23/.git" "$TRASH_DIRECTORY"
+'
+
+#
+# case #24
+#
+############################################################
+#
+# Input:
+#
+# - GIT_WORK_TREE is not set
+# - GIT_DIR is not set
+# - core.worktree is not set
+# - .git is a file
+# - core.bare is set
+#
+# Output:
+#
+# #16.2 except git_dir is set according to .git file
+
+test_expect_success '#24: setup' '
+ unset GIT_DIR GIT_WORK_TREE &&
+ mkdir 24 24/sub &&
+ cd 24 &&
+ git init &&
+ git config core.bare true &&
+ mv .git ../24.git &&
+ echo gitdir: ../24.git >.git &&
+ cd ..
+'
+
+test_expect_success '#24: at root' '
+ cat >24/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/24.git
+setup: worktree: (null)
+setup: cwd: $TRASH_DIRECTORY/24
+setup: prefix: (null)
+EOF
+ test_repo 24
+'
+
+test_expect_success '#24: in subdir' '
+ cat >24/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/24.git
+setup: worktree: (null)
+setup: cwd: $TRASH_DIRECTORY/24/sub
+setup: prefix: (null)
+EOF
+ test_repo 24/sub
+'
+
+#
+# case #25
+#
+############################################################
+#
+# Input:
+#
+# - GIT_WORK_TREE is set
+# - GIT_DIR is not set
+# - core.worktree is not set
+# - .git is a file
+# - core.bare is set
+#
+# Output:
+#
+# #17.2 except git_dir is set according to .git file
+
+test_expect_success '#25: setup' '
+ unset GIT_DIR GIT_WORK_TREE &&
+ mkdir 25 25/sub &&
+ cd 25 &&
+ git init &&
+ git config core.bare true &&
+ GIT_WORK_TREE=non-existent &&
+ export GIT_WORK_TREE &&
+ mv .git ../25.git &&
+ echo gitdir: ../25.git >.git &&
+ cd ..
+'
+
+test_expect_success '#25: at root' '
+ cat >25/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/25.git
+setup: worktree: (null)
+setup: cwd: $TRASH_DIRECTORY/25
+setup: prefix: (null)
+EOF
+ test_repo 25
+'
+
+test_expect_success '#25: in subdir' '
+ cat >25/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/25.git
+setup: worktree: (null)
+setup: cwd: $TRASH_DIRECTORY/25/sub
+setup: prefix: (null)
+EOF
+ test_repo 25/sub
+'
+
+#
+# case #26
+#
+############################################################
+#
+# Input:
+#
+# - GIT_WORK_TREE is not set
+# - GIT_DIR is set
+# - core.worktree is not set
+# - .git is a file
+# - core.bare is set
+#
+# Output:
+#
+# #18 except git_dir is set according to .git file
+
+test_expect_success '#26: setup' '
+ unset GIT_DIR GIT_WORK_TREE &&
+ mkdir 26 26/sub &&
+ cd 26 &&
+ git init &&
+ git config core.bare true &&
+ mv .git ../26.git &&
+ echo gitdir: ../26.git >.git &&
+ cd ..
+'
+
+test_expect_success '#26: (rel) at root' '
+ cat >26/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/26.git
+setup: worktree: (null)
+setup: cwd: $TRASH_DIRECTORY/26
+setup: prefix: (null)
+EOF
+ test_repo 26 .git
+'
+
+test_expect_success '#26: at root' '
+ cat >26/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/26.git
+setup: worktree: (null)
+setup: cwd: $TRASH_DIRECTORY/26
+setup: prefix: (null)
+EOF
+ test_repo 26 "$TRASH_DIRECTORY/26/.git"
+'
+
+test_expect_success '#26: (rel) in subdir' '
+ cat >26/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/26.git
+setup: worktree: (null)
+setup: cwd: $TRASH_DIRECTORY/26/sub
+setup: prefix: (null)
+EOF
+ test_repo 26/sub ../.git
+'
+
+test_expect_success '#26: in subdir' '
+ cat >26/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/26.git
+setup: worktree: (null)
+setup: cwd: $TRASH_DIRECTORY/26/sub
+setup: prefix: (null)
+EOF
+ test_repo 26/sub "$TRASH_DIRECTORY/26/.git"
+'
+
+#
+# case #27
+#
+############################################################
+#
+# Input:
+#
+# - GIT_WORK_TREE is set
+# - GIT_DIR is set
+# - .git is a file
+# - core.worktree is not set
+# - core.bare is set
+#
+# Output:
+#
+# #19 except git_dir is set according to .git file
+
+test_expect_success '#27: setup' '
+ unset GIT_DIR GIT_WORK_TREE &&
+ mkdir 27 27/sub 27/sub/sub 27.wt 27.wt/sub 27/wt 27/wt/sub &&
+ cd 27 &&
+ git init &&
+ git config core.bare true &&
+ mv .git ../27.git &&
+ echo gitdir: ../27.git >.git &&
+ cd ..
+'
+
+test_expect_success '#27: GIT_DIR(rel), GIT_WORK_TREE=root at root' '
+ cat >27/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/27.git
+setup: worktree: $TRASH_DIRECTORY/27
+setup: cwd: $TRASH_DIRECTORY/27
+setup: prefix: (null)
+EOF
+ test_repo 27 .git "$TRASH_DIRECTORY/27"
+'
+
+test_expect_success '#27: GIT_DIR(rel), GIT_WORK_TREE=root(rel) at root' '
+ cat >27/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/27.git
+setup: worktree: $TRASH_DIRECTORY/27
+setup: cwd: $TRASH_DIRECTORY/27
+setup: prefix: (null)
+EOF
+ test_repo 27 .git .
+'
+
+test_expect_success '#27: GIT_DIR, GIT_WORK_TREE=root at root' '
+ cat >27/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/27.git
+setup: worktree: $TRASH_DIRECTORY/27
+setup: cwd: $TRASH_DIRECTORY/27
+setup: prefix: (null)
+EOF
+ test_repo 27 "$TRASH_DIRECTORY/27/.git" "$TRASH_DIRECTORY/27"
+'
+
+test_expect_success '#27: GIT_DIR, GIT_WORK_TREE=root(rel) at root' '
+ cat >27/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/27.git
+setup: worktree: $TRASH_DIRECTORY/27
+setup: cwd: $TRASH_DIRECTORY/27
+setup: prefix: (null)
+EOF
+ test_repo 27 "$TRASH_DIRECTORY/27/.git" .
+'
+
+test_expect_success '#27: GIT_DIR(rel), GIT_WORKTREE=root in subdir' '
+ cat >27/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/27.git
+setup: worktree: $TRASH_DIRECTORY/27
+setup: cwd: $TRASH_DIRECTORY/27
+setup: prefix: sub/sub/
+EOF
+ test_repo 27/sub/sub ../../.git "$TRASH_DIRECTORY/27"
+'
+
+test_expect_success '#27: GIT_DIR(rel), GIT_WORKTREE=root(rel) in subdir' '
+ cat >27/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/27.git
+setup: worktree: $TRASH_DIRECTORY/27
+setup: cwd: $TRASH_DIRECTORY/27
+setup: prefix: sub/sub/
+EOF
+ test_repo 27/sub/sub ../../.git ../..
+'
+
+test_expect_success '#27: GIT_DIR, GIT_WORKTREE=root in subdir' '
+ cat >27/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/27.git
+setup: worktree: $TRASH_DIRECTORY/27
+setup: cwd: $TRASH_DIRECTORY/27
+setup: prefix: sub/
+EOF
+ test_repo 27/sub "$TRASH_DIRECTORY/27/.git" "$TRASH_DIRECTORY/27"
+'
+
+test_expect_success '#27: GIT_DIR, GIT_WORKTREE=root(rel) in subdir' '
+ cat >27/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/27.git
+setup: worktree: $TRASH_DIRECTORY/27
+setup: cwd: $TRASH_DIRECTORY/27
+setup: prefix: sub/sub/
+EOF
+ test_repo 27/sub/sub "$TRASH_DIRECTORY/27/.git" ../..
+'
+
+test_expect_success '#27: GIT_DIR(rel), GIT_WORK_TREE=wt at root' '
+ cat >27/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/27.git
+setup: worktree: $TRASH_DIRECTORY/27/wt
+setup: cwd: $TRASH_DIRECTORY/27
+setup: prefix: (null)
+EOF
+ test_repo 27 .git "$TRASH_DIRECTORY/27/wt"
+'
+
+test_expect_success '#27: GIT_DIR(rel), GIT_WORK_TREE=wt(rel) at root' '
+ cat >27/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/27.git
+setup: worktree: $TRASH_DIRECTORY/27/wt
+setup: cwd: $TRASH_DIRECTORY/27
+setup: prefix: (null)
+EOF
+ test_repo 27 .git wt
+'
+
+test_expect_success '#27: GIT_DIR, GIT_WORK_TREE=wt(rel) at root' '
+ cat >27/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/27.git
+setup: worktree: $TRASH_DIRECTORY/27/wt
+setup: cwd: $TRASH_DIRECTORY/27
+setup: prefix: (null)
+EOF
+ test_repo 27 "$TRASH_DIRECTORY/27/.git" wt
+'
+
+test_expect_success '#27: GIT_DIR, GIT_WORK_TREE=wt at root' '
+ cat >27/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/27.git
+setup: worktree: $TRASH_DIRECTORY/27/wt
+setup: cwd: $TRASH_DIRECTORY/27
+setup: prefix: (null)
+EOF
+ test_repo 27 "$TRASH_DIRECTORY/27/.git" "$TRASH_DIRECTORY/27/wt"
+'
+
+test_expect_success '#27: GIT_DIR(rel), GIT_WORK_TREE=wt in subdir' '
+ cat >27/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/27.git
+setup: worktree: $TRASH_DIRECTORY/27/wt
+setup: cwd: $TRASH_DIRECTORY/27/sub/sub
+setup: prefix: (null)
+EOF
+ test_repo 27/sub/sub ../../.git "$TRASH_DIRECTORY/27/wt"
+'
+
+test_expect_success '#27: GIT_DIR(rel), GIT_WORK_TREE=wt(rel) in subdir' '
+ cat >27/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/27.git
+setup: worktree: $TRASH_DIRECTORY/27/wt
+setup: cwd: $TRASH_DIRECTORY/27/sub/sub
+setup: prefix: (null)
+EOF
+ test_repo 27/sub/sub ../../.git ../../wt
+'
+
+test_expect_success '#27: GIT_DIR, GIT_WORK_TREE=wt(rel) in subdir' '
+ cat >27/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/27.git
+setup: worktree: $TRASH_DIRECTORY/27/wt
+setup: cwd: $TRASH_DIRECTORY/27/sub/sub
+setup: prefix: (null)
+EOF
+ test_repo 27/sub/sub "$TRASH_DIRECTORY/27/.git" ../../wt
+'
+
+test_expect_success '#27: GIT_DIR, GIT_WORK_TREE=wt in subdir' '
+ cat >27/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/27.git
+setup: worktree: $TRASH_DIRECTORY/27/wt
+setup: cwd: $TRASH_DIRECTORY/27/sub/sub
+setup: prefix: (null)
+EOF
+ test_repo 27/sub/sub "$TRASH_DIRECTORY/27/.git" "$TRASH_DIRECTORY/27/wt"
+'
+
+test_expect_success '#27: GIT_DIR(rel), GIT_WORK_TREE=.. at root' '
+ cat >27/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/27.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 27/
+EOF
+ test_repo 27 .git "$TRASH_DIRECTORY"
+'
+
+test_expect_success '#27: GIT_DIR(rel), GIT_WORK_TREE=..(rel) at root' '
+ cat >27/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/27.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 27/
+EOF
+ test_repo 27 .git ..
+'
+
+test_expect_success '#27: GIT_DIR, GIT_WORK_TREE=..(rel) at root' '
+ cat >27/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/27.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 27/
+EOF
+ test_repo 27 "$TRASH_DIRECTORY/27/.git" ..
+'
+
+test_expect_success '#27: GIT_DIR, GIT_WORK_TREE=.. at root' '
+ cat >27/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/27.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 27/
+EOF
+ test_repo 27 "$TRASH_DIRECTORY/27/.git" "$TRASH_DIRECTORY"
+'
+
+test_expect_success '#27: GIT_DIR(rel), GIT_WORK_TREE=.. in subdir' '
+ cat >27/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/27.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 27/sub/sub/
+EOF
+ test_repo 27/sub/sub ../../.git "$TRASH_DIRECTORY"
+'
+
+test_expect_success '#27: GIT_DIR(rel), GIT_WORK_TREE=..(rel) in subdir' '
+ cat >27/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/27.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 27/sub/sub/
+EOF
+ test_repo 27/sub/sub ../../.git ../../..
+'
+
+test_expect_success '#27: GIT_DIR, GIT_WORK_TREE=..(rel) in subdir' '
+ cat >27/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/27.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 27/sub/sub/
+EOF
+ test_repo 27/sub/sub "$TRASH_DIRECTORY/27/.git" ../../../
+'
+
+test_expect_success '#27: GIT_DIR, GIT_WORK_TREE=.. in subdir' '
+ cat >27/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/27.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 27/sub/sub/
+EOF
+ test_repo 27/sub/sub "$TRASH_DIRECTORY/27/.git" "$TRASH_DIRECTORY"
+'
+
+#
+# case #28
+#
+############################################################
+#
+# Input:
+#
+# - GIT_WORK_TREE is not set
+# - GIT_DIR is not set
+# - core.worktree is set
+# - .git is a file
+# - core.bare is set
+#
+# Output:
+#
+# core.worktree is ignored -> #24
+
+test_expect_success '#28: setup' '
+ unset GIT_DIR GIT_WORK_TREE &&
+ mkdir 28 28/sub &&
+ cd 28 &&
+ git init &&
+ git config core.bare true &&
+ git config core.worktree non-existent &&
+ mv .git ../28.git &&
+ echo gitdir: ../28.git >.git &&
+ cd ..
+'
+
+test_expect_success '#28: at root' '
+ cat >28/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/28.git
+setup: worktree: (null)
+setup: cwd: $TRASH_DIRECTORY/28
+setup: prefix: (null)
+EOF
+ test_repo 28
+'
+
+test_expect_success '#28: in subdir' '
+ cat >28/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/28.git
+setup: worktree: (null)
+setup: cwd: $TRASH_DIRECTORY/28/sub
+setup: prefix: (null)
+EOF
+ test_repo 28/sub
+'
+
+#
+# case #29
+#
+############################################################
+#
+# Input:
+#
+# - GIT_WORK_TREE is set
+# - GIT_DIR is not set
+# - core.worktree is set
+# - .git is a file
+# - core.bare is set
+#
+# Output:
+#
+# GIT_WORK_TREE/core.worktree are ignored -> #28
+
+test_expect_success '#29: setup' '
+ unset GIT_DIR GIT_WORK_TREE &&
+ mkdir 29 29/sub &&
+ cd 29 &&
+ git init &&
+ git config core.bare true &&
+ GIT_WORK_TREE=non-existent &&
+ export GIT_WORK_TREE &&
+ mv .git ../29.git &&
+ echo gitdir: ../29.git >.git &&
+ cd ..
+'
+
+test_expect_success '#29: at root' '
+ cat >29/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/29.git
+setup: worktree: (null)
+setup: cwd: $TRASH_DIRECTORY/29
+setup: prefix: (null)
+EOF
+ test_repo 29
+'
+
+test_expect_success '#29: in subdir' '
+ cat >29/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/29.git
+setup: worktree: (null)
+setup: cwd: $TRASH_DIRECTORY/29/sub
+setup: prefix: (null)
+EOF
+ test_repo 29/sub
+'
+
+#
+# case #30
+#
+############################################################
+#
+# Input:
+#
+# - GIT_WORK_TREE is not set
+# - GIT_DIR is set
+# - core.worktree is set
+# - .git is a file
+# - core.bare is set
+#
+# Output:
+#
+# core.worktree and core.bare conflict, won't fly.
+
+test_expect_success '#30: setup' '
+ unset GIT_DIR GIT_WORK_TREE &&
+ mkdir 30 &&
+ cd 30 &&
+ git init &&
+ git config core.bare true &&
+ git config core.worktree non-existent &&
+ mv .git ../30.git &&
+ echo gitdir: ../30.git >.git &&
+ cd ..
+'
+
+test_expect_success '#30: at root' '
+ (
+ cd 30 &&
+ GIT_DIR=.git &&
+ export GIT_DIR &&
+ test_must_fail git symbolic-ref HEAD 2>result &&
+ grep "core.bare and core.worktree do not make sense" result
+ )
+'
+
+#
+# case #31
+#
+############################################################
+#
+# Input:
+#
+# - GIT_WORK_TREE is set
+# - GIT_DIR is set
+# - core.worktree is set
+# - .git is a file
+# - core.bare is set
+#
+# Output:
+#
+# #23 except git_dir is set according to .git file
+
+test_expect_success '#31: setup' '
+ unset GIT_DIR GIT_WORK_TREE &&
+ mkdir 31 31/sub 31/sub/sub 31.wt 31.wt/sub 31/wt 31/wt/sub &&
+ cd 31 &&
+ git init &&
+ git config core.bare true &&
+ git config core.worktree non-existent &&
+ mv .git ../31.git &&
+ echo gitdir: ../31.git >.git &&
+ cd ..
+'
+
+test_expect_success '#31: GIT_DIR(rel), GIT_WORK_TREE=root at root' '
+ cat >31/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/31.git
+setup: worktree: $TRASH_DIRECTORY/31
+setup: cwd: $TRASH_DIRECTORY/31
+setup: prefix: (null)
+EOF
+ test_repo 31 .git "$TRASH_DIRECTORY/31"
+'
+
+test_expect_success '#31: GIT_DIR(rel), GIT_WORK_TREE=root(rel) at root' '
+ cat >31/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/31.git
+setup: worktree: $TRASH_DIRECTORY/31
+setup: cwd: $TRASH_DIRECTORY/31
+setup: prefix: (null)
+EOF
+ test_repo 31 .git .
+'
+
+test_expect_success '#31: GIT_DIR, GIT_WORK_TREE=root at root' '
+ cat >31/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/31.git
+setup: worktree: $TRASH_DIRECTORY/31
+setup: cwd: $TRASH_DIRECTORY/31
+setup: prefix: (null)
+EOF
+ test_repo 31 "$TRASH_DIRECTORY/31/.git" "$TRASH_DIRECTORY/31"
+'
+
+test_expect_success '#31: GIT_DIR, GIT_WORK_TREE=root(rel) at root' '
+ cat >31/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/31.git
+setup: worktree: $TRASH_DIRECTORY/31
+setup: cwd: $TRASH_DIRECTORY/31
+setup: prefix: (null)
+EOF
+ test_repo 31 "$TRASH_DIRECTORY/31/.git" .
+'
+
+test_expect_success '#31: GIT_DIR(rel), GIT_WORKTREE=root in subdir' '
+ cat >31/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/31.git
+setup: worktree: $TRASH_DIRECTORY/31
+setup: cwd: $TRASH_DIRECTORY/31
+setup: prefix: sub/sub/
+EOF
+ test_repo 31/sub/sub ../../.git "$TRASH_DIRECTORY/31"
+'
+
+test_expect_success '#31: GIT_DIR(rel), GIT_WORKTREE=root(rel) in subdir' '
+ cat >31/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/31.git
+setup: worktree: $TRASH_DIRECTORY/31
+setup: cwd: $TRASH_DIRECTORY/31
+setup: prefix: sub/sub/
+EOF
+ test_repo 31/sub/sub ../../.git ../..
+'
+
+test_expect_success '#31: GIT_DIR, GIT_WORKTREE=root in subdir' '
+ cat >31/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/31.git
+setup: worktree: $TRASH_DIRECTORY/31
+setup: cwd: $TRASH_DIRECTORY/31
+setup: prefix: sub/
+EOF
+ test_repo 31/sub "$TRASH_DIRECTORY/31/.git" "$TRASH_DIRECTORY/31"
+'
+
+test_expect_success '#31: GIT_DIR, GIT_WORKTREE=root(rel) in subdir' '
+ cat >31/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/31.git
+setup: worktree: $TRASH_DIRECTORY/31
+setup: cwd: $TRASH_DIRECTORY/31
+setup: prefix: sub/sub/
+EOF
+ test_repo 31/sub/sub "$TRASH_DIRECTORY/31/.git" ../..
+'
+
+test_expect_success '#31: GIT_DIR(rel), GIT_WORK_TREE=wt at root' '
+ cat >31/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/31.git
+setup: worktree: $TRASH_DIRECTORY/31/wt
+setup: cwd: $TRASH_DIRECTORY/31
+setup: prefix: (null)
+EOF
+ test_repo 31 .git "$TRASH_DIRECTORY/31/wt"
+'
+
+test_expect_success '#31: GIT_DIR(rel), GIT_WORK_TREE=wt(rel) at root' '
+ cat >31/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/31.git
+setup: worktree: $TRASH_DIRECTORY/31/wt
+setup: cwd: $TRASH_DIRECTORY/31
+setup: prefix: (null)
+EOF
+ test_repo 31 .git wt
+'
+
+test_expect_success '#31: GIT_DIR, GIT_WORK_TREE=wt(rel) at root' '
+ cat >31/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/31.git
+setup: worktree: $TRASH_DIRECTORY/31/wt
+setup: cwd: $TRASH_DIRECTORY/31
+setup: prefix: (null)
+EOF
+ test_repo 31 "$TRASH_DIRECTORY/31/.git" wt
+'
+
+test_expect_success '#31: GIT_DIR, GIT_WORK_TREE=wt at root' '
+ cat >31/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/31.git
+setup: worktree: $TRASH_DIRECTORY/31/wt
+setup: cwd: $TRASH_DIRECTORY/31
+setup: prefix: (null)
+EOF
+ test_repo 31 "$TRASH_DIRECTORY/31/.git" "$TRASH_DIRECTORY/31/wt"
+'
+
+test_expect_success '#31: GIT_DIR(rel), GIT_WORK_TREE=wt in subdir' '
+ cat >31/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/31.git
+setup: worktree: $TRASH_DIRECTORY/31/wt
+setup: cwd: $TRASH_DIRECTORY/31/sub/sub
+setup: prefix: (null)
+EOF
+ test_repo 31/sub/sub ../../.git "$TRASH_DIRECTORY/31/wt"
+'
+
+test_expect_success '#31: GIT_DIR(rel), GIT_WORK_TREE=wt(rel) in subdir' '
+ cat >31/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/31.git
+setup: worktree: $TRASH_DIRECTORY/31/wt
+setup: cwd: $TRASH_DIRECTORY/31/sub/sub
+setup: prefix: (null)
+EOF
+ test_repo 31/sub/sub ../../.git ../../wt
+'
+
+test_expect_success '#31: GIT_DIR, GIT_WORK_TREE=wt(rel) in subdir' '
+ cat >31/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/31.git
+setup: worktree: $TRASH_DIRECTORY/31/wt
+setup: cwd: $TRASH_DIRECTORY/31/sub/sub
+setup: prefix: (null)
+EOF
+ test_repo 31/sub/sub "$TRASH_DIRECTORY/31/.git" ../../wt
+'
+
+test_expect_success '#31: GIT_DIR, GIT_WORK_TREE=wt in subdir' '
+ cat >31/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/31.git
+setup: worktree: $TRASH_DIRECTORY/31/wt
+setup: cwd: $TRASH_DIRECTORY/31/sub/sub
+setup: prefix: (null)
+EOF
+ test_repo 31/sub/sub "$TRASH_DIRECTORY/31/.git" "$TRASH_DIRECTORY/31/wt"
+'
+
+test_expect_success '#31: GIT_DIR(rel), GIT_WORK_TREE=.. at root' '
+ cat >31/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/31.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 31/
+EOF
+ test_repo 31 .git "$TRASH_DIRECTORY"
+'
+
+test_expect_success '#31: GIT_DIR(rel), GIT_WORK_TREE=..(rel) at root' '
+ cat >31/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/31.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 31/
+EOF
+ test_repo 31 .git ..
+'
+
+test_expect_success '#31: GIT_DIR, GIT_WORK_TREE=..(rel) at root' '
+ cat >31/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/31.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 31/
+EOF
+ test_repo 31 "$TRASH_DIRECTORY/31/.git" ..
+'
+
+test_expect_success '#31: GIT_DIR, GIT_WORK_TREE=.. at root' '
+ cat >31/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/31.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 31/
+EOF
+ test_repo 31 "$TRASH_DIRECTORY/31/.git" "$TRASH_DIRECTORY"
+'
+
+test_expect_success '#31: GIT_DIR(rel), GIT_WORK_TREE=.. in subdir' '
+ cat >31/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/31.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 31/sub/sub/
+EOF
+ test_repo 31/sub/sub ../../.git "$TRASH_DIRECTORY"
+'
+
+test_expect_success '#31: GIT_DIR(rel), GIT_WORK_TREE=..(rel) in subdir' '
+ cat >31/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/31.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 31/sub/sub/
+EOF
+ test_repo 31/sub/sub ../../.git ../../..
+'
+
+test_expect_success '#31: GIT_DIR, GIT_WORK_TREE=..(rel) in subdir' '
+ cat >31/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/31.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 31/sub/sub/
+EOF
+ test_repo 31/sub/sub "$TRASH_DIRECTORY/31/.git" ../../../
+'
+
+test_expect_success '#31: GIT_DIR, GIT_WORK_TREE=.. in subdir' '
+ cat >31/sub/sub/expected <<EOF &&
+setup: git_dir: $TRASH_DIRECTORY/31.git
+setup: worktree: $TRASH_DIRECTORY
+setup: cwd: $TRASH_DIRECTORY
+setup: prefix: 31/sub/sub/
+EOF
+ test_repo 31/sub/sub "$TRASH_DIRECTORY/31/.git" "$TRASH_DIRECTORY"
+'
+
+test_done
diff --git a/test-subprocess.c b/test-subprocess.c
new file mode 100644
index 0000000000..667d3e5079
--- /dev/null
+++ b/test-subprocess.c
@@ -0,0 +1,21 @@
+#include "cache.h"
+#include "run-command.h"
+
+int main(int argc, char **argv)
+{
+ const char *prefix;
+ struct child_process cp;
+ int nogit = 0;
+
+ prefix = setup_git_directory_gently(&nogit);
+ if (nogit)
+ die("No git repo found");
+ if (!strcmp(argv[1], "--setup-work-tree")) {
+ setup_work_tree();
+ argv++;
+ }
+ memset(&cp, 0, sizeof(cp));
+ cp.git_cmd = 1;
+ cp.argv = (const char **)argv+1;
+ return run_command(&cp);
+}
diff --git a/trace.c b/trace.c
index 0fb2a2c64b..02279b82c4 100644
--- a/trace.c
+++ b/trace.c
@@ -127,3 +127,45 @@ void trace_argv_printf(const char **argv, const char *fmt, ...)
if (need_close)
close(fd);
}
+
+static const char *quote_crnl(const char *path)
+{
+ static char new_path[PATH_MAX];
+ const char *p2 = path;
+ char *p1 = new_path;
+
+ if (!path)
+ return NULL;
+
+ while (*p2) {
+ switch (*p2) {
+ case '\\': *p1++ = '\\'; *p1++ = '\\'; break;
+ case '\n': *p1++ = '\\'; *p1++ = 'n'; break;
+ case '\r': *p1++ = '\\'; *p1++ = 'r'; break;
+ default:
+ *p1++ = *p2;
+ }
+ p2++;
+ }
+ *p1 = '\0';
+ return new_path;
+}
+
+/* FIXME: move prefix to startup_info struct and get rid of this arg */
+void trace_repo_setup(const char *prefix)
+{
+ char cwd[PATH_MAX];
+ char *trace = getenv("GIT_TRACE");
+
+ if (!trace || !strcmp(trace, "") ||
+ !strcmp(trace, "0") || !strcasecmp(trace, "false"))
+ return;
+
+ if (!getcwd(cwd, PATH_MAX))
+ die("Unable to get current working directory");
+
+ trace_printf("setup: git_dir: %s\n", quote_crnl(get_git_dir()));
+ trace_printf("setup: worktree: %s\n", quote_crnl(get_git_work_tree()));
+ trace_printf("setup: cwd: %s\n", quote_crnl(cwd));
+ trace_printf("setup: prefix: %s\n", quote_crnl(prefix));
+}