Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Pre-commit hook for eslint, linting *only* staged changes.
#!/bin/bash
for file in $(git diff --cached --name-only | grep -E '\.(js|jsx)$')
do
git show ":$file" | node_modules/.bin/eslint --stdin --stdin-filename "$file" # we only want to lint the staged changes, not any un-staged changes
if [ $? -ne 0 ]; then
echo "ESLint failed on staged file '$file'. Please check your code and try again. You can run ESLint manually via npm run eslint."
exit 1 # exit with failure status
fi
done
@gichuwil

This comment has been minimized.

Copy link

@gichuwil gichuwil commented Sep 9, 2016

Thanks. Very helpful.

@Fer0x

This comment has been minimized.

Copy link

@Fer0x Fer0x commented Jan 20, 2017

Option --diff-filter=d should be specified in git diff to exclude deleted files.

@alburritos

This comment has been minimized.

Copy link

@alburritos alburritos commented Jan 28, 2017

@Fer0x Where would that go?

@rashtay

This comment has been minimized.

Copy link

@rashtay rashtay commented Apr 24, 2017

@Alberth8 It'd be like this -> git diff --diff-filter=d --cached --name-only

@gilesbutler

This comment has been minimized.

Copy link

@gilesbutler gilesbutler commented May 30, 2017

Thanks @dahjelle! Great stuff :)

@solo474

This comment has been minimized.

Copy link

@solo474 solo474 commented Aug 8, 2017

Thank you very much

@julianlam

This comment has been minimized.

Copy link

@julianlam julianlam commented Aug 23, 2017

eslint is quite slow when it runs against my entire project, this is much faster, thanks!!

@SalTor

This comment has been minimized.

Copy link

@SalTor SalTor commented Dec 19, 2017

Has anyone figured out a workflow for using the --fix flag during this pre-commit hook?

What I've come across is that when the pre-commit hook is triggered for files that are staged, the new changes aren't included in the commit.

It makes sense why it wouldn't be included: this is changing a staged file, and those changes would also have to be staged.

lint-staged has a partly-working fix for this, however, and as they note, this doesn't work for partially-staged files, AKA files whose changes have been cherry-picked for a commit.

@artem-litvinov

This comment has been minimized.

Copy link

@artem-litvinov artem-litvinov commented Jan 30, 2018

@SalTor take a look at this. It works well for me.

@suyanhanx

This comment has been minimized.

Copy link

@suyanhanx suyanhanx commented Apr 20, 2018

Thank you very much.

@jancimajek

This comment has been minimized.

Copy link

@jancimajek jancimajek commented Apr 24, 2018

One-liner version of the above:

git diff --diff-filter=d --cached --name-only | grep -E '\.(js|jsx)$' | xargs -I % sh -c 'git show ":%" | eslint --stdin --stdin-filename "%";'
@richistron

This comment has been minimized.

Copy link

@richistron richistron commented Apr 24, 2018

you can do this in one line git diff --cached --name-only | grep ".js$" | xargs ./node_modules/.bin/eslint

@Brantron

This comment has been minimized.

Copy link

@Brantron Brantron commented Apr 25, 2018

nice, @richistron

@luuuis

This comment has been minimized.

Copy link

@luuuis luuuis commented May 11, 2018

@jancimajek's one-liner is great but does not handle spaces (and other funny chars) in the filename. Using git diff -z with xargs -0 handles that nicely: luuuis/pre-commit.sh.

The @richistron one liner will lint the changed files in the local checkout, which is not necessarily what is being committed to Git if you have not staged every hunk in a file.

@TNT-Likely

This comment has been minimized.

Copy link

@TNT-Likely TNT-Likely commented Sep 29, 2018

thanks

@sampathBlam

This comment has been minimized.

Copy link

@sampathBlam sampathBlam commented Mar 14, 2019

Thanks @dahjelle.

@lifenstein

This comment has been minimized.

Copy link

@lifenstein lifenstein commented Jul 4, 2019

The scripts above works well enough for a handful of changes, but for large projects when things like a project-wide search & replace is performed, it takes ages because the files are sent one by one to eslint. Running over the whole project only takes 20 seconds, but the commit hook takes 4 minutes! Is there a way to batch the files instead of calling eslint for every file one by one?

@mihow

This comment has been minimized.

Copy link

@mihow mihow commented Feb 4, 2020

This is great! @lifenstein That seems like a less common case, so when it happens you could run git commit --no-verify to skip the 4 minute check and then run eslint directly. For most commits this will be much faster than linting the entire project every time.

@Alynva

This comment has been minimized.

Copy link

@Alynva Alynva commented Feb 10, 2020

One-liner version of the above:

git diff --diff-filter=d --cached --name-only | grep -E '\.(js|jsx)$' | xargs -I % sh -c 'git show ":%" | eslint --stdin --stdin-filename "%";'

I had to change the @jancimajek version a little bit, because % is reserved in my shell and eslint is not global, so:

git diff --diff-filter=d --cached --name-only | grep -E '\.(js|jsx)$' | xargs -I A sh -c 'git show ":A" | .\\node_modules\\.bin\\eslint --stdin --stdin-filename "A";'
@mholtzhausen

This comment has been minimized.

Copy link

@mholtzhausen mholtzhausen commented Mar 19, 2020

Thank you to OP -- very useful. I adapted and my lint-staged.sh file looks like this:

#!/bin/bash
clear
fileList=$(git diff --diff-filter=d --cached --name-only | grep -E '\.(js|vue)$')
if [ ${#fileList} -lt 1 ]; then
    echo -e "You have no staged .js or .vue files to test\n"
    exit
fi
npx eslint ${fileList[*]} "$@"
if [ $? -ne 0 ]; then
    echo -e "\nPlease fix the above linting issues before committing.\n"
    exit 1
fi

Benefits are:

  • using npx allows running local or global eslint
  • Passing the file list to eslint limits this to a single run -- so eslint only has to start up once, and not once for every file
  • It only exits after all staged files have been tested
  • Has an out for when no files are staged
  • allows you to configure eslint by adding arguments to shell command. ie. ./lint-staged.sh --fix
@kuladeeparun

This comment has been minimized.

Copy link

@kuladeeparun kuladeeparun commented Jul 21, 2020

Thanks @nemesarial! This works like a charm

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.