Git Hooked
Category 1: Client-Side: Local Workflow
pre-commit: Runs before a commit is created. Use for linting, formatting, security scans.
prepare-commit-msg: Runs before the commit message editor opens. Use for templating messages.
commit-msg: Runs after the message is written. Use for validating the message format.
post-commit: Runs after a commit is successfully created. Use for notifications.
Category 2: Client-Side: Pushing Code
pre-push: Runs before git push. Use for running tests, ensuring you're not pushing broken code.
Category 3: Client-Side: Workflow Events
post-merge: Runs after a successful merge. Use for installing dependencies, rebuilding caches.
Objective: Create a basic pre-commit hook that blocks a commit based on a simple condition.
git add files -> [HOOK: pre-commit] [HOOK: prepare-commit-msg] -> Commit Editor Opens -> [HOOK: commit-msg] -> Commit is created -> Developer Action: git push -> [HOOK: pre-push] -> Code sent to Remote -> Developer Action: git merge other-branch -> [HOOK: post-merge]
pre-commit: "Is this code good enough to commit?"
prepare-commit-msg: "Can I help you write a better message?"
commit-msg: "Does this message meet our team's standards?"
Focus on the push portion of the diagram.
pre-push: "Are we absolutely sure this is ready to be shared with the team?" This is your last chance to stop a mistake on your local machine.
Use Case: Since it runs less frequently than pre-commit, it's the perfect place for slightly slower checks, like running a critical subset of unit tests.
Focus on the merge portion of the diagram.
post-merge: "Now that we've brought in new code, does our environment need any cleanup or setup?" It runs after a successful merge.
Use Case: Automatically run npm install if package.json changed, or pip install -r requirements.txt if requirements.txt changed. A huge quality-of-life improvement.
Objective: Write a pre-commit hook that runs a linter on staged files and blocks the commit if errors are found.
Link: github.com/your-repo/LAB-2.md
A timer pre-set to 30:00.
Objective: Build a two-part hook system to enforce policy and automate chores.
Part 1 (commit-msg): Enforce that commit messages contain a JIRA-style ID based on the current branch name.
Part 2 (post-merge): Automatically run a dependency installer if a package file has changed after a merge.
A timer pre-set to 35:00.
Hooks out in the wild
A simple, text-only slide.
"So, manual hooks are great, right? They're powerful, flexible, and have no dependencies."
"...what happens when you try to share them with your team?"
A visual 3x2 bingo card grid.
Each square contains one of the common problems:
"It works on my machine!" (macOS sed vs. Linux sed)
"I forgot to run chmod +x"
"New dev joined, forgot to install the hooks"
"Our hooks aren't even in version control!"
"I just used --no-verify to bypass it..."
"Managing Python, Node, and Ruby hooks is a nightmare"
pre-commit
pre-commit WorksA simple three-step diagram:
You write a .pre-commit-config.yaml file. (Shows a snippet of the YAML).
You run pre-commit install. This installs a tiny, smart script into .git/hooks/pre-commit.
On commit, the script reads the YAML. It then downloads the specified tools into isolated, cached environments and runs them against your staged files.
.pre-commit-config.yamlA code block with a well-annotated example YAML file.
The Husky logo.
A code block showing a sample package.json configuration for Husky.
Text: "Husky is the go-to hook manager for the Node.js ecosystem. It leverages package.json and npm scripts for configuration."
A diagram with two columns.
Column 1: Git Hooks (Your Laptop)
Icon: Laptop
Fast, Individual Feedback
Runs on every commit
Jobs: Linting, Formatting, Secret Scanning, Syntax Checks
Column 2: CI/CD Pipeline (The Server)
Icon: Server/Cloud
Slower, Authoritative Team Feedback
Runs on every pull request
Jobs: Full Unit/Integration Test Suites, Building Artifacts, Deploying
An arrow connects them, labeled "Partners in Quality".
The Automatic Ticket Inserter (prepare-commit-msg)
Reads branch name feature/PROJ-451-login
Automatically prepends PROJ-451: to the commit message.
"Turns a manual chore into an invisible, automated process."
The Automatic Dependency Installer (post-merge)
Detects changes to package.json after a merge.
Automatically runs npm install.
"Handles a common follow-up task without any user intervention."
The "Did you run migrations?" Reminder (post-merge)
Detects changes in the db/migrate/ directory.
Prints a big, bold, colorful message to the console: "ATTENTION: New migrations were pulled. Remember to run rails db:migrate!"
"A low-effort, high-impact nudge at the perfect moment."
A numbered list of actionable steps.
1. Start Small & Provide Value: Don't boil the ocean. Introduce a single, undeniably useful hook first. An auto-formatter like Black or Prettier is a perfect start because its value is immediately obvious.
2. Get Buy-In, Don't Mandate: Share a success story (like the secret-scanning one). Show, don't just tell. Frame it as a tool that helps everyone, not a process that is forced upon them.
3. Use a Framework for Consistency: Once you have more than one hook or more than one developer, adopt a framework like pre-commit or Husky. This is non-negotiable for team success.
4. Document the Setup: Add the two-line installation guide to your CONTRIBUTING.md or team wiki. Make it the path of least resistance.
github.com/exitflynn