▰▰ jshakespeare.com

A former coworker and I had a system for letting each other know about dependency changes in shared codebases. We wrote npm install on a post-it note and would stick it to the other person’s monitor. Once the post-it note eventually lost its stickiness, we just screwed up and threw it at each other. By the end of the project, the universal sign for ‘update your dependencies’ was to throw a random object across the room.

The only downside of this otherwise perfect system is that it doesn’t scale well, especially on distributed teams. A much better solution is to use git hooks.

Git hooks execute a command when git performs an action. They are useful for doing things like running a linter before you commit (pre-commit) or running a build script when a server receives a push (post-receive).

We want to check whether package-lock.json has changed when we run git pull, so we can use the post-merge hook (git pull being equivalent to git fetch + git merge). If the lockfile has changed, we can echo a notification to the user that they should run npm install to bring their node_modules directory up to date.

Create a git hook file

In your repo, create a file called post-merge in .git/hooks:

touch .git/hooks/post-merge

In that file we’re going to define a function that checks whether a file has changed between commits, and run that function with package-lock.json as the argument:

function changed {
  git diff --name-only HEAD@{1} HEAD | grep "^$1" > /dev/null 2>&1
}

if changed 'package-lock.json'; then
  echo "📦 package-lock.json changed. Run npm install to bring your dependencies up to date."
fi

You could add notifications for other file changes in here, like Gemfile.lock or Podfile.lock.

Credit to 8bitDesigner for this approach.

Test the hook

Try out the hook by rewinding to a commit where you know package-lock.json has changed, let’s say 20 commits ago, then running git pull to fast-forward back to now:

git reset --hard HEAD~20 && git pull

If package-lock.json changed between now and then, you will see the notification.

Use husky to share your hook with others

Changes in the .git directory are not version controlled, so we need to move our hook to somewhere that is. We then need to provide a way for other developers to easily install the hook for themselves. Thankfully husky exists to do exactly that.

Create a directory called .githooks and move your hook there:

mkdir .githooks && mv .git/hooks/post-merge .githooks

Now we can set up husky. The npm post-install script for husky checks package.json for any declared hooks and automatically installs them in .git/hooks.

In package.json add:

"husky": {
  "hooks": {
     "post-merge": "./.githooks/post-merge"
  }
}

Then install husky:

npm install --save-dev husky

Next time someone runs npm install with your changes, the hook will be installed in their local .git directory.