Skip to main content

Command Palette

Search for a command to run...

Git Hooks: Automate Workflow Like Pro

Learn: Git Hooks: Automate Workflow Like Pro

Updated
5 min readView as Markdown
T

Welcome to TopperBlog! 👋

I'm a tech content creator passionate about helping developers level up their careers and master cutting-edge technologies.

🎯 What I Write About: • AI/ML Engineering & LLMs • Web3 & Blockchain Development
• System Design & Architecture • Interview Preparation (FAANG) • Freelancing & Remote Work • Modern Tech Stacks (Next.js, React, Rust, TypeScript) • Performance Optimization & Best Practices

💼 Mission: Sharing practical, actionable insights that accelerate your tech career and maximize your earning potential.

📚 15+ In-Depth Guides covering everything from earning $10k/month as a freelancer to cracking FAANG interviews.

🌐 Let's connect and grow together in this amazing tech journey!

#TechBlogger #SoftwareEngineering #CareerGrowth #WebDevelopment #AIEngineering

Git Hooks: Automate Workflow Like a Pro

The Magic Behind Pre-Commit Hooks

Git hooks are like invisible ninjas in your repository—they silently watch your every move and spring into action at critical moments. Whether you're committing code, pushing to a remote, or merging branches, hooks can automate tedious tasks, enforce standards, and save your team from countless headaches.

Think of them as automated gatekeepers that ensure quality before code even reaches your repository.

The Story: Why We Need Git Hooks

The Scenario: Sarah's team was drowning in code review comments. Every pull request had the same issues: inconsistent formatting, missing tests, hardcoded credentials, and linting errors. The team was spending 40% of their time on trivial fixes instead of actual development.

Then Sarah discovered git hooks.

Within a week, her team's workflow transformed. Developers couldn't commit broken code even if they tried. Linters ran automatically. Tests executed before pushing. Credentials were caught before they leaked. Code reviews became about logic and architecture, not formatting.

The Result:

  • 60% reduction in review cycle time
  • Zero accidental credential leaks
  • Consistent code style across the entire codebase
  • Developers shipping features 30% faster

Pre-Commit Hooks: The Foundation

Pre-commit hooks fire before your commit is finalized. They're your first line of defense.

Setting Up Your First Hook

# Navigate to your git hooks directory
cd .git/hooks

# Create a pre-commit hook
touch pre-commit
chmod +x pre-commit

Basic Pre-Commit Hook Example

#!/bin/bash
# .git/hooks/pre-commit

echo "🔍 Running pre-commit checks..."

# Check for staged changes
if git diff --cached --name-only | grep -q "\.js$"; then
    echo "📝 Linting JavaScript files..."
    npm run lint -- --fix

    if [ $? -ne 0 ]; then
        echo "❌ Linting failed! Fix errors before committing."
        exit 1
    fi
fi

# Check for console.log statements
if git diff --cached | grep -q "console\.log"; then
    echo "⚠️  Found console.log statements. Remove them!"
    exit 1
fi

echo "✅ Pre-commit checks passed!"
exit 0

The Hook Arsenal: Essential Hooks Explained

1. Pre-Commit Hook (Most Important)

Runs before the commit is created. Perfect for:

  • Linting and formatting
  • Running tests
  • Checking for secrets
  • Validating file sizes

2. Commit-Msg Hook

Validates commit messages. Enforce conventional commits:

#!/bin/bash
# .git/hooks/commit-msg

COMMIT_MSG=$(cat $1)

# Check if commit follows conventional commits format
if ! echo "$COMMIT_MSG" | grep -qE "^(feat|fix|docs|style|refactor|test|chore)(\(.+\))?!?: .+"; then
    echo "❌ Commit message must follow conventional commits:"
    echo "   feat(scope): description"
    echo "   fix(scope): description"
    exit 1
fi

echo "✅ Commit message is valid!"
exit 0

3. Pre-Push Hook

Runs before pushing to remote. Catch issues before they go public:

#!/bin/bash
# .git/hooks/pre-push

echo "🚀 Running pre-push checks..."

# Run full test suite
npm test
if [ $? -ne 0 ]; then
    echo "❌ Tests failed! Fix before pushing."
    exit 1
fi

