git-detect-case-change
v1.1.2
Published
Detect file name case changes in a Git repository
Maintainers
Readme
git-detect-case-change
Detect and fix case-only filename changes that Git can't see on macOS/Windows.
On case-insensitive filesystems, renaming utils.ts → Utils.ts won't register in Git.
This tool compares Git's tree with the filesystem and fixes mismatches in both directions.
# Renamed foo.js → Foo.js but Git didn't notice?
npx git-detect-case-change # Stage the case change in Git
npx git-detect-case-change --fix-local # Rename local files to match GitSupport this project by ⭐️ starring and sharing it. Follow me to see what other projects I'm working on.
Usage
The CLI supports two main modes:
# Stage local case changes to Git (most common)
npx git-detect-case-change
# Rename local files to match Git's case (after pulling teammate's changes)
npx git-detect-case-change --fix-local
# See what would change without modifying anything
npx git-detect-case-change --dryExample output:
$ npx git-detect-case-change
src/utils.ts -> src/Utils.ts
lib/helper.js -> lib/Helper.jsWhen to use it
- Bundlers (Vite/Webpack/Rollup) error due to mismatched import casing
- CI fails on Linux but your Mac build passes
- Git doesn't show a rename even though you changed the file
- Teammate pushed case-only changes and your local filesystem is out of sync
What it does
This tool finds and fixes case mismatches between Git and the filesystem:
| You want to… | Command | Effect |
| ------------------------------------------------- | ---------------------------------------- | --------------------------------- |
| Stage local case changes to Git | npx git-detect-case-change | Stages the rename with git mv |
| Rename local files to match Git (e.g. after pull) | npx git-detect-case-change --fix-local | Renames local files to Git's case |
Options
Dry run:
npx git-detect-case-change --dry
npx git-detect-case-change --fix-local --dryLimit to specific paths:
npx git-detect-case-change -- <dir-or-file>macOS and Windows default to case-insensitive filesystems. Git respects the underlying filesystem, so it can't reliably detect case-only renames.
The official workaround is:
git mv <old-path> <new-path>This gets tedious when:
- Many files changed at once
- Renames came from automated refactors
- You inherited case drift from someone else
This tool automates that detection. See this StackOverflow discussion for more context.
Reads file paths from Git's index:
git ls-tree --name-only -z -r HEAD-zuses NUL terminators so filenames with spaces or special characters are safe.Detects case mismatches:
For each Git path, uses
fs.promises.existsto look up the actual filesystem path in a case-insensitive way. Files are processed in batches of 100 to avoid file descriptor limits on large repos.Applies fixes based on mode:
Default mode: Stages changes with
git mv <git-path> <local-path>--fix-localmode: Renames local files/directories to match Git's case:- Directories first: Extracts unique directory changes and renames them (deepest first)
- Files second: Renames remaining files with case-only differences
- Two-step rename: Uses temporary path (
file.tmp-<pid>-<timestamp>) to work around case-insensitive filesystem limitations - Transactional rollback: If the second rename fails, attempts to restore from temporary path to prevent data loss
