Windows: worktree creation in an LFS repo creates a literal dev\null\ directory

Status Closed — duplicate
Maintainer reply None cached
Activity 2 comments · opened Jul 28, 2026 · closed Aug 15, 2026

Summary

On Windows, creating a Claude Code worktree in a Git LFS repository creates a literal dev\null\ directory at the repository root, containing four Git LFS hook files. It appears to come from a git lfs install invoked with core.hooksPath=/dev/null — an idiom that discards hooks on POSIX but materializes a real directory on Windows.

The directory shows up as untracked in git status and is easy to commit by accident with git add ..

Environment

  • OS: Windows 11 Home 10.0.26200
  • Claude Code: desktop app 1.0.1307 (CLI binary at ~\.local\bin\claude.exe)
  • Git: Git for Windows, with git-lfs at C:\Program Files\Git\cmd\git-lfs.exe
  • Repository uses Git LFS (.gitattributes contains *.dll filter=lfs diff=lfs merge=lfs -text)

Steps to reproduce

  1. On Windows, use a repository that has Git LFS configured (any filter=lfs entry in .gitattributes).
  2. Create a worktree from Claude Code (EnterWorktree, or the worktree UI).
  3. Run git status in the new worktree.

Expected

Clean worktree; no stray untracked files.

Actual

$ git status --short
?? dev/null/

$ ls dev/null/
post-checkout   360 bytes
post-commit     356 bytes
post-merge      354 bytes
pre-push        350 bytes

Each file is a standard Git LFS hook, e.g. pre-push:

#!/bin/sh
command -v git-lfs >/dev/null 2>&1 || { printf >&2 "\n%s\n\n" "This repository is configured for Git LFS but 'git-lfs' was not found on your path. ..."; exit 2; }
git lfs pre-push "$@"

Root cause

The four files are what git lfs install writes. Passing /dev/null as the hooks path is a common way to initialize LFS filters without touching hooks. On Windows there is no /dev/null, so Git resolves it as a path relative to the repository root and creates dev\null\.

Reproduced directly, outside Claude Code:

mkdir lfstest && cd lfstest
git init -q
git -c core.hooksPath=/dev/null lfs install
# -> Updated Git hooks.
# -> Git LFS initialized.

find dev
# dev
# dev/null
# dev/null/post-checkout   (360 bytes)
# dev/null/post-commit     (356 bytes)
# dev/null/post-merge      (354 bytes)
# dev/null/pre-push        (350 bytes)

Byte sizes match the files produced during worktree creation exactly.

Evidence that this is worktree creation

  • Present in 15 of 18 Claude Code worktrees on this machine; never in the main checkout.
  • dev\null\ is created 2–3 seconds after each worktree directory, consistently across ~3 weeks of worktrees.
  • A plain git worktree add --detach <path> HEAD does not reproduce it, so it is not git worktree add or the LFS post-checkout hook on its own.
  • Each worktree's config.worktree contains the hooks configuration Claude Code writes:

``ini
[core]
longpaths = true
hooksPath = C:\\path\\to\\main\\.git\\hooks
``

Impact

Cosmetic but persistent:

  • Permanently dirty git status in every worktree of an LFS repo on Windows.
  • Risk of committing four stray shell scripts via git add . / "commit everything" flows.
  • Mildly confusing — /dev/null is not an obvious thing to find checked into a repository.

The hooks themselves are inert. The real LFS hooks in .git/hooks are installed correctly and unaffected, so LFS keeps working.

Suggested fix

Use the platform-appropriate null device when suppressing hook installation — NUL on Windows, /dev/null elsewhere — or skip the hook-suppression flag entirely on Windows and clean up afterwards. Anything that avoids handing Git a POSIX-only absolute path it will resolve relative to the repo root.

Workaround

Delete the directory and ignore it:

/dev/null/

It reappears on each new worktree, but stays out of git status.

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