You don't need husky for git-hooks!
When going mono-repo, I noticed that the Node.js package "husky" can actually be replaced by a single line of code. And it works for people that do not have Node.js installed.
The title sounds like a clickbait, and I may be wrong. Maybe husky is actually doing more than I think. But I really thought: “Why do I need this package at all?”.
When I converted Gachou to a mono-repo, I wondered what I
should to about the pre-commit hooks and lint-staged
for linting and
formatting. Since I had to run it in multiple sub-repositories, with only one
commit hook, I thought about installing husky
in the root repository as well.
I did not like this idea. Maybe some Java-developer wants to do something in the
backend. Even if she does not touch anything in the Node.js repositories, she
has to install Node.js. So I went and I tried to figure out what husky
actually does.
What does husky
do?
Usually, git looks for hooks in the .git/hooks
directory, but of course, this
is not committed to the repository, so you cannot use it to share your hooks.
Husky configures git to use a different directory for this repository. If you
look at .git/config
, you will see
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
hooksPath = .husky <---- This is it!
The hooksPath
is set to the .husky
directory, and that is where a
pre-commit
-script is placed by husky.
Do it yourself!
For my mono-repo, I added a simple script bin/init-repo.sh
with the following
content.
#!/bin/bash
git config core.hooksPath .git-hooks
Then I added a file .git-hooks/pre-commit
to the repository:
#!/bin/bash
set -e
( cd e2e-testing && npx lint-staged )
( cd web-ui && npx lint-staged )
I also had to make this file executable, otherwise git will just ignore it with a warning.
chmod a+x .git-hooks/pre-commit
When a new user clones the mono-repo, she can run init-repo.sh
and the hooks
will be setup just fine. But she still needs Node.js to run the hook itself,
because npx lint-staged
does not work otherwise.
Restrict pre-commit checks to relevant sub-directories
As long as my potential Java-dev does not do changes in web-ui
or
e2e-testing
, she does not need to execute lint-staged
, so how can we check
that?
git diff --quiet --cached e2e-testing
will look for staged (“cached”) differences in the repository inside
e2e-testing
. It will not print anything (“quiet”), but it will return with a
non-zero exit-code if changes are found. We can use that in our pre-commit hook:
#!/bin/bash
set -e
if ! git diff --quiet --cached e2e-testing ; then
( cd e2e-testing && npx lint-staged )
fi
if ! git diff --quiet --cached web-ui ; then
( cd web-ui && npx lint-staged )
fi
This will only run lint-staged
if there are changes in the given
subdirectories.
Replacing husky
Assuming, you don’t have a mono-repo, but just a simple Node.js project. I think, instead of husky, you can also do the following:
-
create a file
.git-hooks/pre-commit
-
make it executable
-
add a script to your
package.json
{ "scripts": { "prepare": "git config core.hooksPath .git-hooks" } }
This should have the same effect.
Conclusion / Disclaimer
I haven’t had a thorough look at the husky source-code. Maybe there other things that I don’t know. And if you are using Node.js anyway, you might as well use it. It has no dependencies after all.
But I was glad to find out, that I could very simply have the same thing without making the root-project in my mono-repo a Node.js project.