From fc03fdc2e869384eb2d6423ff31f84e3cf22007e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iiro=20J=C3=A4ppinen?= Date: Sun, 15 Sep 2019 09:12:29 +0300 Subject: [PATCH] fix: keep untracked files around by backing them up Git diff completely ignores new, untracked files, but they can be read/written separately --- lib/gitWorkflow.js | 36 ++++++++++++++++++++++++++++++++++++ test/runAll.unmocked.spec.js | 19 +++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/lib/gitWorkflow.js b/lib/gitWorkflow.js index cf0518e84..b6d5af1d9 100644 --- a/lib/gitWorkflow.js +++ b/lib/gitWorkflow.js @@ -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') @@ -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]) @@ -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!') + } } /** diff --git a/test/runAll.unmocked.spec.js b/test/runAll.unmocked.spec.js index c3794e51d..3e9e9be47 100644 --- a/test/runAll.unmocked.spec.js +++ b/test/runAll.unmocked.spec.js @@ -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() + }) })