8000 fix: only stage changes to deleted files if they're no longer deleted… · lint-staged/lint-staged@a7c0c88 · GitHub
[go: up one dir, main page]

Skip to content

Commit a7c0c88

Browse files
committed
fix: only stage changes to deleted files if they're no longer deleted after running tasks
1 parent ccd5edd commit a7c0c88

File tree

3 files changed

+52
-2
lines changed

3 files changed

+52
-2
lines changed

.changeset/khaki-laws-relate.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'lint-staged': patch
3+
---
4+
5+
When using `--diff-filter` with the `D` option to include deleted staged files, _lint-staged_ no longer tries to stage the deleted files, unless they're no longer deleted. Previously this caused an error from `git add` like `fatal: pathspec 'deleted-file' did not match any files`.

lib/gitWorkflow.js

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import fs from 'node:fs/promises'
12
import path from 'node:path'
23

34
import debug from 'debug'
@@ -279,8 +280,22 @@ export class GitWorkflow {
279280
// These additions per chunk are run "serially" to prevent race conditions.
280281
// Git add creates a lockfile in the repo causing concurrent operations to fail.
281282
for (const files of this.matchedFileChunks) {
282-
/** @todo Deleted files cannot be staged because they're... deleted */
283-
await this.execGit(['add', '--', ...files.map((f) => f.filepath)])
283+
const accessCheckedFiles = await Promise.allSettled(
284+
files.map(async (f) => {
285+
if (f.status === 'D') {
286+
await fs.access(f.filepath)
287+
return f.filepath // File is no longer deleted and can be added
288+
} else {
289+
return f.filepath
290+
}
291+
})
292+
)
293+
294+
const addableFiles = accessCheckedFiles.flatMap((r) =>
295+
r.status === 'fulfilled' ? [r.value] : []
296+
)
297+
298+
await this.execGit(['add', '--', ...addableFiles])
284299
}
285300

286301
debugLog('Done adding task modifications to index!')

test/integration/diff-options.test.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,36 @@ describe('lint-staged', () => {
9797
})
9898
)
9999

100+
test(
101+
'supports staged deleted files restored by linter',
102+
withGitIntegration(async ({ appendFile, cwd, execGit }) => {
103+
const globalConsoleTemp = console
104+
console = makeConsoleMock()
105+
106+
// Stage and commit ugly file
107+
await appendFile('test.js', fileFixtures.uglyJS)
108+
await execGit(['add', 'test.js'])
109+
await execGit(['commit', '-m', 'test'])
110+
111+
// Staged deleted file
112+
await execGit(['rm', 'test.js'])
113+
114+
// Run lint-staged with `--diff-filter=D` to include only deleted files.
115+
// Use git to restore deleted staged file and then prettify it
116+
const passed = await lintStaged({
117+
config: { '*.js': ['git reset --', 'git checkout --', 'prettier --write'] },
118+
cwd,
119+
diffFilter: 'D',
120+
})
121+
122+
expect(passed).toEqual(false)
123+
expect(console.printHistory()).not.toMatch('No files matching the pattern were found:')
124+
expect(console.printHistory()).toMatch('lint-staged prevented an empty git commit.')
125+
126+
console = globalConsoleTemp
127+
})
128+
)
129+
100130
test(
101131
'supports staged deleted files not processed by linter',
102132
withGitIntegration(async ({ appendFile, cwd, execGit }) => {

0 commit comments

Comments
 (0)
0