Merge branch 'as/userdiff-pascal'

* as/userdiff-pascal:
  userdiff: match Pascal class methods
diff --git a/Documentation/RelNotes/1.7.4.txt b/Documentation/RelNotes/1.7.4.txt
index 055c1ca..84d0e1d 100644
--- a/Documentation/RelNotes/1.7.4.txt
+++ b/Documentation/RelNotes/1.7.4.txt
@@ -15,7 +15,7 @@
    themselves.  The name of a branch cannot begin with a dash now.
 
  * System-wide fallback default attributes can be stored in
-   /etc/gitattributes; core.attributesfile configuration variable can
+   /etc/gitattributes; the core.attributesfile configuration variable can
    be used to customize the path to this file.
 
  * The thread structure generated by "git send-email" has changed
@@ -25,39 +25,39 @@
    cover letter of the previous series; this has been changed to make
    the patches in the new series replies to the new cover letter.
 
- * Bash completion script in contrib/ has been adjusted to be usable with
-   Bash 4 (options with '=value' didn't complete)  It has been also made
+ * The Bash completion script in contrib/ has been adjusted to be usable with
+   Bash 4 (options with '=value' didn't complete).  It has been also made
    usable with zsh.
 
  * Different pagers can be chosen depending on which subcommand is
-   being run under the pager, using "pager.<subcommand>" variable.
+   being run under the pager, using the "pager.<subcommand>" variable.
 
- * The hardcoded tab-width of 8 used in whitespace breakage checks is now
+ * The hardcoded tab-width of 8 that is used in whitespace breakage checks is now
    configurable via the attributes mechanism.
 
  * Support of case insensitive filesystems (i.e. "core.ignorecase") has
    been improved.  For example, the gitignore mechanism didn't pay attention
-   to the case insensitivity.
+   to case insensitivity.
 
- * The <tree>:<path> syntax to name a blob in a tree, and :<path>
-   syntax to name a blob in the index (e.g. "master:Makefile",
+ * The <tree>:<path> syntax for naming a blob in a tree, and the :<path>
+   syntax for naming a blob in the index (e.g. "master:Makefile",
    ":hello.c") have been extended.  You can start <path> with "./" to
    implicitly have the (sub)directory you are in prefixed to the
    lookup.  Similarly, ":../Makefile" from a subdirectory would mean
    "the Makefile of the parent directory in the index".
 
- * "git blame" learned --show-email option to display the e-mail
+ * "git blame" learned the --show-email option to display the e-mail
    addresses instead of the names of authors.
 
- * "git commit" learned --fixup and --squash options to help later invocation
-   of the interactive rebase.
+ * "git commit" learned the --fixup and --squash options to help later invocation
+   of interactive rebase.
 
  * Command line options to "git cvsimport" whose names are in capital
    letters (-A, -M, -R and -S) can now be specified as the default in
    the .git/config file by their longer names (cvsimport.authorsFile,
    cvsimport.mergeRegex, cvsimport.trackRevisions, cvsimport.ignorePaths).
 
- * "git daemon" can be built in MinGW environment.
+ * "git daemon" can be built in the MinGW environment.
 
  * "git daemon" can take more than one --listen option to listen to
    multiple addresses.
@@ -65,13 +65,13 @@
  * "git describe --exact-match" was optimized not to read commit
    objects unnecessarily.
 
- * "git diff" and "git grep" learned how functions and subroutines
-   in Fortran look like.
+ * "git diff" and "git grep" learned what functions and subroutines
+   in Fortran and Perl look like.
 
- * "git fetch" learned "--recurse-submodules" option.
+ * "git fetch" learned the "--recurse-submodules" option.
 
- * "git mergetool" tells vim/gvim to show three-way diff by default
-   (use vimdiff2/gvimdiff2 as the tool name for old behaviour).
+ * "git mergetool" tells vim/gvim to show a three-way diff by default
+   (use vimdiff2/gvimdiff2 as the tool name for old behavior).
 
  * "git log -G<pattern>" limits the output to commits whose change has
    added or deleted lines that match the given pattern.
@@ -91,12 +91,20 @@
    directory in one branch while a new file is created in place of that
    directory in the other branch.
 
- * "git rebase --autosquash" can use SHA-1 object names to name which
-   commit to fix up (e.g. "fixup! e83c5163").
+ * "git merge" learned the "--abort" option, synonymous to
+   "git reset --merge" when a merge is in progress.
 
- * The default "recursive" merge strategy learned --rename-threshold
+ * "git notes" learned the "merge" subcommand to merge notes refs.
+   In addition to the default manual conflict resolution, there are
+   also several notes merge strategies for automatically resolving
+   notes merge conflicts.
+
+ * "git rebase --autosquash" can use SHA-1 object names to name the
+   commit which is to be fixed up (e.g. "fixup! e83c5163").
+
+ * The default "recursive" merge strategy learned the --rename-threshold
    option to influence the rename detection, similar to the -M option
-   of "git diff".  From "git merge" frontend, "-X<strategy option>"
+   of "git diff".  From the "git merge" frontend, the "-X<strategy option>"
    interface, e.g. "git merge -Xrename-threshold=50% ...", can be used
    to trigger this.
 
@@ -104,21 +112,21 @@
    changes; the most notable is -Xignore-space-at-eol.
 
  * "git send-email" learned "--to-cmd", similar to "--cc-cmd", to read
-   recipient list from a command output.
+   the recipient list from a command output.
 
  * "git send-email" learned to read and use "To:" from its input files.
 
  * you can extend "git shell", which is often used on boxes that allow
-   git-only login over ssh as login shell, with custom set of
+   git-only login over ssh as login shell, with a custom set of
    commands.
 
  * The current branch name in "git status" output can be colored differently
-   from the generic header color by setting "color.status.branch" variable.
+   from the generic header color by setting the "color.status.branch" variable.
 
  * "git submodule sync" updates metainformation for all submodules,
    not just the ones that have been checked out.
 
- * gitweb can use custom 'highlight' command with its configuration file.
+ * gitweb can use a custom 'highlight' command with its configuration file.
 
  * other gitweb updates.
 
@@ -129,7 +137,7 @@
 Fixes since v1.7.3
 ------------------
 
-All of the fixes in v1.7.3.X maintenance series are included in this
+All of the fixes in the v1.7.3.X maintenance series are included in this
 release, unless otherwise noted.
 
  * "git log --author=me --author=her" did not find commits written by
@@ -146,6 +154,6 @@
 
 ---
 exec >/var/tmp/1
-O=v1.7.4-rc1
+O=v1.7.4-rc2
 echo O=$(git describe master)
 git shortlog --no-merges ^maint ^$O master
diff --git a/Documentation/config.txt b/Documentation/config.txt
index ff7c225..c5e1835 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -317,17 +317,26 @@
 = true).
 
 core.worktree::
-	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).
+	Set the path to the root of the working tree.
 	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 relative path to the directory specified by
-	--git-dir or GIT_DIR.
-	Note: If --git-dir or GIT_DIR are specified but none of
+	variable and the '--work-tree' command line option.
+	The value can an absolute path or relative to the path to
+	the .git directory, which is either specified by --git-dir
+	or GIT_DIR, or automatically discovered.
+	If --git-dir or GIT_DIR is specified but none of
 	--work-tree, GIT_WORK_TREE and core.worktree is specified,
-	the current working directory is regarded as the top directory
+	the current working directory is regarded as the top level
 	of your working 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 the "/path/to" directory will
+still use "/different/path" as the root of the work tree and can cause
+confusion unless you know what you are doing (e.g. you are creating a
+read-only snapshot of the same index to a location different from the
+repository's usual working tree).
 
 core.logAllRefUpdates::
 	Enable the reflog. Updates to a ref <ref> is logged to the file
diff --git a/Documentation/git-archive.txt b/Documentation/git-archive.txt
index 4163a1b..bf5037a 100644
--- a/Documentation/git-archive.txt
+++ b/Documentation/git-archive.txt
@@ -116,7 +116,7 @@
 in the tree that is being archived.  If you want to tweak the way the
 output is generated after the fact (e.g. you committed without adding an
 appropriate export-ignore in its `.gitattributes`), adjust the checked out
-`.gitattributes` file as necessary and use `--work-tree-attributes`
+`.gitattributes` file as necessary and use `--worktree-attributes`
 option.  Alternatively you can keep necessary attributes that should apply
 while archiving any tree in your `$GIT_DIR/info/attributes` file.
 
diff --git a/Documentation/git-fast-import.txt b/Documentation/git-fast-import.txt
index f56dfca..4415e63 100644
--- a/Documentation/git-fast-import.txt
+++ b/Documentation/git-fast-import.txt
@@ -534,9 +534,6 @@
 If an `LF` or double quote must be encoded into `<path>` shell-style
 quoting should be used, e.g. `"path/with\n and \" in it"`.
 
-Additionally, in `040000` mode, `<path>` may also be an empty string
-(`""`) to specify the root of the tree.
-
 The value of `<path>` must be in canonical form. That is it must not:
 
 * contain an empty directory component (e.g. `foo//bar` is invalid),
@@ -545,6 +542,8 @@
 * contain the special component `.` or `..` (e.g. `foo/./bar` and
   `foo/../bar` are invalid).
 
+The root of the tree can be represented by an empty string as `<path>`.
+
 It is recommended that `<path>` always be encoded using UTF-8.
 
 `filedelete`
@@ -905,7 +904,7 @@
 set previously or a full 40-byte SHA-1 of a Git blob, preexisting or
 ready to be written.
 
-output uses the same format as `git cat-file --batch`:
+Output uses the same format as `git cat-file --batch`:
 
 ====
 	<sha1> SP 'blob' SP <size> LF
diff --git a/Documentation/git-reset.txt b/Documentation/git-reset.txt
index fd72976..927ecee 100644
--- a/Documentation/git-reset.txt
+++ b/Documentation/git-reset.txt
@@ -76,15 +76,10 @@
 but carries forward unmerged index entries.
 
 --keep::
-	Resets the index, updates files in the working tree that are
-	different between <commit> and HEAD, but keeps those
-	which are different between HEAD and the working tree (i.e.
-	which have local changes).
+	Resets index entries and updates files in the working tree that are
+	different between <commit> and HEAD.
 	If a file that is different between <commit> and HEAD has local changes,
 	reset is aborted.
-+
-In other words, --keep does a 2-way merge between <commit> and HEAD followed by
-'git reset --mixed <commit>'.
 --
 
 If you want to undo a commit other than the latest on a branch,
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 4e5fe4d..0dac7aa 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -291,17 +291,12 @@
 	path or relative path to current working directory.
 
 --work-tree=<path>::
-	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).
+	Set the path to the working tree. It can be an absolute path
+	or a path relative to the current working directory.
 	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
-	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
-	of your working tree.
+	variable (see core.worktree in linkgit:git-config[1] for a
+	more detailed discussion).
 
 --bare::
 	Treat the repository as a bare repository.  If GIT_DIR
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index 22b8582..7e7e121 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -504,6 +504,8 @@
 
 - `pascal` suitable for source code in the Pascal/Delphi language.
 
+- `perl` suitable for source code in the Perl language.
+
 - `php` suitable for source code in the PHP language.
 
 - `python` suitable for source code in the Python language.
@@ -591,6 +593,39 @@
 manually with `git update-ref -d refs/notes/textconv/jpg` (where
 "jpg" is the name of the diff driver, as in the example above).
 
+Marking files as binary
+^^^^^^^^^^^^^^^^^^^^^^^
+
+Git usually guesses correctly whether a blob contains text or binary
+data by examining the beginning of the contents. However, sometimes you
+may want to override its decision, either because a blob contains binary
+data later in the file, or because the content, while technically
+composed of text characters, is opaque to a human reader. For example,
+many postscript files contain only ascii characters, but produce noisy
+and meaningless diffs.
+
+The simplest way to mark a file as binary is to unset the diff
+attribute in the `.gitattributes` file:
+
+------------------------
+*.ps -diff
+------------------------
+
+This will cause git to generate `Binary files differ` (or a binary
+patch, if binary patches are enabled) instead of a regular diff.
+
+However, one may also want to specify other diff driver attributes. For
+example, you might want to use `textconv` to convert postscript files to
+an ascii representation for human viewing, but otherwise treat them as
+binary files. You cannot specify both `-diff` and `diff=ps` attributes.
+The solution is to use the `diff.*.binary` config option:
+
+------------------------
+[diff "ps"]
+  textconv = ps2ascii
+  binary = true
+------------------------
+
 Performing a three-way merge
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt
index 7183aa9..28edefa 100644
--- a/Documentation/githooks.txt
+++ b/Documentation/githooks.txt
@@ -350,10 +350,6 @@
 The commits are guaranteed to be listed in the order that they were
 processed by rebase.
 
-There is no default 'post-rewrite' hook, but see the
-`post-receive-copy-notes` script in `contrib/hooks` for an example
-that copies your git-notes to the rewritten commits.
-
 
 GIT
 ---
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index c29b944..ccfc298 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v1.7.4-rc1
+DEF_VER=v1.7.4-rc2
 
 LF='
 '
diff --git a/builtin/commit.c b/builtin/commit.c
index 22ba54f..03cff5a 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -45,9 +45,9 @@
 "    git config --global user.name \"Your Name\"\n"
 "    git config --global user.email you@example.com\n"
 "\n"
-"If the identity used for this commit is wrong, you can fix it with:\n"
+"After doing this, you may fix the identity used for this commit with:\n"
 "\n"
-"    git commit --amend --author='Your Name <you@example.com>'\n";
+"    git commit --amend --reset-author\n";
 
 static const char empty_amend_advice[] =
 "You asked to amend the most recent commit, but doing so would make\n"
diff --git a/builtin/remote-ext.c b/builtin/remote-ext.c
index 1f77317..ea71977 100644
--- a/builtin/remote-ext.c
+++ b/builtin/remote-ext.c
@@ -212,16 +212,16 @@
 	char buffer[MAXCOMMAND];
 
 	while (1) {
-		size_t length;
+		size_t i;
 		if (!fgets(buffer, MAXCOMMAND - 1, stdin)) {
 			if (ferror(stdin))
 				die("Comammand input error");
 			exit(0);
 		}
 		/* Strip end of line characters. */
-		length = strlen(buffer);
-		while (isspace((unsigned char)buffer[length - 1]))
-			buffer[--length] = 0;
+		i = strlen(buffer);
+		while (i > 0 && isspace(buffer[i - 1]))
+			buffer[--i] = 0;
 
 		if (!strcmp(buffer, "capabilities")) {
 			printf("*connect\n\n");
diff --git a/exec_cmd.c b/exec_cmd.c
index bf22570..38545e8 100644
--- a/exec_cmd.c
+++ b/exec_cmd.c
@@ -3,7 +3,6 @@
 #include "quote.h"
 #define MAX_ARGS	32
 
-extern char **environ;
 static const char *argv_exec_path;
 static const char *argv0_path;
 
diff --git a/git-submodule.sh b/git-submodule.sh
index c21b77a..8b90589 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -37,12 +37,24 @@
 		die "remote ($remote) does not have a url defined in .git/config"
 	url="$1"
 	remoteurl=${remoteurl%/}
+	sep=/
 	while test -n "$url"
 	do
 		case "$url" in
 		../*)
 			url="${url#../}"
-			remoteurl="${remoteurl%/*}"
+			case "$remoteurl" in
+			*/*)
+				remoteurl="${remoteurl%/*}"
+				;;
+			*:*)
+				remoteurl="${remoteurl%:*}"
+				sep=:
+				;;
+			*)
+				die "cannot strip one component off url '$remoteurl'"
+				;;
+			esac
 			;;
 		./*)
 			url="${url#./}"
@@ -51,7 +63,7 @@
 			break;;
 		esac
 	done
-	echo "$remoteurl/${url%/}"
+	echo "$remoteurl$sep${url%/}"
 }
 
 #
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index c65af1a..1025c2f 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -250,13 +250,14 @@
 	# main extensions, defining name of syntax;
 	# see files in /usr/share/highlight/langDefs/ directory
 	map { $_ => $_ }
-		qw(py c cpp rb java css php sh pl js tex bib xml awk bat ini spec tcl),
+		qw(py c cpp rb java css php sh pl js tex bib xml awk bat ini spec tcl sql make),
 	# alternate extensions, see /etc/highlight/filetypes.conf
 	'h' => 'c',
+	map { $_ => 'sh'  } qw(bash zsh ksh),
 	map { $_ => 'cpp' } qw(cxx c++ cc),
-	map { $_ => 'php' } qw(php3 php4),
+	map { $_ => 'php' } qw(php3 php4 php5 phps),
 	map { $_ => 'pl'  } qw(perl pm), # perhaps also 'cgi'
-	'mak' => 'make',
+	map { $_ => 'make'} qw(mak mk),
 	map { $_ => 'xml' } qw(xhtml html htm),
 );
 
@@ -3464,8 +3465,7 @@
 	my ($fd, $highlight, $syntax) = @_;
 	return $fd unless ($highlight && defined $syntax);
 
-	close $fd
-		or die_error(404, "Reading blob failed");
+	close $fd;
 	open $fd, quote_command(git_cmd(), "cat-file", "blob", $hash)." | ".
 	          quote_command($highlight_bin).
 	          " --xhtml --fragment --syntax $syntax |"
@@ -3601,10 +3601,15 @@
 		insert_file($site_header);
 	}
 
-	print "<div class=\"page_header\">\n" .
-	      $cgi->a({-href => esc_url($logo_url),
-	               -title => $logo_label},
-	              qq(<img src=").esc_url($logo).qq(" width="72" height="27" alt="git" class="logo"/>));
+	print "<div class=\"page_header\">\n";
+	if (defined $logo) {
+		print $cgi->a({-href => esc_url($logo_url),
+		               -title => $logo_label},
+		              $cgi->img({-src => esc_url($logo),
+		                         -width => 72, -height => 27,
+		                         -alt => "git",
+		                         -class => "logo"}));
+	}
 	print $cgi->a({-href => esc_url($home_link)}, $home_link_str) . " / ";
 	if (defined $project) {
 		print $cgi->a({-href => href(action=>"summary")}, esc_html($project));
diff --git a/ll-merge.c b/ll-merge.c
index 007dd3e..6ce512e 100644
--- a/ll-merge.c
+++ b/ll-merge.c
@@ -351,16 +351,13 @@
 	     const struct ll_merge_options *opts)
 {
 	static struct git_attr_check check[2];
+	static const struct ll_merge_options default_opts;
 	const char *ll_driver_name = NULL;
 	int marker_size = DEFAULT_CONFLICT_MARKER_SIZE;
 	const struct ll_merge_driver *driver;
 
-	if (!opts) {
-		struct ll_merge_options default_opts = {0};
-		return ll_merge(result_buf, path, ancestor, ancestor_label,
-				ours, our_label, theirs, their_label,
-				&default_opts);
-	}
+	if (!opts)
+		opts = &default_opts;
 
 	if (opts->renormalize) {
 		normalize_file(ancestor, path);
diff --git a/setup.c b/setup.c
index 3d73269..dadc666 100644
--- a/setup.c
+++ b/setup.c
@@ -411,6 +411,15 @@
 	if (check_repository_format_gently(gitdir, nongit_ok))
 		return NULL;
 
+	/* --work-tree is set without --git-dir; use discovered one */
+	if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) {
+		if (offset != len && !is_absolute_path(gitdir))
+			gitdir = xstrdup(make_absolute_path(gitdir));
+		if (chdir(cwd))
+			die_errno("Could not come back to cwd");
+		return setup_explicit_git_dir(gitdir, cwd, len, 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));
@@ -443,6 +452,16 @@
 	if (check_repository_format_gently(".", nongit_ok))
 		return NULL;
 
