Skip to content

Commit

Permalink
fix: only run git add on staged files matched to a task
Browse files Browse the repository at this point in the history
# Conflicts:
#	lib/gitWorkflow.js
  • Loading branch information
iiroj committed Apr 9, 2020
1 parent a85c7b5 commit d39573b
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 7 deletions.
24 changes: 18 additions & 6 deletions lib/gitWorkflow.js
Expand Up @@ -3,6 +3,7 @@
const debug = require('debug')('lint-staged:git')
const path = require('path')

const chunkFiles = require('./chunkFiles')
const execGit = require('./execGit')
const { readFile, unlink, writeFile } = require('./file')

Expand Down Expand Up @@ -52,14 +53,15 @@ const handleError = (error, ctx) => {
}

class GitWorkflow {
constructor({ allowEmpty, gitConfigDir, gitDir, stagedFileChunks }) {
constructor({ allowEmpty, gitConfigDir, gitDir, matchedFiles, maxArgLength }) {
this.execGit = (args, options = {}) => execGit(args, { ...options, cwd: gitDir })
this.deletedFiles = []
this.gitConfigDir = gitConfigDir
this.gitDir = gitDir
this.unstagedDiff = null
this.allowEmpty = allowEmpty
this.stagedFileChunks = stagedFileChunks
this.matchedFiles = matchedFiles
this.maxArgLength = maxArgLength

/**
* These three files hold state about an ongoing git merge
Expand Down Expand Up @@ -235,12 +237,22 @@ class GitWorkflow {
*/
async applyModifications(ctx) {
debug('Adding task modifications to index...')
// stagedFileChunks includes staged files that lint-staged originally detected.
// `matchedFiles` includes staged files that lint-staged originally detected and matched against a task.
// Add only these files so any 3rd-party edits to other files won't be included in the commit.
// This is run "serially" to prevent race conditions because `git add` is a locking operation.
for (const stagedFiles of this.stagedFileChunks) {
await this.execGit(['add', '--', ...stagedFiles])
const files = Array.from(this.matchedFiles)
// Chunk files for better Windows compatibility
const matchedFileChunks = chunkFiles({
baseDir: this.gitDir,
files,
maxArgLength: this.maxArgLength
})

// These additions per chunk are run "serially" to prevent race conditions.
// Git add creates a lockfile in the repo causing concurrent operations to fail.
for (const files of matchedFileChunks) {
await this.execGit(['add', '--', ...files])
}

debug('Done adding task modifications to index!')

const stagedFilesAfterAdd = await this.execGit(['diff', '--name-only', '--cached'])
Expand Down
10 changes: 9 additions & 1 deletion lib/runAll.js
Expand Up @@ -125,6 +125,9 @@ const runAll = async (

const listrTasks = []

// Set of all staged files that matched a task glob. Values in a set are unique.
const matchedFiles = new Set()

for (const [index, files] of stagedFileChunks.entries()) {
const chunkTasks = generateTasks({ config, cwd, gitDir, files, relative })
const chunkListrTasks = []
Expand All @@ -137,6 +140,11 @@ const runAll = async (
shell
})

// Add files from task to match set
task.fileList.forEach(file => {
matchedFiles.add(file)
})

hasDeprecatedGitAdd = subTasks.some(subTask => subTask.command === 'git add')

chunkListrTasks.push({
Expand Down Expand Up @@ -188,7 +196,7 @@ const runAll = async (
return 'No tasks to run.'
}

const git = new GitWorkflow({ allowEmpty, gitConfigDir, gitDir, stagedFileChunks })
const git = new GitWorkflow({ allowEmpty, gitConfigDir, gitDir, matchedFiles, maxArgLength })

const runner = new Listr(
[
Expand Down

0 comments on commit d39573b

Please sign in to comment.