Chapter 72: DevOps Projects Part 2: Git Branching, Hooks, Conflicts, Semver, Monorepo and Gitea
72.2 Project 12: Pre-commit hooks for linting and secret detection
Friends, bad commits waste reviewer time. Today we add Git hooks that block a commit when a secret sneaks in or a shell script fails a basic lint. Hooks run on your laptop before the push.
मित्रांनो, वाईट commits reviewer चा वेळ खातात. आज Git hooks: secret आला किंवा shell lint fail झाले तर commit थांबेल. Hooks laptop वर push आधी चालतात.
दोस्तों, खराब commits reviewer का समय खाते हैं. आज Git hooks: secret आने या shell lint fail होने पर commit रुकेगा. Hooks laptop पर push से पहले चलते हैं.
What you will build in this project
- A practice repo with a pre-commit hook.
- Secret pattern blocked.
- Shell lint check with shellcheck or a simple grep.
- Proof that a clean commit still passes.
1. Start from a real company story
At Capgemini in Mumbai, a developer pushed an AWS access key inside a demo script. The key lived in Git history for six hours.
Security rotated 14 keys and paused a client demo. Extra cost: about ₹2.5 lakh in engineer time and delayed billing.
Neha added a pre-commit hook that greps for AKIA and private key headers, plus a shellcheck step for *.sh files.
Today we build that safety net on a local repo.
Ravindra Bagale's Tip
Many students disable hooks with --no-verify to save one minute. That flag is for true emergencies only. Keep the hook on. Keep that habit.
खूप students --no-verify ने hooks बंद करतात एक मिनिट वाचवण्यासाठी. तो flag फक्त खऱ्या emergency साठी. Hook चालू ठेवा. सवय ठेवा.
बहुत students --no-verify से hooks बंद करते हैं एक मिनट बचाने को. वह flag सिर्फ असली emergency के लिए. Hook चालू रखें. आदत रखिए.
2. Start and prepare
Step 1: Init practice repo
Why: Need a repo first. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.
What: git init. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.
Example 1: init
Type this:
rm -rf /tmp/hooklab && mkdir /tmp/hooklab && cd /tmp/hooklab && git init && git config user.email 'neha@capgemini.example' && git config user.name 'Neha' && echo ready
You will see:
ready
What it means: Repo ready.
Example 2: readme
Type this:
cd /tmp/hooklab && printf '%s\n' 'hook lab' > README.md && git add README.md && git commit -m 'chore: start' && git log --oneline -1
You will see:
a11 chore: start
What it means: First commit without hooks.
Example 3: hooks dir
Type this:
cd /tmp/hooklab && ls .git/hooks | head -5
You will see:
applypatch-msg.sample
commit-msg.sample
fsmonitor-watchman.sample
post-update.sample
pre-commit.sample
What it means: Sample hooks present.
Step 2: Make a clean first commit
Why: Baseline history. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.
What: git commit. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.
Example 4: status
Type this:
cd /tmp/hooklab && git status -sb
You will see:
## main
What it means: Clean on main (or master renamed later).
Example 5: show
Type this:
cd /tmp/hooklab && cat README.md
You will see:
hook lab
What it means: Baseline file.
Example 6: config
Type this:
cd /tmp/hooklab && git config --get user.name
You will see:
Neha
What it means: Identity set.
Step 3: Write pre-commit hook
Why: Hook script is plain shell. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.
What: printf hook. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.
Example 7: hook
Type this:
cd /tmp/hooklab && printf '%s\n' '#!/bin/sh' 'set -e' 'echo "pre-commit: scanning..."' 'if git diff --cached -U0 | grep -E "AKIA[0-9A-Z]{16}|BEGIN OPENSSH PRIVATE KEY"; then' ' echo "BLOCKED: possible secret in staged diff" >&2' ' exit 1' 'fi' 'for f in $(git diff --cached --name-only --diff-filter=ACM | grep "\.sh$" || true); do' ' if grep -q "curl .*| *sh" "$f" 2>/dev/null; then' ' echo "BLOCKED: pipe-to-shell in $f" >&2' ' exit 1' ' fi' 'done' 'echo "pre-commit: ok"' > .git/hooks/pre-commit && wc -l .git/hooks/pre-commit
You will see:
12 .git/hooks/pre-commit
What it means: Hook written with secret and shell checks.
Example 8: mode
Type this:
cd /tmp/hooklab && chmod 755 .git/hooks/pre-commit && stat -c '%a %n' .git/hooks/pre-commit
You will see:
755 .git/hooks/pre-commit
What it means: Executable.
Example 9: head
Type this:
cd /tmp/hooklab && head -3 .git/hooks/pre-commit
You will see:
#!/bin/sh
set -e
echo "pre-commit: scanning..."
What it means: Shebang ok.
3. Build the main pieces
Step 4: Make hook executable
Why: Mode 755 required. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.
What: chmod 755. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.
Example 10: chmod proof
Type this:
cd /tmp/hooklab && test -x .git/hooks/pre-commit && echo executable
You will see:
executable
What it means: Git will run it.
Example 11: dry run hook
Type this:
cd /tmp/hooklab && .git/hooks/pre-commit
You will see:
pre-commit: scanning...
pre-commit: ok
What it means: Empty staged diff passes.
Example 12: list
Type this:
cd /tmp/hooklab && ls -l .git/hooks/pre-commit
You will see:
-rwxr-xr-x 1 user user ... .git/hooks/pre-commit
What it means: Mode shown.
Step 5: Try commit with fake key
Why: Fake AKIA must block. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.
What: git commit fail. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.
Example 13: fake key file
Type this:
cd /tmp/hooklab && printf '%s\n' 'export AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE' > leak.env && git add leak.env && echo staged
You will see:
staged
What it means: Fake key staged on purpose. Not a real secret.
Example 14: commit blocked
Type this:
cd /tmp/hooklab && git commit -m 'bad: leak' 2>&1 | tee /tmp/block1.txt | tail -5
You will see:
pre-commit: scanning...
BLOCKED: possible secret in staged diff
What it means: Commit refused.
Example 15: still staged
Type this:
cd /tmp/hooklab && git status -s
You will see:
A leak.env
What it means: File still staged; nothing entered history.
Step 6: See refusal
Why: Message explains why. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.
What: Read stderr. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.
Example 16: message
Type this:
grep BLOCKED /tmp/block1.txt
You will see:
BLOCKED: possible secret in staged diff
What it means: Clear reason for the developer.
Example 17: log unchanged
Type this:
cd /tmp/hooklab && git log --oneline | wc -l
You will see:
1
What it means: Only the first commit remains.
Example 18: reset
Type this:
cd /tmp/hooklab && git reset HEAD leak.env && rm -f leak.env && git status -s
You will see:
What it means: Clean again.
4. Automate and verify
Step 7: Remove secret and commit
Why: Clean path must work. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.
What: git commit ok. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.
Example 19: safe file
Type this:
cd /tmp/hooklab && printf '%s\n' 'export APP_ENV=dev' > app.env && git add app.env && git commit -m 'chore: add app.env' && git log --oneline -2
You will see:
pre-commit: scanning...
pre-commit: ok
b22 chore: add app.env
a11 chore: start
What it means: Clean commit passes the hook.
Example 20: show env
Type this:
cd /tmp/hooklab && cat app.env
You will see:
export APP_ENV=dev
What it means: No secret pattern.
Example 21: status
Type this:
cd /tmp/hooklab && git status -sb
You will see:
## main
What it means: Clean.
Step 8: Add shell script lint
Why: *.sh get a check. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.
What: grep check. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.
Example 22: bad sh
Type this:
cd /tmp/hooklab && printf '%s\n' '#!/bin/sh' 'curl http://example.com/install.sh | sh' > install.sh && git add install.sh && echo bad_staged
You will see:
bad_staged
What it means: Pipe-to-shell pattern staged.
Example 23: block sh
Type this:
cd /tmp/hooklab && git commit -m 'bad: pipe' 2>&1 | tee /tmp/block2.txt | tail -4
You will see:
pre-commit: scanning...
BLOCKED: pipe-to-shell in install.sh
What it means: Shell check refused the commit.
Example 24: unstage
Type this:
cd /tmp/hooklab && git reset HEAD install.sh && rm -f install.sh && echo cleared
You will see:
cleared
What it means: Bad file removed.
Step 9: Fail a bad script
Why: set -e missing fails. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.
What: fail sample. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.
Example 25: good sh
Type this:
cd /tmp/hooklab && printf '%s\n' '#!/bin/sh' 'set -e' 'echo hello' > greeter.sh && chmod 755 greeter.sh && git add greeter.sh && git commit -m 'feat: greeter script' && git log --oneline -1
You will see:
pre-commit: ok
c33 feat: greeter script
What it means: Good script committed.
Example 26: run script
Type this:
cd /tmp/hooklab && ./greeter.sh
You will see:
hello
What it means: Works.
Example 27: files
Type this:
cd /tmp/hooklab && git ls-files
You will see:
README.md
app.env
greeter.sh
What it means: Three tracked files.
5. Harden and accept
Step 10: Pass a good script
Why: Good script commits. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.
What: pass sample. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.
Example 28: cat hook
Type this:
cd /tmp/hooklab && grep -E 'AKIA|pipe-to-shell|pre-commit: ok' .git/hooks/pre-commit
You will see:
AKIA line present
pipe-to-shell line present
pre-commit: ok
What it means: Hook covers both rules.
Example 29: no verify warning
Type this:
echo 'use --no-verify only in a real emergency and tell the team'
You will see:
use --no-verify only in a real emergency and tell the team
What it means: Team rule.
Example 30: history clean
Type this:
cd /tmp/hooklab && git log --all --oneline | grep -i AKIA || echo 'no_key_in_history'
You will see:
no_key_in_history
What it means: History safe.
Step 11: Show hook contents
Why: Reviewers can read it. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.
What: cat hook. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.
Example 31: lint note
Type this:
printf '%s
' 'shell rule: block curl|sh in staged *.sh' > /tmp/shell-hook-rule.txt && cat /tmp/shell-hook-rule.txt
You will see:
shell rule: block curl|sh in staged *.sh
What it means: Documented before we test a bad script.
Example 32: hook still there
Type this:
test -x /tmp/hooklab/.git/hooks/pre-commit && echo still
You will see:
still
What it means: Hook remains.
Example 33: ready for sh
Type this:
echo next_we_stage_a_bad_script
You will see:
next_we_stage_a_bad_script
What it means: Next concept.
Step 12: Acceptance checklist
Why: Neha signs off when these pass. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.
What: All green. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.
Example 34: hook exists
Type this:
test -x /tmp/hooklab/.git/hooks/pre-commit && echo hook_ok
You will see:
hook_ok
What it means: Present.
Example 35: commits
Type this:
cd /tmp/hooklab && git rev-list --count HEAD
You will see:
3
What it means: Three clean commits.
Example 36: Sign-off
Type this:
echo 'Neha: PASS'
You will see:
Neha: PASS
What it means: Done.
Check yourself
Q1. Who added the Capgemini hook?
Neha
Q2. Hook file name?
pre-commit
Q3. AWS key prefix often seen?
AKIA
Q4. Flag that skips hooks?
--no-verify
Q5. Exit code that blocks?
1
Q6. Where do hooks live?
.git/hooks
Friends, you blocked secrets and rough shell scripts before they entered history. Did you understand? Let us try it once more. Add one more pattern for Slack tokens and prove it blocks.
मित्रांनो, तुम्ही secrets आणि खराब shell scripts history मध्ये जाण्यापूर्वी थांबवले. Slack token pattern add करून सिद्ध करा.
दोस्तों, आपने secrets और खराब shell scripts को history में जाने से पहले रोका. Slack token pattern जोड़कर सिद्ध करें.
Lab: try at home
- Init the practice repo.
- Write the pre-commit hook.
- Prove a secret is blocked.
- Prove a clean commit passes.
- Document the team rule.
Recap
- Hooks live under .git/hooks.
- pre-commit runs before the commit object.
- Exit code 1 blocks the commit.
- Never put real secrets in examples.
- --no-verify is last resort only.