How do you ensure that developers cannot commit unencrypted passwords or secrets into your Git repository before the code even hits the remote branch?
Quick Answer
Install a pre-commit hook (via a tool like gitleaks, git-secrets, or detect-secrets) that scans staged changes for credential-shaped patterns — AWS keys, private key headers, high-entropy strings, known API token formats — and blocks the commit locally before it's ever created, since catching a secret after it's pushed means it may already be scraped by automated bots within seconds. This must be paired with a server-side or CI-side scan as a second layer, because local pre-commit hooks are opt-in and easy to bypass with --no-verify or simply not installed, so the client-side hook is a fast developer-friendly first line of defense, not the only line.
Detailed Answer
Think of a office building with a metal detector at the front desk and a second bag-check station at the loading dock. The front-desk detector catches almost everyone as a matter of routine, quickly and with minimal friction — but it's staffed by whoever happens to be walking by, and a determined person could walk past it. The loading dock check is slower and less convenient, but nothing gets through it, because it's not optional the way the front desk is. Preventing secrets in Git needs both: a fast, convenient local check that catches the vast majority of accidents, and a mandatory server-side check that catches the rest regardless of whether any individual developer configured anything on their laptop.
Git was designed with hooks as local, per-clone scripts specifically because Git itself is a distributed system with no central authority over an individual developer's local repository — a pre-commit hook lives in .git/hooks on that one machine and isn't automatically shared or enforced across the team just by existing in the codebase, since .git/hooks itself is never committed to the repository (it's part of Git's local metadata directory). This is exactly why relying solely on pre-commit hooks is fragile: a new team member who clones the repo doesn't automatically get the hook installed unless a setup script or a tool like pre-commit or husky explicitly wires it in during onboarding, and any developer can bypass a hook that is installed with git commit --no-verify, whether accidentally or under time pressure.
Internally, a secret-scanning pre-commit hook works by running against the staged diff (git diff --cached) rather than the whole repository, checking each added line against a set of regex patterns tuned for common credential formats (AWS access keys start with a recognizable prefix like AKIA, private key files contain a distinctive -----BEGIN PRIVATE KEY----- header, and generic secrets are often flagged via Shannon entropy scoring, since random-looking high-entropy strings are statistically more likely to be tokens than actual English or code) and exits with a non-zero status to abort the commit if a match is found, before the commit object is ever created in the local repository, let alone pushed.
At production scale, mature teams layer three independent checks rather than relying on any single one: a local pre-commit hook (gitleaks protect --staged, git-secrets --scan) for fast developer feedback; a mandatory CI pipeline stage that re-runs the same scan against the full commit history of every pushed branch, catching anyone who bypassed or never installed the local hook; and GitHub's (or GitLab's) native push protection and secret scanning, which runs server-side on every push regardless of any local configuration and can block the push outright for certain well-known credential formats before it's even accepted. This defense-in-depth matters because each layer has a different failure mode — a local hook can be skipped, a CI check can be misconfigured to not fail the build, but having all three means an actual secret leak requires all three layers to fail simultaneously, which is a much lower probability event.
The non-obvious gotcha: secret scanners tuned purely on regex patterns for known formats (AWS keys, GitHub tokens) will completely miss a hardcoded database password or a custom internal API key that doesn't match any known vendor's format, which is why entropy-based detection and a maintained custom pattern list for your organization's own internal secret formats are both necessary — teams that only enable default rule sets from an off-the-shelf tool often have a false sense of complete coverage while their own internally-issued credentials slip through entirely undetected.