+	/* --work-tree is set without --git-dir; use discovered one */
+	if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) {
+		const char *gitdir;
+
+		gitdir = offset == len ? "." : xmemdupz(cwd, offset);
+		if (chdir(cwd))
+			die_errno("Could not come back to cwd");
+		return setup_explicit_git_dir(gitdir, cwd, len, nongit_ok);
+	}
+
 	inside_git_dir = 1;
 	inside_work_tree = 0;
 	if (offset != len) {
diff --git a/sha1_file.c b/sha1_file.c
index 1cafdfa..d86a8db 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -2141,7 +2141,7 @@
 		return data;
 	}
 
-	if (errno != ENOENT)
+	if (errno && errno != ENOENT)
 		die_errno("failed to read object %s", sha1_to_hex(sha1));
 
 	/* die if we replaced an object with one that does not exist */
diff --git a/t/README b/t/README
index 892d443..25f7d2d 100644
--- a/t/README
+++ b/t/README
@@ -283,6 +283,12 @@
    Tests that are likely to smoke out future regressions are better
    than tests that just inflate the coverage metrics.
 
+ - When a test checks for an absolute path that a git command generated,
+   construct the expected value using $(pwd) rather than $PWD,
+   $TEST_DIRECTORY, or $TRASH_DIRECTORY. It makes a difference on
+   Windows, where the shell (MSYS bash) mangles absolute path names.
+   For details, see the commit message of 4114156ae9.
+
 Don't:
 
  - exit() within a <script> part.
