Lint Only Files with Changes on pre-commit

A few days ago, I remembered that at my former workplace, karriere.at, we had a pre-commit hook bash script that executed ESLint and Stylelint, not on the entire repo, but only on files that were changed. Because that was pretty handy, I was looking into how I could have the same convenience for my projects.

Manually create a pre-commit hook for linting

There are multiple ways of how to achieve this, and what I see a lot is using something like the npm package Husky to help with managing git hooks. But because this can also be done by hand without adding a dependency to your project, I settled for using a good old bash script.

#!/bin/bash

PREFIX="pre-commit:"

fileList=$(git diff --diff-filter=d --cached --name-only)

jsFileList=$(echo "$fileList" | grep -E '\.(js)$')
if [ ${#jsFileList} -gt 0 ]; then
    if ! npx eslint ${jsFileList[*]} "$@"; then
        echo "$PREFIX Commit aborted."
        echo "$PREFIX You can lint manually via 'yarn lint:scripts'.\n"
        exit 1
    fi
fi

cssFileList=$(echo "$fileList" | grep -E '\.(css|scss)$')
if [ ${#cssFileList} -gt 0 ]; then
    if ! npx stylelint ${cssFileList[*]} "$@"; then
        echo "$PREFIX Commit aborted."
        echo "$PREFIX You can lint manually via 'yarn lint:styles'.\n"
        exit 1
    fi
fi

In my project, I’ve created a new bin directory, where I put this file with the file name pre-commit. Here we specify the commands we want to run before every commit. In our case, we run ESLint and stylelint. The way we’ve set this up, our linting scripts run only on staged files; if there is a linting error, the commit aborts.

The script you can see above is loosely based on this snippet by Mark Holtzhausen.

Also make sure to set the correct permissions on the newly created file so it can be executed.

chmod 0755 bin/pre-commit

If we want to keep things simple, we can now manually copy the file into our git hooks directory. But to make it easier for our colleagues and our future selfs we can add a setup script which does that for us. We configure our setup script to run automatically whenever we run npm install.

#!/bin/bash

echo "Installing pre-commit hook ..."

cp bin/pre-commit .git/hooks/pre-commit

echo -e "\033[32mFinished!\033e"

For now, we only install our pre-commit hook in the setup script, but we can add additional set up procedures later.

Again, we have to set the correct permissions to make the newly created setup script runnable.

chmod 0755 bin/setup

To automatically run the setup script whenever somebody starts using the codebase, we can add an npm postinstall script.

{
  "scripts": {
    "postinstall": "bin/setup"
  }
}

Husky and lint-staged

If you don’t want to manually create your own pre-commit hook you can also use the combination of Husky and lint-staged to achieve the same.

Wrapping it up

Once multiple people are working on the same codebase and performing regular code reviews, it is essential to establish procedures to check your code for inconsistencies automatically. By automatically running your lint scripts every time you commit, you ensure that no one can commit code that doesn’t match your project’s code style.


Do you want to learn how to build advanced Vue.js applications?

Register for the Newsletter of my upcoming book: Advanced Vue.js Application Architecture.



Do you enjoy reading my blog?

You can buy me a ☕️ on Ko-fi!

☕️ Support Me on Ko-fi