-
-
Notifications
You must be signed in to change notification settings - Fork 4.7k
Description
In a https://git-scm.com/docs/git-worktree, .git is a file (containing gitdir: ...) rather than a directory. Prettier's project root detection (find-project-root.js) uses search-closest with DirectorySearcher to look for .git, which only matches directories. This causes prettier to miss the worktree's .git file and walk up the filesystem, potentially picking up unrelated .editorconfig files (e.g., ~/.editorconfig).
Environments:
- Prettier Version: 3.8.1
- Running Prettier via: CLI
- Runtime: Node.js v24.11.1
- Operating System: macOS
- Prettier plugins (if any): N/A
Steps to reproduce:
Run the reproduction script below, or manually:
- Create ~/.editorconfig with indent_style = tab
- git init main-repo && cd main-repo
- Create a space-indented test.js, install prettier, commit
- prettier --check test.js → passes, resolveConfig returns null
- git worktree add ../worktree && cd ../worktree
- prettier --check test.js → fails, resolveConfig returns {"useTabs":true}
Script to reproduce:
#!/usr/bin/env bash
set -euo pipefail
# Reproduction script for prettier editorconfig + git worktree bug.
#
# In a git worktree, .git is a file (not a directory). Prettier uses .git
# as the project root boundary when resolving .editorconfig files. Because
# it only looks for .git as a directory, it misses the worktree's .git file
# and walks up to parent directories — potentially picking up unrelated
# .editorconfig files (e.g. ~/.editorconfig).
REPRO_DIR=$(mktemp -d "$HOME/prettier-repro-XXXXXX")
EDITORCONFIG_BAK=""
echo "=== Setup ==="
echo "Repro dir: $REPRO_DIR"
# Back up existing ~/.editorconfig if present
if [ -f "$HOME/.editorconfig" ]; then
EDITORCONFIG_BAK="$HOME/.editorconfig.bak.$$"
cp "$HOME/.editorconfig" "$EDITORCONFIG_BAK"
echo "Backed up existing ~/.editorconfig to $EDITORCONFIG_BAK"
fi
cleanup() {
# Restore original ~/.editorconfig
if [ -n "$EDITORCONFIG_BAK" ] && [ -f "$EDITORCONFIG_BAK" ]; then
mv "$EDITORCONFIG_BAK" "$HOME/.editorconfig"
echo "Restored ~/.editorconfig"
else
rm -f "$HOME/.editorconfig"
fi
rm -rf "$REPRO_DIR"
echo "Cleaned up $REPRO_DIR"
}
trap cleanup EXIT
# Create a ~/.editorconfig that uses tabs
cat > "$HOME/.editorconfig" << 'EOF'
root = true
[*]
indent_style = tab
EOF
echo "Created ~/.editorconfig with indent_style = tab"
# --- Step 1: Create a git repo with a space-indented file ---
cd "$REPRO_DIR"
git init main-repo --quiet
cd main-repo
cat > test.js << 'EOF'
function hello() {
console.log("hello");
if (true) {
console.log("world");
}
}
EOF
npm init -y > /dev/null 2>&1
npm install [email protected] --save-dev > /dev/null 2>&1
git add -A
git commit -m "initial" --quiet
# --- Step 2: Verify formatting passes in the main repo ---
echo ""
echo "=== Main repo (.git is a directory) ==="
file .git
echo "Resolved editorconfig options:"
node -e "
const prettier = require('prettier');
prettier.resolveConfig('./test.js', { editorconfig: true })
.then(c => console.log(JSON.stringify(c)));
"
echo -n "prettier --check: "
npx prettier --check test.js 2>&1 | tail -1
# --- Step 3: Create a worktree ---
git worktree add ../worktree-repo -b worktree-branch --quiet 2>&1
# --- Step 4: Verify formatting FAILS in the worktree ---
cd ../worktree-repo
echo ""
echo "=== Worktree (.git is a file) ==="
file .git
echo ".git contents: $(cat .git)"
echo "Resolved editorconfig options:"
node -e "
const prettier = require('prettier');
prettier.resolveConfig('./test.js', { editorconfig: true })
.then(c => console.log(JSON.stringify(c)));
"
echo -n "prettier --check: "
npx prettier --check test.js 2>&1 | tail -1 || true
echo ""
echo "=== Result ==="
echo "In the main repo, .git is a directory and prettier correctly"
echo "uses it as the project root boundary for editorconfig resolution."
echo ""
echo "In the worktree, .git is a file and prettier does not recognize"
echo "it as a project root boundary. It walks up the filesystem and"
echo "picks up ~/.editorconfig (indent_style = tab), causing formatting"
echo "to differ between the main repo and the worktree."
Expected behavior:
Both the main repo and worktree should resolve the same editorconfig options.
Actual behavior:
Prettier ends up reporting different results in the worktree due to the unrelated .editorconfig file.
Root cause:
src/config/find-project-root.js
uses DirectorySearcher from search-closest which only matches .git as a directory, not as a file.