Published on

Adding Husky to a subfolder of a Git root repository

Last Modified on
Last modified on
Authors
Chicks in nest representing adding Husky to a subfolder of a Git root repository
Photo by Pixabay on Pexels

Recently I decided to add Husky, linters, and lint-staged to an application of mine AFTER I had almost completed it. However, it contains two subfolders within its root Git repository. A client folder and a server folder. So how was I going to achieve adding Husky (along with some linters) to the client folder? Husky expects to be placed in the root directory!

In this kind of scenario, we can’t completely automate the process. What do I mean by that? You can visit my post entitled Adding husky to your development workflow to find out more. The long and short of it? Except for the installation of the linters you want to add to your Git repository and the installation of the husky and lint-staged devDependencies, everything else has to be manually created.

So what did I do? I wanted to add stylelint for sass/scss, eslint (custom) configuration, and prettier, so I added the following devDependencies inside my client subfolder where the React part of my application generated with create-react-app resides:

"devDependencies": {
    "eslint": "^8.31.0",
    "eslint-config-prettier": "^8.6.0",
    "eslint-plugin-import": "^2.27.4",
    "eslint-plugin-prettier": "^4.2.1",
    "husky": "^8.0.3",
    "lint-staged": "^13.1.0",
    "prettier": "^2.8.3",
    "stylelint": "^14.16.1",
    "stylelint-config-prettier": "^9.0.4",
    "stylelint-config-prettier-scss": "^0.0.1",
    "stylelint-config-standard": "^29.0.0",
    "stylelint-config-standard-scss": "^6.1.0"
  }

However, I initialized my local Git repository in a parent root directory called socketio-realtime-node-chat. So how was I going to circumvent this?

After installing Husky as a devDependency, I did not go to the next step of running npx husky install in the macOS Terminal to enable the running of npm pkg set scripts.prepare="husky install" command which resulted in the addition of a “prepare” script “husky install” in my package.json located in my client folder. I manually added my "prepare" script to my client folder’s package.json, and it looks like the following:

"prepare": "cd ../ && husky install ./client/.husky"

Because my Git repository was initialized in a parent root folder which contains both my client and server subfolders, but I only wanted to set up husky and linters inside my client folder, I had to set up a script which would cd (change directory) me out of the client directory into the parent, root Git directory, and then install husky inside of the .husky directory located at the root of my client subfolder. So that is why “./client/.husky”. ./ indicates that the client folder is located at the root of the parent Git repository directory (in my case) called socketio-realtime-node-chat.

Next, instead of running a command such as

npx husky add .husky/pre-commit “npm run validate”

to create a pre-commit Git hook via macOS Terminal, I manually created a file within the .husky directory at the root of my client subfolder called pre-commit (no file extension, and there is not one when created when running a command in Terminal), and I added the following to it:

#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

cd ./client && npm run validate

Why the #!/bin/sh at the beginning of the above script? The # stands for commenting out something. If you take a look at a pre-commit file, you will see that that line is “greyed out”. That’s the reason why. As for /bin/sh, it is normally an executable representing the system shell and usually implemented as a symbolic link pointing to the executable for whichever shell is the system shell. However, here, it is not an executable representing your system (computer) shell. It represents the script for a Git hook. In this case, a `pre-commit hook``. So that is why it is commented out.

What does . represent? It represents the parent root directory, which in this case, is socketio-realtime-node-chat.

And what does "$(dirname "$0")/_/husky.sh" mean?

dirname is short for directory name, and given a string containing the path of a file or directory, this command returns the parent directory's path. And dirname "$0" returns the directory where the script is saved. In the case of husky, the script is saved inside of a directory called .husky, right after a folder called _ which contains a .gitignore file and a husky.sh file. And /husky.sh after _ denotes the path to husky.sh inside the _ directory.

So .husky contains the following hierarchy:

.husky
  _
    .gitignore
    husky.sh
  pre-commit

Then, when I commit any changes, if there is anything that needs fixing, I can’t commit the changes until they have been fixed. And that is it!