Windows: worktrees in git-lfs repos get a stray dev/null/ directory with LFS hooks (hooksPath suppression bypassed via GIT_CONFIG_PARAMETERS)
Summary
On Windows, every worktree created by the Claude desktop app (via createWorktree) in a git-lfs-enabled repo ends up with a stray untracked directory literally named dev/null/ at the worktree root, containing the four stock git-lfs hooks (post-checkout, post-commit, post-merge, pre-push).
Root cause
The desktop app's execGit helper (in app.asar) prepends these flags to git invocations to suppress hooks:
-c core.hooksPath=/dev/null -c safe.directory=* -c core.fsmonitor=false
When the worktree-creation flow runs git worktree add, the checkout step spawns git-lfs filter-process. That subprocess inherits core.hooksPath=/dev/null via GIT_CONFIG_PARAMETERS (git's mechanism for passing -c values to children) and, per git-lfs's own hook-install-on-checkout behavior, tries to (re)install its hooks at the configured hooksPath.
On Windows, Go's filepath.IsAbs("/dev/null") returns false (a leading / isn't an absolute path on Windows — that requires a drive letter). So git-lfs resolves /dev/null relative to the worktree root instead of recognizing it as the null device, and writes:
<worktree>/dev/null/post-checkout
<worktree>/dev/null/post-commit
<worktree>/dev/null/post-merge
<worktree>/dev/null/pre-push
On macOS/Linux this same code path writes to the real /dev/null and fails silently (or is a no-op), so the bug is Windows-only.
Environment
- Claude desktop 1.18286
- Claude Code 2.1.197
- git-lfs 3.7.1
- Windows 11
- Repro repo: any git-lfs-enabled repo (e.g. one tracking
*.onnx/*.wav)
Minimal repro
GIT_CONFIG_PARAMETERS="'core.hooksPath=/dev/null'" git worktree add --no-track -B probe <path> origin/main
→ <path>/dev/null/ appears with the 4 LFS hooks.
Note: running git -c core.hooksPath=/dev/null worktree add ... directly from Git Bash does not reproduce this — MSYS path conversion rewrites the /dev/null argument before git-lfs sees it. The desktop app spawns git directly (not through MSYS), so the literal string /dev/null passes through unmodified, which is why this only shows up from the app, not from a manual shell invocation.
Suggested fixes
- Desktop app: on Windows, use
-c core.hooksPath=NUL(or point at a real empty directory) instead of/dev/nullwhen suppressing hooks. - git-lfs (upstream, filed separately at git-lfs/git-lfs): special-case
/dev/nullas the null device on Windows, or skip hook installation entirely whencore.hooksPathresolves to a null device.
Impact
Low severity — the extra directory is harmless (git-ignorable, doesn't break functionality) but is confusing clutter in every worktree, and could plausibly interfere with tooling that walks the worktree root.