Git Hooks Security — Why Hooks Don’t Clone and How to Distribute Them Safely
In the previous videos we explored Git hooks like pre-commit and prepare-commit-msg.
This post tackles two practical questions:
- Security: What if a malicious repo’s hook tries to run harmful code on your machine?
- Distribution: If hooks are local-only, how do we share the team’s standard hooks with every developer?
Short answer:
- Hooks never travel with your commits — they live in
.git/hooks/and are not versioned. This is a security guard-rail. - To share hooks safely, store them as plain files in your repo (e.g.,
hooks/) and provide a one-step installer (e.g.,make).
Why hooks don’t clone (and why that’s good)
When you git clone, Git does not copy any executable hook into your local .git/hooks/.
This prevents auto-executing untrusted code the moment you make your first commit.
You saw this live:
- After cloning a repo,
.git/hooks/contains only*.samplefiles (or nothing executable). - Your custom
pre-commit/prepare-commit-msgfrom another machine were not present.
The problem: we still want team-wide hooks
You do want the team to run formatters, linters, tests, and message rules locally before code ever leaves laptops.
But since hooks aren’t versioned automatically, you need a simple, explicit install step.
Ship hooks in the repo + give a one-step installer
1) Commit your hook scripts as plain files
hooks/
pre-commit
prepare-commit-msg
Add and push them like any source file.
2) Provide a Makefile target that installs them into .git/hooks/
In the video, we used a target called
install hooksand ranmake install hooks. Below is the same spirit packaged as a single target name (commonly used in practice):
# Makefile
install-hooks:
@mkdir -p .git/hooks
cp -a hooks/* .git/hooks/
chmod +x .git/hooks/*
@echo "✓ Hooks installed to .git/hooks"
3) Developer flow after clone
git clone <REPO_URL>
cd <REPO_DIR>
make install-hooks # installs and chmod +x
Now their local .git/hooks/ contains your team’s hook scripts, ready to run.
What you demonstrated in the video (step-by-step recap)
-
Created a repo; proved hooks aren’t part of version control by cloning it elsewhere and checking
.git/hooks/. -
Moved local hook scripts into a tracked
hooks/folder:mkdir hooks cp .git/hooks/pre-commit hooks/ cp .git/hooks/prepare-commit-msg hooks/ git add hooks git commit -m "hooks added" git push origin main -
Added a Makefile with an install target that copies from
hooks/to.git/hooks/. -
Cloned fresh, ran:
make install hooks # as narrated in the videoand verified the hooks now exist under
.git/hooks/and are executable.
🔐 Note on permissions: If the committed files don’t have execute bit in the repo, ensure your installer runs
chmod +x .git/hooks/*.
Security checklist for client-side hooks
- Trust the repo before you install its hooks. Review the
hooks/folder like any other code. - Explicit install: nothing runs until the developer chooses to install.
- Print clear errors when blocking a commit; never silently pass/fail.
- Keep hooks fast; slow hooks make teams disable them.
Alternatives you mentioned
If you prefer dedicated hook managers, you can evaluate:
- Husky (popular in JS/TS projects)
- Lefthook (language-agnostic, fast)
These tools are outside the core Git series here, but the idea is the same: manage hooks as code, install them explicitly.
Summary
- Hooks are local-only by design — they don’t clone (security).
- Put scripts in
hooks/(tracked), then install into.git/hooks/via a one-step command (e.g.,make install-hooks). - Ensure executable permissions are set.
- Consider managers like Husky or Lefthook if your stack prefers them.
Keep Learning 🚀
👉 Subscribe to Learning Ocean – Subscribers get coupon codes for my courses, early access to blogs and courses, and even exclusive YouTube videos.
👉 My YouTube Channel – More videos, more fun, and lots of learning!
👉 📺 Watch this topic in video form
Stay curious, keep coding, and let’s make learning fun together! 🎉