diff --git a/vcsh b/vcsh
index 3fa63d7bf266a698a8a1804fb8ae4152a41d9b5f..d45e95d927925fa31e45deadd7e19f409a94ae9b 100755
--- a/vcsh
+++ b/vcsh
@@ -197,9 +197,8 @@ hook() {
 
 init() {
 	[ ! -e "$GIT_DIR" ] || fatal "'$GIT_DIR' exists" 10
-	export GIT_WORK_TREE="$VCSH_BASE"
-	mkdir -p "$GIT_WORK_TREE" || fatal "could not create '$GIT_WORK_TREE'" 50
-	cd "$GIT_WORK_TREE" || fatal "could not enter '$GIT_WORK_TREE'" 11
+	mkdir -p "$VCSH_BASE" || fatal "could not create '$VCSH_BASE'" 50
+	cd "$VCSH_BASE" || fatal "could not enter '$VCSH_BASE'" 11
 	git init
 	upgrade
 }
@@ -275,17 +274,22 @@ run() {
 
 upgrade() {
 	hook pre-upgrade
-	use
-	git config core.worktree     "$GIT_WORK_TREE"
+	# fake-bare repositories are not bare, actually. Set this to false
+	# because otherwise Git complains "fatal: core.bare and core.worktree
+	# do not make sense"
+	git config core.bare false
+	# in core.worktree, keep a relative reference to the base directory
+	git config core.worktree $(cd $GIT_DIR && GIT_WORK_TREE="$VCSH_BASE" git rev-parse --show-cdup)
 	[ ! "x$VCSH_GITIGNORE" = 'xnone' ] && git config core.excludesfile ".gitignore.d/$VCSH_REPO_NAME"
 	git config vcsh.vcsh         'true'
+	use
 	[ -e "$VCSH_BASE/.gitignore.d/$VCSH_REPO_NAME" ] && git add -f "$VCSH_BASE/.gitignore.d/$VCSH_REPO_NAME"
 	hook post-upgrade
 }
 
 use() {
 	git_dir_exists
-	export GIT_WORK_TREE="$(git config --get core.worktree)"
+	export GIT_WORK_TREE="$(git rev-parse --show-toplevel)"
 	export VCSH_DIRECTORY="$VCSH_REPO_NAME"
 }