diff --git a/t/lib-git-svn.sh b/t/lib-git-svn.sh
index 6a9d975..199f22c 100644
--- a/t/lib-git-svn.sh
+++ b/t/lib-git-svn.sh
@@ -68,8 +68,7 @@
 	svn "$orig_svncmd" --config-dir "$svnconf" "$@"
 }
 
-if test -n "$SVN_HTTPD_PORT"
-then
+prepare_httpd () {
 	for d in \
 		"$SVN_HTTPD_PATH" \
 		/usr/sbin/apache2 \
@@ -83,8 +82,8 @@
 	done
 	if test -z "$SVN_HTTPD_PATH"
 	then
-		skip_all='skipping git svn tests, Apache not found'
-		test_done
+		echo >&2 '*** error: Apache not found'
+		return 1
 	fi
 	for d in \
 		"$SVN_HTTPD_MODULE_PATH" \
@@ -99,23 +98,16 @@
 	done
 	if test -z "$SVN_HTTPD_MODULE_PATH"
 	then
-		skip_all='skipping git svn tests, Apache module dir not found'
-		test_done
+		echo >&2 '*** error: Apache module dir not found'
+		return 1
 	fi
-fi
-
-start_httpd () {
-	repo_base_path="$1"
-	if test -z "$SVN_HTTPD_PORT"
+	if test ! -f "$SVN_HTTPD_MODULE_PATH/mod_dav_svn.so"
 	then
-		echo >&2 'SVN_HTTPD_PORT is not defined!'
-		return
-	fi
-	if test -z "$repo_base_path"
-	then
-		repo_base_path=svn
+		echo >&2 '*** error: Apache module "mod_dav_svn" not found'
+		return 1
 	fi
 
+	repo_base_path="${1-svn}"
 	mkdir "$GIT_DIR"/logs
 
 	cat > "$GIT_DIR/httpd.conf" <<EOF
@@ -132,12 +124,24 @@
 	SVNPath "$rawsvnrepo"
 </Location>
 EOF
+}
+
+start_httpd () {
+	if test -z "$SVN_HTTPD_PORT"
+	then
+		echo >&2 'SVN_HTTPD_PORT is not defined!'
+		return
+	fi
+
+	prepare_httpd "$1" || return 1
+
 	"$SVN_HTTPD_PATH" -f "$GIT_DIR"/httpd.conf -k start
 	svnrepo="http://127.0.0.1:$SVN_HTTPD_PORT/$repo_base_path"
 }
 
 stop_httpd () {
 	test -z "$SVN_HTTPD_PORT" && return
+	test ! -f "$GIT_DIR/httpd.conf" && return
 	"$SVN_HTTPD_PATH" -f "$GIT_DIR"/httpd.conf -k stop
 }
 
diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh
index 2f7002a..8deec75 100755
--- a/t/t0000-basic.sh
+++ b/t/t0000-basic.sh
@@ -80,11 +80,11 @@
     chmod +x passing-todo.sh &&
     ./passing-todo.sh >out 2>err &&
     ! test -s err &&
-cat >expect <<EOF &&
-ok 1 - pretend we have fixed a known breakage # TODO known breakage
-# fixed 1 known breakage(s)
-# passed all 1 test(s)
-1..1
+sed -e 's/^> //' >expect <<EOF &&
+> ok 1 - pretend we have fixed a known breakage # TODO known breakage
+> # fixed 1 known breakage(s)
+> # passed all 1 test(s)
+> 1..1
 EOF
     test_cmp expect out)
 "
@@ -164,19 +164,19 @@
     test_must_fail ./failing-cleanup.sh >out 2>err &&
     ! test -s err &&
     ! test -f \"trash directory.failing-cleanup/clean-after-failure\" &&
-sed -e 's/Z$//' >expect <<\EOF &&
-not ok - 1 tests clean up even after a failure
-#	Z
-#	    touch clean-after-failure &&
-#	    test_when_finished rm clean-after-failure &&
-#	    (exit 1)
-#	Z
-not ok - 2 failure to clean up causes the test to fail
-#	Z
-#	    test_when_finished \"(exit 2)\"
-#	Z
-# failed 2 among 2 test(s)
-1..2
+sed -e 's/Z$//' -e 's/^> //' >expect <<\EOF &&
+> not ok - 1 tests clean up even after a failure
+> #	Z
+> #	    touch clean-after-failure &&
+> #	    test_when_finished rm clean-after-failure &&
+> #	    (exit 1)
+> #	Z
+> not ok - 2 failure to clean up causes the test to fail
+> #	Z
+> #	    test_when_finished \"(exit 2)\"
+> #	Z
+> # failed 2 among 2 test(s)
+> 1..2
 EOF
     test_cmp expect out)
 "
diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh
index f072a8e..da6252b 100755
--- a/t/t1501-worktree.sh
+++ b/t/t1501-worktree.sh
@@ -343,7 +343,7 @@
 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 &&
+	echo "$(pwd)/repo.git/work" >expected &&
 	test_cmp expected actual
 '
 
diff --git a/t/t1510-repo-setup.sh b/t/t1510-repo-setup.sh
index c3798ce..15101d5 100755
--- a/t/t1510-repo-setup.sh
+++ b/t/t1510-repo-setup.sh
@@ -1,56 +1,223 @@
 #!/bin/sh
 
-test_description='Tests of cwd/prefix/worktree/gitdir setup in all cases'
+test_description="Tests of cwd/prefix/worktree/gitdir setup in all cases
 
