-
-
Save dahjelle/8ddedf0aebd488208a9a7c829f19b9e8 to your computer and use it in GitHub Desktop.
#!/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 |
Option --diff-filter=d should be specified in git diff to exclude deleted files.
@Fer0x Where would that go?
@Alberth8 It'd be like this -> git diff --diff-filter=d --cached --name-only
Thanks @dahjelle! Great stuff :)
Thank you very much
eslint is quite slow when it runs against my entire project, this is much faster, thanks!!
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.
Thank you very much.
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 "%";'
you can do this in one line git diff --cached --name-only | grep ".js$" | xargs ./node_modules/.bin/eslint
nice, @richistron
@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.
thanks
Thanks @dahjelle.
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?
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.
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";'
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 globaleslint
- Passing the file list to
eslint
limits this to a single run -- soeslint
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
Thanks @nemesarial! This works like a charm
This does not lint "only staged changes" it lints each file that is changed. Which is annoying because it can block your commit for stuff that isn't even in the commit! Eslint should just have a --diff
options like flake8
There is an cleaner way to accomplish this, with husky:
// package.json
...
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"*.{js,ts,tsx}": [
"prettier --write",
"eslint --ext .ts,.tsx,.js --fix"
]
},
LGTM, but maybe eslint
should be run before prettier
.
Note: If you use ESLint, make sure lint-staged runs it before Prettier, not after.
ref: https://prettier.io/docs/en/install.html#git-hooks
},
@aperkaz
Where exactly i need to place above lines inside package.json file.
@Naveen9453 after the dependencies section is a good place, although I tend to locate it at the end of the file. No strict placement requirements though.
package.json
configuration of husky no longer works, by design.
Thanks. Very helpful.