Skip to content

Mastering Git – Part 7: Git Hooks and Automation

Git isn’t just about tracking code—it can also automate tasks, enforce best practices, and prevent mistakes using Git Hooks.

Imagine automatically:

  • ✅ Running tests before committing 🚀
  • ✅ Preventing bad commit messages ❌
  • ✅ Formatting code before pushing 🎨
  • ✅ Blocking commits with secrets 🔒

Git hooks let you do all this and more!

In this post, we’ll cover:

  • ✅ What Git hooks are and how they work
  • ✅ Setting up pre-commit and pre-push hooks
  • ✅ Automating Git with Husky
  • ✅ Best practices for Git hook usage

By the end, you'll know how to use Git hooks to improve code quality, automate workflows, and prevent common mistakes.


1. What Are Git Hooks?

Git hooks are scripts that run automatically at different points in the Git workflow.

There are two types of hooks:

  • 🔹 Client-side hooks – Run on your local machine (before committing, pushing, or merging).
  • 🔹 Server-side hooks – Run on the remote repository (before accepting pushes).

2. Commonly Used Git Hooks

Hook When it Runs Common Use Cases
pre-commit Before committing Run linters, formatters, security checks
commit-msg Before commit is saved Enforce commit message rules
pre-push Before pushing Run tests, prevent bad code from being pushed
pre-receive Before remote repo accepts push Reject bad commits on server
post-merge After merging a branch Auto-install dependencies

3. Setting Up Git Hooks Manually

A. Creating a Pre-Commit Hook

1️⃣ Navigate to the Git hooks directory in your repo:

cd .git/hooks

2️⃣ Create a new pre-commit file:

touch pre-commit
chmod +x pre-commit  # Make it executable

3️⃣ Open it in an editor and add a simple script (e.g., prevent commits with TODOs):

#!/bin/bash
if grep -r 'TODO' *; then
  echo "🚨 Commit blocked: Remove TODOs before committing!"
  exit 1
fi

4️⃣ Save and try committing a file with TODO—it will block the commit.

✅ Use Case: Prevent committing unfinished work.


B. Creating a Pre-Push Hook

1️⃣ Create the hook:

touch .git/hooks/pre-push
chmod +x .git/hooks/pre-push

2️⃣ Add a script to run tests before pushing:

#!/bin/bash
echo "🔍 Running tests before push..."
if ! ./run-tests.sh; then
  echo "🚨 Tests failed! Push aborted."
  exit 1
fi

✅ Use Case: Ensure broken code isn’t pushed.


C. Enforcing Commit Message Format (commit-msg Hook)

1️⃣ Create the hook:

touch .git/hooks/commit-msg
chmod +x .git/hooks/commit-msg

2️⃣ Add a script to enforce a conventional commit format:

#!/bin/bash
COMMIT_MSG=$(cat "$1")

if ! [[ "$COMMIT_MSG" =~ ^(feat|fix|docs|refactor|test|chore)\(.*\): ]]; then
  echo "🚨 Commit message must follow format: type(scope): description"
  echo "Example: feat(auth): add login support"
  exit 1
fi

✅ Use Case: Ensure clean and structured commit messages.


Manually setting up hooks per user is painful. Husky solves this by managing hooks as part of the repository.

A. Installing Husky

npm install husky --save-dev

B. Setting Up Husky in Your Repo

npx husky install

Then enable it in package.json:

"scripts": {
  "prepare": "husky install"
}

C. Adding a Pre-Commit Hook with Husky

npx husky add .husky/pre-commit "npm run lint"
git add .husky/pre-commit

✅ Now, every commit will run npm run lint automatically!


5. Best Practices for Git Hooks

  • ✅ Keep hooks fast – Hooks should not slow down development.
  • ✅ Use Husky for easier management – Avoid manually setting up hooks per user.
  • ✅ Version control your hooks – Keep them in the repo (.husky/ for Husky or share .githooks/).
  • ✅ Allow skipping hooks when necessary – Use git commit --no-verify to bypass if needed.
  • ✅ Use server-side hooks for critical checks – Prevent bad commits from reaching production.

6. Summary of Key Commands

Action Command
List available Git hooks ls .git/hooks/
Create a pre-commit hook touch .git/hooks/pre-commit
Make a hook executable chmod +x .git/hooks/pre-commit
Install Husky npm install husky --save-dev
Add a Husky pre-commit hook npx husky add .husky/pre-commit "npm run lint"
Skip hooks when committing git commit --no-verify

What’s Next?

Now you know how to automate Git workflows and enforce best practices using hooks. But what about handling advanced Git scenarios like stashing, cherry-picking, and submodules?

In Part 8: Advanced Git – Stashing, Cherry-Picking, and Submodules, we’ll cover:

  • ✅ Stashing changes for later
  • ✅ Applying specific commits with cherry-picking
  • ✅ Managing submodules for large projects