+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 was originally meant to work only if
+   GIT_DIR is set, but earlier git didn't enforce it, and some scripts
+   depend on the implementation that happened to first discover .git by
+   going up from the users $cwd and then using the specified working tree
+   that may or may not have any relation to where .git was found in.  This
+   historical behaviour must be kept.
+
+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-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.
-#
+here=$(pwd)
 
-test_repo() {
+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
+		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
 	)
 }
 
+maybe_config () {
+	file=$1 var=$2 value=$3 &&
+	if test "$value" != unset
+	then
+		git config --file="$file" "$var" "$value"
+	fi
+}
+
+setup_repo () {
+	name=$1 worktreecfg=$2 gitfile=$3 barecfg=$4 &&
+	sane_unset GIT_DIR GIT_WORK_TREE &&
+
+	git init "$name" &&
+	maybe_config "$name/.git/config" core.worktree "$worktreecfg" &&
+	maybe_config "$name/.git/config" core.bare "$barecfg" &&
+	mkdir -p "$name/sub/sub" &&
+
+	if test "${gitfile:+set}"
+	then
+		mv "$name/.git" "$name.git" &&
+		echo "gitdir: ../$name.git" >"$name/.git"
+	fi
+}
+
+maybe_set () {
+	var=$1 value=$2 &&
+	if test "$value" != unset
+	then
+		eval "$var=\$value" &&
+		export $var
+	fi
+}
+
+setup_env () {
+	worktreenv=$1 gitdirenv=$2 &&
+	sane_unset GIT_DIR GIT_WORK_TREE &&
+	maybe_set GIT_DIR "$gitdirenv" &&
+	maybe_set GIT_WORK_TREE "$worktreeenv"
+}
+
+expect () {
+	cat >"$1/expected" <<-EOF
+	setup: git_dir: $2
+	setup: worktree: $3
+	setup: cwd: $4
+	setup: prefix: $5
+	EOF
+}
+
+try_case () {
+	name=$1 worktreeenv=$2 gitdirenv=$3 &&
+	setup_env "$worktreeenv" "$gitdirenv" &&
+	expect "$name" "$4" "$5" "$6" "$7" &&
+	test_repo "$name"
+}
+
+run_wt_tests () {
+	N=$1 gitfile=$2
+
+	absgit="$here/$N/.git"
+	dotgit=.git
+	dotdotgit=../../.git
+
+	if test "$gitfile"
+	then
+		absgit="$here/$N.git"
+		dotgit=$absgit dotdotgit=$absgit
+	fi
+
+	test_expect_success "#$N: explicit GIT_WORK_TREE and GIT_DIR at toplevel" '
+		try_case $N "$here/$N" .git \
+			"$dotgit" "$here/$N" "$here/$N" "(null)" &&
+		try_case $N . .git \
+			"$dotgit" "$here/$N" "$here/$N" "(null)" &&
+		try_case $N "$here/$N" "$here/$N/.git" \
+			"$absgit" "$here/$N" "$here/$N" "(null)" &&
+		try_case $N . "$here/$N/.git" \
+			"$absgit" "$here/$N" "$here/$N" "(null)"
+	'
+
+	test_expect_success "#$N: explicit GIT_WORK_TREE and GIT_DIR in subdir" '
+		try_case $N/sub/sub "$here/$N" ../../.git \
+			"$absgit" "$here/$N" "$here/$N" sub/sub/ &&
+		try_case $N/sub/sub ../.. ../../.git \
+			"$absgit" "$here/$N" "$here/$N" sub/sub/ &&
+		try_case $N/sub/sub "$here/$N" "$here/$N/.git" \
+			"$absgit" "$here/$N" "$here/$N" sub/sub/ &&
+		try_case $N/sub/sub ../.. "$here/$N/.git" \
+			"$absgit" "$here/$N" "$here/$N" sub/sub/
+	'
+
+	test_expect_success "#$N: explicit GIT_WORK_TREE from parent of worktree" '
+		try_case $N "$here/$N/wt" .git \
+			"$dotgit" "$here/$N/wt" "$here/$N" "(null)" &&
+		try_case $N wt .git \
+			"$dotgit" "$here/$N/wt" "$here/$N" "(null)" &&
+		try_case $N wt "$here/$N/.git" \
+			"$absgit" "$here/$N/wt" "$here/$N" "(null)" &&
+		try_case $N "$here/$N/wt" "$here/$N/.git" \
+			"$absgit" "$here/$N/wt" "$here/$N" "(null)"
+	'
+
+	test_expect_success "#$N: explicit GIT_WORK_TREE from nephew of worktree" '
+		try_case $N/sub/sub "$here/$N/wt" ../../.git \
+			"$dotdotgit" "$here/$N/wt" "$here/$N/sub/sub" "(null)" &&
+		try_case $N/sub/sub ../../wt ../../.git \
+			"$dotdotgit" "$here/$N/wt" "$here/$N/sub/sub" "(null)" &&
+		try_case $N/sub/sub ../../wt "$here/$N/.git" \
+			"$absgit" "$here/$N/wt" "$here/$N/sub/sub" "(null)" &&
+		try_case $N/sub/sub "$here/$N/wt" "$here/$N/.git" \
+			"$absgit" "$here/$N/wt" "$here/$N/sub/sub" "(null)"
+	'
+
+	test_expect_success "#$N: chdir_to_toplevel uses worktree, not git dir" '
+		try_case $N "$here" .git \
+			"$absgit" "$here" "$here" $N/ &&
+		try_case $N .. .git \
+			"$absgit" "$here" "$here" $N/ &&
+		try_case $N .. "$here/$N/.git" \
+			"$absgit" "$here" "$here" $N/ &&
+		try_case $N "$here" "$here/$N/.git" \
+			"$absgit" "$here" "$here" $N/
+	'
+
+	test_expect_success "#$N: chdir_to_toplevel uses worktree (from subdir)" '
+		try_case $N/sub/sub "$here" ../../.git \
+			"$absgit" "$here" "$here" $N/sub/sub/ &&
+		try_case $N/sub/sub ../../.. ../../.git \
+			"$absgit" "$here" "$here" $N/sub/sub/ &&
+		try_case $N/sub/sub ../../../ "$here/$N/.git" \
+			"$absgit" "$here" "$here" $N/sub/sub/ &&
+		try_case $N/sub/sub "$here" "$here/$N/.git" \
+			"$absgit" "$here" "$here" $N/sub/sub/
+	'
+}
+
+# try_repo #c GIT_WORK_TREE GIT_DIR core.worktree .gitfile? core.bare \
+#	(git dir) (work tree) (cwd) (prefix) \	<-- at toplevel
+#	(git dir) (work tree) (cwd) (prefix)	<-- from subdir
+try_repo () {
+	name=$1 worktreeenv=$2 gitdirenv=$3 &&
+	setup_repo "$name" "$4" "$5" "$6" &&
+	shift 6 &&
+	try_case "$name" "$worktreeenv" "$gitdirenv" \
+		"$1" "$2" "$3" "$4" &&
+	shift 4 &&
+	case "$gitdirenv" in
+	/* | ?:/* | unset) ;;
+	*)
+		gitdirenv=../$gitdirenv ;;
+	esac &&
+	try_case "$name/sub" "$worktreeenv" "$gitdirenv" \
+		"$1" "$2" "$3" "$4"
+}
+
 # Bit 0 = GIT_WORK_TREE
 # Bit 1 = GIT_DIR
 # Bit 2 = core.worktree
@@ -58,4475 +225,552 @@
 # 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' '
-	sane_unset GIT_DIR GIT_WORK_TREE &&
-	mkdir 0 0/sub &&
-	cd 0 && git init && cd ..
+test_expect_success '#0: nonbare repo, no explicit configuration' '
+	try_repo 0 unset unset unset "" unset \
+		.git "$here/0" "$here/0" "(null)" \
+		.git "$here/0" "$here/0" sub/ 2>message &&
+	! test -s message
 '
 
-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 '#1: GIT_WORK_TREE without explicit GIT_DIR is accepted' '
+	mkdir -p wt &&
+	try_repo 1 "$here" unset unset "" unset \
+		"$here/1/.git" "$here" "$here" 1/ \
+		"$here/1/.git" "$here" "$here" 1/sub/ 2>message &&
+	! test -s message
 '
 
-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
+test_expect_success '#2: worktree defaults to cwd with explicit GIT_DIR' '
+	try_repo 2 unset "$here/2/.git" unset "" unset \
+		"$here/2/.git" "$here/2" "$here/2" "(null)" \
+		"$here/2/.git" "$here/2/sub" "$here/2/sub" "(null)"
 '
 
-#
-# 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' '
-	sane_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 '#2b: relative GIT_DIR' '
+	try_repo 2b unset ".git" unset "" unset \
+		".git" "$here/2b" "$here/2b" "(null)" \
+		"../.git" "$here/2b/sub" "$here/2b/sub" "(null)"
 '
 
-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' '
-	sane_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' '
-	sane_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 ..
+	setup_repo 3 unset "" unset &&
+	mkdir -p 3/sub/sub 3/wt/sub
+'
+run_wt_tests 3
+
+test_expect_success '#4: core.worktree without GIT_DIR set is accepted' '
+	setup_repo 4 ../sub "" unset &&
+	mkdir -p 4/sub sub &&
+	try_case 4 unset unset \
+		.git "$here/4/sub" "$here/4" "(null)" \
+		"$here/4/.git" "$here/4/sub" "$here/4/sub" "(null)" 2>message &&
+	! test -s message
 '
 
-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 '#5: core.worktree + GIT_WORK_TREE is accepted' '
+	# or: you cannot intimidate away the lack of GIT_DIR setting
+	try_repo 5 "$here" unset "$here/5" "" unset \
+		"$here/5/.git" "$here" "$here" 5/ \
+		"$here/5/.git" "$here" "$here" 5/sub/ 2>message &&
+	try_repo 5a .. unset "$here/5a" "" unset \
+		"$here/5a/.git" "$here" "$here" 5a/ \
+		"$here/5a/.git" "$here/5a" "$here/5a" sub/ &&
+	! test -s message
 '
 
-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 '#6: setting GIT_DIR brings core.worktree to life' '
+	setup_repo 6 "$here/6" "" unset &&
+	try_case 6 unset .git \
+		.git "$here/6" "$here/6" "(null)" &&
+	try_case 6 unset "$here/6/.git" \
+		"$here/6/.git" "$here/6" "$here/6" "(null)" &&
+	try_case 6/sub/sub unset ../../.git \
+		"$here/6/.git" "$here/6" "$here/6" sub/sub/ &&
+	try_case 6/sub/sub unset "$here/6/.git" \
+		"$here/6/.git" "$here/6" "$here/6" sub/sub/
 '
 
-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 '#6b: GIT_DIR set, core.worktree relative' '
+	setup_repo 6b .. "" unset &&
+	try_case 6b unset .git \
+		.git "$here/6b" "$here/6b" "(null)" &&
+	try_case 6b unset "$here/6b/.git" \
+		"$here/6b/.git" "$here/6b" "$here/6b" "(null)" &&
+	try_case 6b/sub/sub unset ../../.git \
+		"$here/6b/.git" "$here/6b" "$here/6b" sub/sub/ &&
+	try_case 6b/sub/sub unset "$here/6b/.git" \
+		"$here/6b/.git" "$here/6b" "$here/6b" sub/sub/
 '
 
-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 '#6c: GIT_DIR set, core.worktree=../wt (absolute)' '
+	setup_repo 6c "$here/6c/wt" "" unset &&
+	mkdir -p 6c/wt/sub &&
+
+	try_case 6c unset .git \
+		.git "$here/6c/wt" "$here/6c" "(null)" &&
+	try_case 6c unset "$here/6c/.git" \
+		"$here/6c/.git" "$here/6c/wt" "$here/6c" "(null)" &&
+	try_case 6c/sub/sub unset ../../.git \
+		../../.git "$here/6c/wt" "$here/6c/sub/sub" "(null)" &&
+	try_case 6c/sub/sub unset "$here/6c/.git" \
+		"$here/6c/.git" "$here/6c/wt" "$here/6c/sub/sub" "(null)"
 '
 
-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 '#6d: GIT_DIR set, core.worktree=../wt (relative)' '
+	setup_repo 6d "$here/6d/wt" "" unset &&
+	mkdir -p 6d/wt/sub &&
+
+	try_case 6d unset .git \
+		.git "$here/6d/wt" "$here/6d" "(null)" &&
+	try_case 6d unset "$here/6d/.git" \
+		"$here/6d/.git" "$here/6d/wt" "$here/6d" "(null)" &&
+	try_case 6d/sub/sub unset ../../.git \
+		../../.git "$here/6d/wt" "$here/6d/sub/sub" "(null)" &&
+	try_case 6d/sub/sub unset "$here/6d/.git" \
+		"$here/6d/.git" "$here/6d/wt" "$here/6d/sub/sub" "(null)"
 '
 
-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 '#6e: GIT_DIR set, core.worktree=../.. (absolute)' '
+	setup_repo 6e "$here" "" unset &&
+	try_case 6e unset .git \
+		"$here/6e/.git" "$here" "$here" 6e/ &&
+	try_case 6e unset "$here/6e/.git" \
+		"$here/6e/.git" "$here" "$here" 6e/ &&
+	try_case 6e/sub/sub unset ../../.git \
+		"$here/6e/.git" "$here" "$here" 6e/sub/sub/ &&
+	try_case 6e/sub/sub unset "$here/6e/.git" \
+		"$here/6e/.git" "$here" "$here" 6e/sub/sub/
 '
 
-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 '#6f: GIT_DIR set, core.worktree=../.. (relative)' '
+	setup_repo 6f ../../ "" unset &&
+	try_case 6f unset .git \
+		"$here/6f/.git" "$here" "$here" 6f/ &&
+	try_case 6f unset "$here/6f/.git" \
+		"$here/6f/.git" "$here" "$here" 6f/ &&
+	try_case 6f/sub/sub unset ../../.git \
+		"$here/6f/.git" "$here" "$here" 6f/sub/sub/ &&
+	try_case 6f/sub/sub unset "$here/6f/.git" \
+		"$here/6f/.git" "$here" "$here" 6f/sub/sub/
 '
 
-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' '
-	sane_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' '
-	sane_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' '
-	sane_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
-
+# case #7: GIT_WORK_TREE overrides core.worktree.
 test_expect_success '#7: setup' '
-	sane_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 ..
+	setup_repo 7 non-existent "" unset &&
+	mkdir -p 7/sub/sub 7/wt/sub
+'
+run_wt_tests 7
+
+test_expect_success '#8: gitfile, easy case' '
+	try_repo 8 unset unset unset gitfile unset \
+		"$here/8.git" "$here/8" "$here/8" "(null)" \
+		"$here/8.git" "$here/8" "$here/8" sub/
 '
 
-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 '#9: GIT_WORK_TREE accepted with gitfile' '
+	mkdir -p 9/wt &&
+	try_repo 9 wt unset unset gitfile unset \
+		"$here/9.git" "$here/9/wt" "$here/9" "(null)" \
+		"$here/9.git" "$here/9/sub/wt" "$here/9/sub" "(null)" 2>message &&
+	! test -s message
 '
 
-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 '#10: GIT_DIR can point to gitfile' '
+	try_repo 10 unset "$here/10/.git" unset gitfile unset \
+		"$here/10.git" "$here/10" "$here/10" "(null)" \
+		"$here/10.git" "$here/10/sub" "$here/10/sub" "(null)"
 '
 
-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 '#10b: relative GIT_DIR can point to gitfile' '
+	try_repo 10b unset .git unset gitfile unset \
+		"$here/10b.git" "$here/10b" "$here/10b" "(null)" \
+		"$here/10b.git" "$here/10b/sub" "$here/10b/sub" "(null)"
 '
 
-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' '
-	sane_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' '
-	sane_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' '
-	sane_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
-
+# case #11: GIT_WORK_TREE works, gitfile case.
 test_expect_success '#11: setup' '
-	sane_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 ..
+	setup_repo 11 unset gitfile unset &&
+	mkdir -p 11/sub/sub 11/wt/sub
+'
+run_wt_tests 11 gitfile
+
+test_expect_success '#12: core.worktree with gitfile is accepted' '
+	try_repo 12 unset unset "$here/12" gitfile unset \
+		"$here/12.git" "$here/12" "$here/12" "(null)" \
+		"$here/12.git" "$here/12" "$here/12" sub/ 2>message &&
+	! test -s message
 '
 
-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 '#13: core.worktree+GIT_WORK_TREE accepted (with gitfile)' '
+	# or: you cannot intimidate away the lack of GIT_DIR setting
+	try_repo 13 non-existent-too unset non-existent gitfile unset \
+		"$here/13.git" "$here/13/non-existent-too" "$here/13" "(null)" \
+		"$here/13.git" "$here/13/sub/non-existent-too" "$here/13/sub" "(null)" 2>message &&
+	! test -s message
 '
 
-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 .
+# case #14.
+# If this were more table-driven, it could share code with case #6.
+
+test_expect_success '#14: core.worktree with GIT_DIR pointing to gitfile' '
+	setup_repo 14 "$here/14" gitfile unset &&
+	try_case 14 unset .git \
+		"$here/14.git" "$here/14" "$here/14" "(null)" &&
+	try_case 14 unset "$here/14/.git" \
+		"$here/14.git" "$here/14" "$here/14" "(null)" &&
+	try_case 14/sub/sub unset ../../.git \
+		"$here/14.git" "$here/14" "$here/14" sub/sub/ &&
+	try_case 14/sub/sub unset "$here/14/.git" \
+		"$here/14.git" "$here/14" "$here/14" sub/sub/ &&
+
+	setup_repo 14c "$here/14c/wt" gitfile unset &&
+	mkdir -p 14c/wt/sub &&
+
+	try_case 14c unset .git \
+		"$here/14c.git" "$here/14c/wt" "$here/14c" "(null)" &&
+	try_case 14c unset "$here/14c/.git" \
+		"$here/14c.git" "$here/14c/wt" "$here/14c" "(null)" &&
+	try_case 14c/sub/sub unset ../../.git \
+		"$here/14c.git" "$here/14c/wt" "$here/14c/sub/sub" "(null)" &&
+	try_case 14c/sub/sub unset "$here/14c/.git" \
+		"$here/14c.git" "$here/14c/wt" "$here/14c/sub/sub" "(null)" &&
+
+	setup_repo 14d "$here/14d/wt" gitfile unset &&
+	mkdir -p 14d/wt/sub &&
+
+	try_case 14d unset .git \
+		"$here/14d.git" "$here/14d/wt" "$here/14d" "(null)" &&
+	try_case 14d unset "$here/14d/.git" \
+		"$here/14d.git" "$here/14d/wt" "$here/14d" "(null)" &&
+	try_case 14d/sub/sub unset ../../.git \
+		"$here/14d.git" "$here/14d/wt" "$here/14d/sub/sub" "(null)" &&
+	try_case 14d/sub/sub unset "$here/14d/.git" \
+		"$here/14d.git" "$here/14d/wt" "$here/14d/sub/sub" "(null)" &&
+
+	setup_repo 14e "$here" gitfile unset &&
+	try_case 14e unset .git \
+		"$here/14e.git" "$here" "$here" 14e/ &&
+	try_case 14e unset "$here/14e/.git" \
+		"$here/14e.git" "$here" "$here" 14e/ &&
+	try_case 14e/sub/sub unset ../../.git \
+		"$here/14e.git" "$here" "$here" 14e/sub/sub/ &&
+	try_case 14e/sub/sub unset "$here/14e/.git" \
+		"$here/14e.git" "$here" "$here" 14e/sub/sub/
 '
 
-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 '#14b: core.worktree is relative to actual git dir' '
+	setup_repo 14b ../14b gitfile unset &&
+	try_case 14b unset .git \
+		"$here/14b.git" "$here/14b" "$here/14b" "(null)" &&
+	try_case 14b unset "$here/14b/.git" \
+		"$here/14b.git" "$here/14b" "$here/14b" "(null)" &&
+	try_case 14b/sub/sub unset ../../.git \
+		"$here/14b.git" "$here/14b" "$here/14b" sub/sub/ &&
+	try_case 14b/sub/sub unset "$here/14b/.git" \
+		"$here/14b.git" "$here/14b" "$here/14b" sub/sub/ &&
+
+	setup_repo 14f ../ gitfile unset &&
+	try_case 14f unset .git \
+		"$here/14f.git" "$here" "$here" 14f/ &&
+	try_case 14f unset "$here/14f/.git" \
+		"$here/14f.git" "$here" "$here" 14f/ &&
+	try_case 14f/sub/sub unset ../../.git \
+		"$here/14f.git" "$here" "$here" 14f/sub/sub/ &&
+	try_case 14f/sub/sub unset "$here/14f/.git" \
+		"$here/14f.git" "$here" "$here" 14f/sub/sub/
 '
 
-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' '
-	sane_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' '
-	sane_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' '
-	sane_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
-
+# case #15: GIT_WORK_TREE overrides core.worktree (gitfile case).
 test_expect_success '#15: setup' '
-	sane_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 ..
+	setup_repo 15 non-existent gitfile unset &&
+	mkdir -p 15/sub/sub 15/wt/sub
+'
+run_wt_tests 15 gitfile
+
+test_expect_success '#16a: implicitly bare repo (cwd inside .git dir)' '
+	setup_repo 16a unset "" unset &&
+	mkdir -p 16a/.git/wt/sub &&
+
+	try_case 16a/.git unset unset \
+		. "(null)" "$here/16a/.git" "(null)" &&
+	try_case 16a/.git/wt unset unset \
+		"$here/16a/.git" "(null)" "$here/16a/.git/wt" "(null)" &&
+	try_case 16a/.git/wt/sub unset unset \
+		"$here/16a/.git" "(null)" "$here/16a/.git/wt/sub" "(null)"
 '
 
-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 '#16b: bare .git (cwd inside .git dir)' '
+	setup_repo 16b unset "" true &&
+	mkdir -p 16b/.git/wt/sub &&
+
+	try_case 16b/.git unset unset \
+		. "(null)" "$here/16b/.git" "(null)" &&
+	try_case 16b/.git/wt unset unset \
+		"$here/16b/.git" "(null)" "$here/16b/.git/wt" "(null)" &&
+	try_case 16b/.git/wt/sub unset unset \
+		"$here/16b/.git" "(null)" "$here/16b/.git/wt/sub" "(null)"
 '
 
-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 '#16c: bare .git has no worktree' '
+	try_repo 16c unset unset unset "" true \
+		.git "(null)" "$here/16c" "(null)" \
+		"$here/16c/.git" "(null)" "$here/16c/sub" "(null)"
 '
 
-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 '#17: GIT_WORK_TREE without explicit GIT_DIR is accepted (bare case)' '
+	# Just like #16.
+	setup_repo 17a unset "" true &&
+	setup_repo 17b unset "" true &&
+	mkdir -p 17a/.git/wt/sub &&
+	mkdir -p 17b/.git/wt/sub &&
+
+	try_case 17a/.git "$here/17a" unset \
+		"$here/17a/.git" "$here/17a" "$here/17a" .git/ \
+		2>message &&
+	try_case 17a/.git/wt "$here/17a" unset \
+		"$here/17a/.git" "$here/17a" "$here/17a" .git/wt/ &&
+	try_case 17a/.git/wt/sub "$here/17a" unset \
+		"$here/17a/.git" "$here/17a" "$here/17a" .git/wt/sub/ &&
+
+	try_case 17b/.git "$here/17b" unset \
+		"$here/17b/.git" "$here/17b" "$here/17b" .git/ &&
+	try_case 17b/.git/wt "$here/17b" unset \
+		"$here/17b/.git" "$here/17b" "$here/17b" .git/wt/ &&
+	try_case 17b/.git/wt/sub "$here/17b" unset \
+		"$here/17b/.git" "$here/17b" "$here/17b" .git/wt/sub/ &&
+
+	try_repo 17c "$here/17c" unset unset "" true \
+		.git "$here/17c" "$here/17c" "(null)" \
+		"$here/17c/.git" "$here/17c" "$here/17c" sub/ 2>message &&
+	! test -s message
 '
 
-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 '#18: bare .git named by GIT_DIR has no worktree' '
+	try_repo 18 unset .git unset "" true \
+		.git "(null)" "$here/18" "(null)" \
+		../.git "(null)" "$here/18/sub" "(null)" &&
+	try_repo 18b unset "$here/18b/.git" unset "" true \
+		"$here/18b/.git" "(null)" "$here/18b" "(null)" \
+		"$here/18b/.git" "(null)" "$here/18b/sub" "(null)"
 '
 
-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' '
-	sane_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' '
-	sane_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' '
-	sane_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
-
+# Case #19: GIT_DIR + GIT_WORK_TREE suppresses bareness.
 test_expect_success '#19: setup' '
-	sane_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 ..
+	setup_repo 19 unset "" true &&
+	mkdir -p 19/sub/sub 19/wt/sub
 '
+run_wt_tests 19
 
-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 '#20a: core.worktree without GIT_DIR accepted (inside .git)' '
+	# Unlike case #16a.
+	setup_repo 20a "$here/20a" "" unset &&
+	mkdir -p 20a/.git/wt/sub &&
+	try_case 20a/.git unset unset \
+		"$here/20a/.git" "$here/20a" "$here/20a" .git/ 2>message &&
+	try_case 20a/.git/wt unset unset \
+		"$here/20a/.git" "$here/20a" "$here/20a" .git/wt/ &&
+	try_case 20a/.git/wt/sub unset unset \
+		"$here/20a/.git" "$here/20a" "$here/20a" .git/wt/sub/ &&
+	! test -s message
 '
 
-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' '
-	sane_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' '
-	sane_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' '
-	sane_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' '
+test_expect_success '#20b/c: core.worktree and core.bare conflict' '
+	setup_repo 20b non-existent "" true &&
+	mkdir -p 20b/.git/wt/sub &&
 	(
-	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
-	)
+		cd 20b/.git &&
+		test_must_fail git symbolic-ref HEAD >/dev/null
+	) 2>message &&
+	grep "core.bare and core.worktree" message
 '
 
-test_expect_success '#22.2: at root' '
+# Case #21: core.worktree/GIT_WORK_TREE overrides core.bare' '
+test_expect_success '#21: setup, core.worktree warns before overriding core.bare' '
+	setup_repo 21 non-existent "" unset &&
+	mkdir -p 21/.git/wt/sub &&
 	(
-	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
-	)
+		cd 21/.git &&
+		GIT_WORK_TREE="$here/21" &&
+		export GIT_WORK_TREE &&
+		git symbolic-ref HEAD >/dev/null
+	) 2>message &&
+	! test -s message
+
+'
+run_wt_tests 21
+
+test_expect_success '#22a: core.worktree = GIT_DIR = .git dir' '
+	# like case #6.
+
+	setup_repo 22a "$here/22a/.git" "" unset &&
+	setup_repo 22ab . "" unset
+	mkdir -p 22a/.git/sub 22a/sub &&
+	mkdir -p 22ab/.git/sub 22ab/sub &&
+	try_case 22a/.git unset . \
+		. "$here/22a/.git" "$here/22a/.git" "(null)" &&
+	try_case 22a/.git unset "$here/22a/.git" \
+		"$here/22a/.git" "$here/22a/.git" "$here/22a/.git" "(null)" &&
+	try_case 22a/.git/sub unset .. \
+		"$here/22a/.git" "$here/22a/.git" "$here/22a/.git" sub/ &&
+	try_case 22a/.git/sub unset "$here/22a/.git" \
+		"$here/22a/.git" "$here/22a/.git" "$here/22a/.git" sub/ &&
+
+	try_case 22ab/.git unset . \
+		. "$here/22ab/.git" "$here/22ab/.git" "(null)" &&
+	try_case 22ab/.git unset "$here/22ab/.git" \
+		"$here/22ab/.git" "$here/22ab/.git" "$here/22ab/.git" "(null)" &&
+	try_case 22ab/.git/sub unset .. \
+		"$here/22ab/.git" "$here/22ab/.git" "$here/22ab/.git" sub/ &&
+	try_case 22ab/.git unset "$here/22ab/.git" \
+		"$here/22ab/.git" "$here/22ab/.git" "$here/22ab/.git" "(null)"
 '
 
-#
-# 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 '#22b: core.worktree child of .git, GIT_DIR=.git' '
+	setup_repo 22b "$here/22b/.git/wt" "" unset &&
+	setup_repo 22bb wt "" unset &&
+	mkdir -p 22b/.git/sub 22b/sub 22b/.git/wt/sub 22b/wt/sub &&
+	mkdir -p 22bb/.git/sub 22bb/sub 22bb/.git/wt 22bb/wt &&
 
+	try_case 22b/.git unset . \
+		. "$here/22b/.git/wt" "$here/22b/.git" "(null)" &&
+	try_case 22b/.git unset "$here/22b/.git" \
+		"$here/22b/.git" "$here/22b/.git/wt" "$here/22b/.git" "(null)" &&
+	try_case 22b/.git/sub unset .. \
+		.. "$here/22b/.git/wt" "$here/22b/.git/sub" "(null)" &&
+	try_case 22b/.git/sub unset "$here/22b/.git" \
+		"$here/22b/.git" "$here/22b/.git/wt" "$here/22b/.git/sub" "(null)" &&
+
+	try_case 22bb/.git unset . \
+		. "$here/22bb/.git/wt" "$here/22bb/.git" "(null)" &&
+	try_case 22bb/.git unset "$here/22bb/.git" \
+		"$here/22bb/.git" "$here/22bb/.git/wt" "$here/22bb/.git" "(null)" &&
+	try_case 22bb/.git/sub unset .. \
+		.. "$here/22bb/.git/wt" "$here/22bb/.git/sub" "(null)" &&
+	try_case 22bb/.git/sub unset "$here/22bb/.git" \
+		"$here/22bb/.git" "$here/22bb/.git/wt" "$here/22bb/.git/sub" "(null)"
+'
+
+test_expect_success '#22c: core.worktree = .git/.., GIT_DIR=.git' '
+	setup_repo 22c "$here/22c" "" unset &&
+	setup_repo 22cb .. "" unset &&
+	mkdir -p 22c/.git/sub 22c/sub &&
+	mkdir -p 22cb/.git/sub 22cb/sub &&
+
+	try_case 22c/.git unset . \
+		"$here/22c/.git" "$here/22c" "$here/22c" .git/ &&
+	try_case 22c/.git unset "$here/22c/.git" \
+		"$here/22c/.git" "$here/22c" "$here/22c" .git/ &&
+	try_case 22c/.git/sub unset .. \
+		"$here/22c/.git" "$here/22c" "$here/22c" .git/sub/ &&
+	try_case 22c/.git/sub unset "$here/22c/.git" \
+		"$here/22c/.git" "$here/22c" "$here/22c" .git/sub/ &&
+
+	try_case 22cb/.git unset . \
+		"$here/22cb/.git" "$here/22cb" "$here/22cb" .git/ &&
+	try_case 22cb/.git unset "$here/22cb/.git" \
+		"$here/22cb/.git" "$here/22cb" "$here/22cb" .git/ &&
+	try_case 22cb/.git/sub unset .. \
+		"$here/22cb/.git" "$here/22cb" "$here/22cb" .git/sub/ &&
+	try_case 22cb/.git/sub unset "$here/22cb/.git" \
+		"$here/22cb/.git" "$here/22cb" "$here/22cb" .git/sub/
+'
+
+test_expect_success '#22.2: core.worktree and core.bare conflict' '
+	setup_repo 22 "$here/22" "" true &&
+	(
+		cd 22/.git &&
+		GIT_DIR=. &&
+		export GIT_DIR &&
+		test_must_fail git symbolic-ref HEAD 2>result
+	) &&
+	(
+		cd 22 &&
+		GIT_DIR=.git &&
+		export GIT_DIR &&
+		test_must_fail git symbolic-ref HEAD 2>result
+	) &&
+	grep "core.bare and core.worktree" 22/.git/result &&
+	grep "core.bare and core.worktree" 22/result
+'
+
+# Case #23: GIT_DIR + GIT_WORK_TREE(+core.worktree) suppresses bareness.
 test_expect_success '#23: setup' '
-	sane_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 ..
+	setup_repo 23 non-existent "" true &&
+	mkdir -p 23/sub/sub 23/wt/sub
+'
+run_wt_tests 23
+
+test_expect_success '#24: bare repo has no worktree (gitfile case)' '
+	try_repo 24 unset unset unset gitfile true \
+		"$here/24.git" "(null)" "$here/24" "(null)" \
+		"$here/24.git" "(null)" "$here/24/sub" "(null)"
 '
 
-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 '#25: GIT_WORK_TREE accepted if GIT_DIR unset (bare gitfile case)' '
+	try_repo 25 "$here/25" unset unset gitfile true \
+		"$here/25.git" "$here/25" "$here/25" "(null)"  \
+		"$here/25.git" "$here/25" "$here/25" "sub/" 2>message &&
+	! test -s message
 '
 
-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 '#26: bare repo has no worktree (GIT_DIR -> gitfile case)' '
+	try_repo 26 unset "$here/26/.git" unset gitfile true \
+		"$here/26.git" "(null)" "$here/26" "(null)" \
+		"$here/26.git" "(null)" "$here/26/sub" "(null)" &&
+	try_repo 26b unset .git unset gitfile true \
+		"$here/26b.git" "(null)" "$here/26b" "(null)" \
+		"$here/26b.git" "(null)" "$here/26b/sub" "(null)"
 '
 
-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' '
-	sane_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' '
-	sane_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' '
-	sane_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
-
+# Case #27: GIT_DIR + GIT_WORK_TREE suppresses bareness (with gitfile).
 test_expect_success '#27: setup' '
-	sane_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 ..
+	setup_repo 27 unset gitfile true &&
+	mkdir -p 27/sub/sub 27/wt/sub
 '
+run_wt_tests 27 gitfile
 
-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' '
-	sane_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' '
-	sane_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' '
-	sane_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' '
+test_expect_success '#28: core.worktree and core.bare conflict (gitfile case)' '
+	setup_repo 28 "$here/28" gitfile true &&
 	(
-	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
-	)
+		cd 28 &&
+		test_must_fail git symbolic-ref HEAD
+	) 2>message &&
+	! grep "^warning:" message &&
+	grep "core.bare and core.worktree" message
 '
 
-#
-# 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
+# Case #29: GIT_WORK_TREE(+core.worktree) overrides core.bare (gitfile case).
+test_expect_success '#29: setup' '
+	setup_repo 29 non-existent gitfile true &&
+	mkdir -p 29/sub/sub 29/wt/sub
+	(
+		cd 29 &&
+		GIT_WORK_TREE="$here/29" &&
+		export GIT_WORK_TREE &&
+		git symbolic-ref HEAD >/dev/null
+	) 2>message &&
+	! test -s message
+'
+run_wt_tests 29 gitfile
 
+test_expect_success '#30: core.worktree and core.bare conflict (gitfile version)' '
+	# Just like case #22.
+	setup_repo 30 "$here/30" gitfile true &&
+	(
+		cd 30 &&
+		GIT_DIR=.git &&
+		export GIT_DIR &&
+		test_must_fail git symbolic-ref HEAD 2>result
+	) &&
+	grep "core.bare and core.worktree" 30/result
+'
+
+# Case #31: GIT_DIR + GIT_WORK_TREE(+core.worktree) suppresses
+# bareness (gitfile version).
 test_expect_success '#31: setup' '
-	sane_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 ..
+	setup_repo 31 non-existent gitfile true &&
+	mkdir -p 31/sub/sub 31/wt/sub
 '
-
-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"
-'
+run_wt_tests 31 gitfile
 
 test_done
diff --git a/t/t3032-merge-recursive-options.sh b/t/t3032-merge-recursive-options.sh
index de9ff89..44f5421 100755
--- a/t/t3032-merge-recursive-options.sh
+++ b/t/t3032-merge-recursive-options.sh
@@ -13,9 +13,12 @@
 
 . ./test-lib.sh
 
+test_have_prereq SED_STRIPS_CR && SED_OPTIONS=-b
+test_have_prereq MINGW && export GREP_OPTIONS=-U
+
 test_expect_success 'setup' '
 	conflict_hunks () {
-		sed -n -e "
+		sed $SED_OPTIONS -n -e "
 			/^<<<</ b conflict
 			b
 			: conflict
diff --git a/t/t4018-diff-funcname.sh b/t/t4018-diff-funcname.sh
index 0a61b57..3646930 100755
--- a/t/t4018-diff-funcname.sh
+++ b/t/t4018-diff-funcname.sh
@@ -32,7 +32,7 @@
 
 sed 's/beer\\/beer,\\/' < Beer.java > Beer-correct.java
 
-builtin_patterns="bibtex cpp csharp fortran html java objc pascal php python ruby tex"
+builtin_patterns="bibtex cpp csharp fortran html java objc pascal perl php python ruby tex"
 for p in $builtin_patterns
 do
 	test_expect_success "builtin $p pattern compiles" '
diff --git a/t/t6038-merge-text-auto.sh b/t/t6038-merge-text-auto.sh
index 460bf74..d9c2d38 100755
--- a/t/t6038-merge-text-auto.sh
+++ b/t/t6038-merge-text-auto.sh
@@ -14,7 +14,7 @@
 
 . ./test-lib.sh
 
-test_have_prereq MINGW && SED_OPTIONS=-b
+test_have_prereq SED_STRIPS_CR && SED_OPTIONS=-b
 
 test_expect_success setup '
 	git config core.autocrlf false &&
diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh
index 2c49db9..874279e 100755
--- a/t/t7400-submodule-basic.sh
+++ b/t/t7400-submodule-basic.sh
@@ -446,4 +446,42 @@
 	)
 '
 
+test_expect_success 'set up for relative path tests' '
+	mkdir reltest &&
+	(
+		cd reltest &&
+		git init &&
+		mkdir sub &&
+		(
+			cd sub &&
+			git init &&
+			test_commit foo
+		) &&
+		git add sub &&
+		git config -f .gitmodules submodule.sub.path sub &&
+		git config -f .gitmodules submodule.sub.url ../subrepo &&
+		cp .git/config pristine-.git-config
+	)
+'
+
+test_expect_success 'relative path works with URL' '
+	(
+		cd reltest &&
+		cp pristine-.git-config .git/config &&
+		git config remote.origin.url ssh://hostname/repo &&
+		git submodule init &&
+		test "$(git config submodule.sub.url)" = ssh://hostname/subrepo
+	)
+'
+
+test_expect_success 'relative path works with user@host:path' '
+	(
+		cd reltest &&
+		cp pristine-.git-config .git/config &&
+		git config remote.origin.url user@host:repo &&
+		git submodule init &&
+		test "$(git config submodule.sub.url)" = user@host:subrepo
+	)
+'
+
 test_done
diff --git a/t/t9010-svn-fe.sh b/t/t9010-svn-fe.sh
index c96bf2f..88a9751 100755
--- a/t/t9010-svn-fe.sh
+++ b/t/t9010-svn-fe.sh
@@ -4,22 +4,6 @@
 
 . ./test-lib.sh
 
-if ! svnadmin -h >/dev/null 2>&1
-then
-	skip_all='skipping svn-fe tests, svn not available'
-	test_done
-fi
-
-svnconf=$PWD/svnconf
-export svnconf
-
-svn_cmd () {
-	subcommand=$1 &&
-	shift &&
-	mkdir -p "$svnconf" &&
-	svn "$subcommand" --config-dir "$svnconf" "$@"
-}
-
 reinit_git () {
 	rm -fr .git &&
 	git init
@@ -41,10 +25,21 @@
 	test_cmp empty stream
 '
 
-test_expect_success 't9135/svn.dump' '
-	svnadmin create simple-svn &&
-	svnadmin load simple-svn <"$TEST_DIRECTORY/t9135/svn.dump" &&
-	svn_cmd export "file://$PWD/simple-svn" simple-svnco &&
+test_expect_success 'set up svn repo' '
+	svnconf=$PWD/svnconf &&
+	mkdir -p "$svnconf" &&
+
+	if
+		svnadmin -h >/dev/null 2>&1 &&
+		svnadmin create simple-svn &&
+		svnadmin load simple-svn <"$TEST_DIRECTORY/t9135/svn.dump" &&
+		svn export --config-dir "$svnconf" "file://$PWD/simple-svn" simple-svnco
+	then
+		test_set_prereq SVNREPO
+	fi
+'
+
+test_expect_success SVNREPO 't9135/svn.dump' '
 	git init simple-git &&
 	test-svn-fe "$TEST_DIRECTORY/t9135/svn.dump" >simple.fe &&
 	(
diff --git a/t/t9157-git-svn-fetch-merge.sh b/t/t9157-git-svn-fetch-merge.sh
index accf61e..991d2aa 100755
--- a/t/t9157-git-svn-fetch-merge.sh
+++ b/t/t9157-git-svn-fetch-merge.sh
@@ -8,7 +8,7 @@
 
 svn_ver="$(svn --version --quiet)"
 case $svn_ver in
-[0-1].[0-4].[0-6])
+0.* | 1.[0-4].*)
 	skip_all="skipping git-svn test - SVN too old ($svn_ver)"
 	test_done
 	;;
diff --git a/t/test-lib.sh b/t/test-lib.sh
index cb1ca97..42f2f14 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -1057,6 +1057,13 @@
 	# backslashes in pathspec are converted to '/'
 	# exec does not inherit the PID
 	test_set_prereq MINGW
+	test_set_prereq SED_STRIPS_CR
+	;;
+*CYGWIN*)
+	test_set_prereq POSIXPERM
+	test_set_prereq EXECKEEPSPID
+	test_set_prereq NOT_MINGW
+	test_set_prereq SED_STRIPS_CR
 	;;
 *)
 	test_set_prereq POSIXPERM
diff --git a/userdiff.c b/userdiff.c
index 2346978..9ebf231 100644
--- a/userdiff.c
+++ b/userdiff.c
@@ -61,6 +61,23 @@
 	 "|[-+0-9.e]+|0[xXbB]?[0-9a-fA-F]+"
 	 "|<>|<=|>=|:=|\\.\\."
 	 "|[^[:space:]]|[\x80-\xff]+"),
+PATTERNS("perl",
+	 "^[ \t]*package .*;\n"
+	 "^[ \t]*sub .* \\{\n"
+	 "^[A-Z]+ \\{\n"	/* BEGIN, END, ... */
+	 "^=head[0-9] ",	/* POD */
+	 /* -- */
+	 "[[:alpha:]_'][[:alnum:]_']*"
+	 "|0[xb]?[0-9a-fA-F_]*"
+	 /* taking care not to interpret 3..5 as (3.)(.5) */
+	 "|[0-9a-fA-F_]+(\\.[0-9a-fA-F_]+)?([eE][-+]?[0-9_]+)?"
+	 "|=>|-[rwxoRWXOezsfdlpSugkbctTBMAC>]|~~|::"
+	 "|&&=|\\|\\|=|//=|\\*\\*="
+	 "|&&|\\|\\||//|\\+\\+|--|\\*\\*|\\.\\.\\.?"
+	 "|[-+*/%.^&<>=!|]="
+	 "|=~|!~"
+	 "|<<|<>|<=>|>>"
+	 "|[^[:space:]]"),
 PATTERNS("php",
 	 "^[\t ]*(((public|protected|private|static)[\t ]+)*function.*)$\n"
 	 "^[\t ]*(class.*)$",
diff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c
index fa580e6..2ad2c30 100644
--- a/vcs-svn/svndump.c
+++ b/vcs-svn/svndump.c
@@ -211,7 +211,7 @@
 		if (key == keys.svn_fs_dump_format_version) {
 			dump_ctx.version = atoi(val);
 			if (dump_ctx.version > 2)
-				die("expected svn dump format version <= 2, found %d",
+				die("expected svn dump format version <= 2, found %"PRIu32,
 				    dump_ctx.version);
 		} else if (key == keys.uuid) {
 			dump_ctx.uuid = pool_intern(val);