diff --git a/.changeset/tidy-voles-glide.md b/.changeset/tidy-voles-glide.md new file mode 100644 index 000000000..92bd662ce --- /dev/null +++ b/.changeset/tidy-voles-glide.md @@ -0,0 +1,5 @@ +--- +type: Fixed +pr: 2235 +--- +**`commit_docs` no longer silently disables on CRLF `.gitignore` repos** — git check-ignore falsely reports a trailing-slash path (e.g. `.planning/`) as ignored when the .gitignore has CRLF line endings with blank lines. isGitIgnored now strips trailing slashes before querying, so the false positive cannot occur. (#2206) diff --git a/src/config-loader.cts b/src/config-loader.cts index 2384f60a2..c5216dfb5 100644 --- a/src/config-loader.cts +++ b/src/config-loader.cts @@ -175,10 +175,14 @@ interface ParsedConfig { const _gitIgnoredCache = new Map(); function isGitIgnored(cwd: string, targetPath: string): boolean { - const key = cwd + '::' + targetPath; + // #2206: strip trailing slashes — `git check-ignore` has a quirk where a + // CRLF .gitignore with blank lines falsely reports a trailing-slash path + // (e.g. `.planning/`) as ignored. Normalizing here protects every call site. + const normalized = targetPath.replace(/\/+$/, ''); + const key = cwd + '::' + normalized; if (_gitIgnoredCache.has(key)) return _gitIgnoredCache.get(key)!; // --no-index checks .gitignore rules regardless of whether the file is tracked. - const result = execGit(['check-ignore', '-q', '--no-index', '--', targetPath], { cwd }); + const result = execGit(['check-ignore', '-q', '--no-index', '--', normalized], { cwd }); const ignored = result.exitCode === 0; _gitIgnoredCache.set(key, ignored); return ignored;