Skip to content

Commit

Permalink
fix: keep untracked files around by backing them up
Browse files Browse the repository at this point in the history
Git diff completely ignores new, untracked files, but they can be read/written separately
  • Loading branch information
iiroj committed Nov 14, 2019
1 parent 90da8a8 commit fc03fdc
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 0 deletions.
36 changes: 36 additions & 0 deletions lib/gitWorkflow.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict'

const debug = require('debug')('lint-staged:git')
const normalize = require('normalize-path')
const path = require('path')

const execGit = require('./execGit')
Expand Down Expand Up @@ -68,6 +69,31 @@ class GitWorkflow {
debug('Done backing up merge state!')
}

// Git stash ignores new, untracked files, so back them up separately
// Use `git ls-files` to list untracked files:
// `--others includes` all untracked files, including ignored files
// `--exclude-standard` excludes ignored files, the .git/ dir and so on...
let untrackedFiles = await this.execGit(['ls-files', '--others', '--exclude-standard'])
if (untrackedFiles) {
debug('Detected untracked files:')
debug(untrackedFiles)
debug('Backing up untracked files...')
// Resolve untrackedFiles output into filenames
untrackedFiles = untrackedFiles
.split('\n')
.map(file => normalize(path.resolve(this.cwd, file)))
this.untrackedFiles = new Map()
const readPromises = []
for (const file of untrackedFiles) {
// Read all untracked files into buffers, and save them into internal Map
readPromises.push(
readBufferFromFile(file).then(buffer => this.untrackedFiles.set(file, buffer))
)
}
await Promise.all(readPromises)
debug('Done backing up untracked files!')
}

// Get stash of entire original state, including unstaged changes
// Keep index so that tasks only work on those files
await this.execGit(['stash', 'save', '--quiet', '--include-untracked', '--keep-index', STASH])
Expand Down Expand Up @@ -107,6 +133,16 @@ class GitWorkflow {
}
}
debug('Done restoring unstaged changes!')

if (this.untrackedFiles) {
debug('Restoring untracked files...')
const writePromises = []
this.untrackedFiles.forEach((buffer, file) => {
writePromises.push(writeBufferToFile(file, buffer))
})
await Promise.all(writePromises)
debug('Done restoring untracked files!')
}
}

/**
Expand Down
19 changes: 19 additions & 0 deletions test/runAll.unmocked.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -450,4 +450,23 @@ describe('runAll', () => {
`)
expect(await readFile('test.js')).toEqual(fileInBranchBFixed)
})

it('should keep untracked files', async () => {
// Stage pretty file
await appendFile('test.js', testJsFilePretty)
await execGit(['add', 'test.js'])

// Add another file, but keep it untracked
await appendFile('test-untracked.js', testJsFilePretty)

// Run lint-staged with `prettier --list-different` and commit pretty file
await gitCommit({ config: { '*.js': 'prettier --list-different' } })

// Nothing is wrong, so a new commit is created
expect(await execGit(['rev-list', '--count', 'HEAD'])).toEqual('2')
expect(await execGit(['log', '-1', '--pretty=%B'])).toMatch('test')
expect(await readFile('test.js')).toEqual(testJsFilePretty)
expect(await readFile('test-untracked.js')).toEqual(testJsFilePretty)
console = makeConsoleMock()
})
})

0 comments on commit fc03fdc

Please sign in to comment.