git hook with minimal effort. When used together with
lint-staged, you can really create a nice developer experience for yourself. I’ve been using both on most of my recent projects and I highly recommend them.
husky primarily to run a
pre-commit hook, where I do some linting and formatting, and even run some tests on changed files. This was working great up until a few weeks ago when I started to notice that the script defined in the
pre-commit hook was not running.
I spent several frustrating hours trying to debug the issue to no avail. This led to some anger-induced Googling and a freshly created GitHub issue. The lone commenter in that issue suggested taking a look at a
git configuration option,
init.templateDir, to potentially solve my problem.
This was helpful for two reasons. For one, it was a spot on suggestion, but we’ll get to that. Second, it forced me to jump into the
git documentation, which I should’ve done in the first place.
After digging through the docs I realized my problem. I had recently created a directory to hold my “global”
git hooks. I then defined the path to that directory using the
core.hooksPath option in my
~/.gitconfig ... [core] hookspath = /path/to/global/git-hooks
This option, according to the docs, tells
git where to find my hooks. What I didn’t realize, was that if such an option existed in my
.gitconfig, then those hooks would be used in favor of any defined at the project level, i.e. in my project’s
.git/hooks directory. This includes the hooks that
husky creates when you install the package.
So, having a global
githooks directory affects my usage of
Frustrating. In my ideal world
git would manage this better. 🤷🏼♂
I needed to find a way to use both my global
git hook and the
husky hooks without creating some complex workaround. Taking the suggestion of the commenter, here’s what I came up with.
Create a template directory#
First, I created a
git template directory.
The contents of this directory, as long as they are not prefixed with a dot, will be copied to the
$GIT_DIR after it’s created. The
$GIT_DIR, in my case, is just my project’s
.git directory, which is created when running
In order to tell
git where to find this newly created directory, I defined its location inside of
.gitconfig using the
~/.gitconfig ... [init] templateDir = /path/to/git-template-dir
Note: I also removed the
core.hooksPath definition inside of
.gitconfig because I no longer need it.
Add your global hooks to the template directory#
At this point, you’ll need to move any globally defined
git hooks to the new template directory underneath a folder named
cd /path/to/git-template-dir mkdir hooks
I ended up re-creating my lone hook instead of “moving” it. If you did the same, make sure to set the proper permissions on the hook so that it is executable:
chmod a+x /hooks/<hook-file>
Now, whenever you run
git init, the contents of your
/path/to/git-template-dir/hooks folder will be copied over to the
.git/hooks folder in your project.
Supporting existing projects#
The only caveat here is that this solution won’t work with existing projects. This is because
git will only copy over the contents of your template directory when you run
If you have an existing project that you want to support, and you don’t mind re-initializing
git, you can remove the
.git directory and run
git init again. This isn’t really ideal, especially if you value your
git history. In that case, I would suggest manually creating your hooks in the
.git/hooks directory of the project as a one-off type of thing.
To wrap this post up, in order to solve my issue I created a template directory and defined its location using the
init.templateDir option inside of
.gitconfig. From there, I created a
hooks folder inside of the template directory, where I can now define my global
git will then copy the contents of this template directory any time I run
git init. This means my global hooks will be accessible inside of any future projects. I can then install
husky as normal, and the package will create its own
git hooks alongside the ones I’ve defined globally.
I hope this helps any of you who have run into the same problem. Reach out to me on Twitter if you have any questions. Happy coding!