# Check for unresolved merge conflicts
if git diff --name-only --diff-filter=U | grep -q .; then
    echo "❌ Unresolved merge conflicts detected!"
    exit 1
fi

echo "✅ Ready to push!"
exit 0

4. Post-Merge Hook

Runs after merging branches. Useful for:

  • Reinstalling dependencies
  • Updating database migrations
  • Refreshing build artifacts
#!/bin/bash
# .git/hooks/post-merge

# Check if package.json changed
if git diff HEAD@{1} HEAD --name-only | grep -q "package.json"; then
    echo "📦 Dependencies changed. Running npm install..."
    npm install
fi

# Check if migrations changed
if git diff HEAD@{1} HEAD --name-only | grep -q "migrations/"; then
    echo "🗄️  Database migrations detected. Review before proceeding!"
fi

Pro Tips & Best Practices

Tip 1: Use a Hook Framework

Don't reinvent the wheel. Use Husky for Node.js projects:

npm install husky --save-dev
npx husky install

# Add a hook
npx husky add .husky/pre-commit "npm run lint"
npx husky add .husky/commit-msg 'echo "Validating commit message..."'

Tip 2: Combine with Lint-Staged

Only lint files that are actually staged:

npm install lint-staged --save-dev
{
  "lint-staged": {
    "*.js": "eslint --fix",
    "*.css": "stylelint --fix",
    "*.md": "prettier --write"
  }
}

Tip 3: Make Hooks Bypassable (When Necessary)

Sometimes you need to skip hooks:

# Skip pre-commit hook
git commit --no-verify -m "Emergency fix"

# Skip pre-push hook
git push --no-verify

Tip 4: Share Hooks Across Team

Store hooks in version control:

# Create hooks directory in repo
mkdir -p .githooks

# Move hooks there
mv .git/hooks/pre-commit .githooks/

# Configure git to use this directory
git config core.hooksPath .githooks

# Team members run this once
git config core.hooksPath .githooks

Tip 5: Add Helpful Output

Make hooks user-friendly:

#!/bin/bash
# Use colors and emojis
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

echo -e "${YELLOW}🔍 Checking code quality...${NC}"

if npm run lint; then
    echo -e "${GREEN}✅ All checks passed!${NC}"
else
    echo -e "${RED}❌ Linting failed. Fix errors and try again.${NC}"
    exit 1
fi

Tip 6: Performance Matters

Keep hooks fast. Slow hooks frustrate developers:

# ❌ Bad: Runs full test suite
npm test

# ✅ Good: Runs only affected tests
npm run test:affected

Advanced Hook Patterns

Pattern 1: Prevent Secrets from Leaking

#!/bin/bash
# Detect AWS keys, API tokens, etc.

PATTERNS=(
    "AKIA[0-9A-Z]{16}"  # AWS Access Key
    "aws_secret_access_key"
    "private_key"
    "password.*="
)

for pattern in "${PATTERNS[@]}"; do
    if git diff --cached | grep -iE "$pattern"; then
        echo "❌ Potential secret detected!"
        exit 1
    fi
done

Pattern 2: Enforce Branch Naming

#!/bin/bash
# .git/hooks/pre-commit

BRANCH=$(git rev-parse --abbrev-ref HEAD)

if ! echo "$BRANCH" | grep -qE "^(main|develop|feature|bugfix|hotfix)\/"; then
    echo "❌ Branch name must follow pattern: feature/*, bugfix/*, etc."
    exit 1
fi

Pattern 3: Auto-Format on Commit

#!/bin/bash
# Auto-format and re-stage files

npm run format
git add .

Troubleshooting Common Issues

IssueSolution
Hook not executingCheck file permissions: chmod +x .git/hooks/pre-commit
Hook runs but changes aren't stagedUse git add to re-stage modified files
Team members skip hooksUse Husky to enforce hooks across team
Hooks too slowOptimize with lint-staged or parallel execution
Hook works locally but not in CIEnsure CI environment has same dependencies

Conclusion

Git hooks transform your workflow from reactive (catching issues in review) to proactive (preventing issues before they happen). Start with pre-commit hooks for linting and formatting, add commit-msg validation, then expand to pre-push and post-merge hooks.

The magic isn't in the hooks themselves—it's in the consistency and automation they bring to your team's development process. Your future self (and your code reviewers) will thank you.

Start small. Automate wisely. Ship better code.