Did That Secret Ever Touch Your Git History?
How to search your git history for committed secrets — and what to do when you find one.
You removed it. Committed the fix. But it was in the repo for a while — maybe days, maybe longer — and you’re not sure who pulled it. The question isn’t whether the secret is in the current code. It’s whether it was ever committed, and how far it spread.
Git history is append-only. Deleting a file doesn’t remove it from the log. The commit that introduced your .env is still there, reachable from anyone who cloned or forked before the cleanup.
Search With git log -S
The -S flag (the “pickaxe”) searches for commits that added or removed a specific string. It scans diffs, not commit messages.
git log -S "MY_SECRET_VALUE" --all --oneline
--all includes every branch and tag, not just your current one. If you get a hit, the output shows the commit hash and message where that string appeared in the diff.
To see the full diff for a match:
git log -S "MY_SECRET_VALUE" --all -p
If you only know the key name and not the value, use -G instead — it accepts a regex:
git log -G "OPENAI_API_KEY" --all --oneline
Scan the Full History With gitleaks
If you’re not sure what to search for — or want to catch secrets you didn’t know were there — gitleaks scans for known patterns: AWS keys, GitHub tokens, Stripe secrets, and hundreds of others.
# install
brew install gitleaks # macOS
# scan the full history of the current repo
gitleaks detect --source . --log-opts="--all"
No account required. Nothing sent anywhere. It outputs each finding with the commit hash, file, line, and matched rule.
To write a full report:
gitleaks detect --source . --log-opts="--all" --report-path report.json
What Not to Do
This is the part most posts skip.
Deleting the file and pushing a new commit does not remove the secret from history. Neither does
git rm. Anyone who cloned before your fix can still rungit log -pand read the old commit.Even after rewriting history, anyone who already cloned or forked has a local copy. History rewriting prevents new clones from seeing the secret — it does not revoke copies already made.
This is why rotation comes first.
What To Actually Do
Step 1: Rotate the secret immediately. Revoke it at the source — your cloud provider, API platform, or secrets manager — before doing anything else. Assume it’s compromised.
Step 2: Rewrite history to remove the commit, using git filter-repo:
# install
brew install git-filter-repo # macOS
# remove a specific file from all history
git filter-repo --path path/to/secret-file --invert-paths
# or replace a specific string everywhere in history
git filter-repo --replace-text <(echo "ACTUAL_SECRET==>REDACTED")
Step 3: Force-push (coordinate with your team first — this rebases everyone):
git push origin --force --all
git push origin --force --tags
Step 4: Notify anyone who cloned the repo. Ask them to re-clone rather than pull — pulling a force-pushed branch can leave the old commits reachable locally. If the repo is public, contact the platform to clear cached commit objects.
The moment you suspect a secret hit the log, rotate it. Use git log -S or gitleaks to confirm the scope. Then clean history — knowing that cleanup limits future exposure, not past exposure.