<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Clay Pask</title>
    <description>The latest articles on DEV Community by Clay Pask (@clay_pask_53467eeab521893).</description>
    <link>https://dev.to/clay_pask_53467eeab521893</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3836243%2F3e0df6b0-9282-439b-ade8-cd58656844bb.png</url>
      <title>DEV Community: Clay Pask</title>
      <link>https://dev.to/clay_pask_53467eeab521893</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/clay_pask_53467eeab521893"/>
    <language>en</language>
    <item>
      <title>How I Built GitCleanse: A CLI Tool That Removes Secrets From Git History</title>
      <dc:creator>Clay Pask</dc:creator>
      <pubDate>Sat, 21 Mar 2026 12:19:46 +0000</pubDate>
      <link>https://dev.to/clay_pask_53467eeab521893/how-i-built-gitcleanse-a-cli-tool-that-removes-secrets-from-git-history-8pc</link>
      <guid>https://dev.to/clay_pask_53467eeab521893/how-i-built-gitcleanse-a-cli-tool-that-removes-secrets-from-git-history-8pc</guid>
      <description>&lt;p&gt;You committed a secret to git. Maybe an API key, a database password, a .env file that slipped through. It happens to everyone.&lt;/p&gt;

&lt;p&gt;The bad news: deleting the file and pushing a new commit does not remove it. The secret is still there in git history, accessible to anyone who clones your repo.&lt;/p&gt;

&lt;p&gt;I built GitCleanse to fix this.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does
&lt;/h2&gt;

&lt;p&gt;GitCleanse is a CLI tool that scrubs secrets from your git history. Point it at a repo, tell it what to remove, and it rewrites history as if the secret was never there.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx gitcleanse &lt;span class="nt"&gt;--repo&lt;/span&gt; ./my-project &lt;span class="nt"&gt;--pattern&lt;/span&gt; &lt;span class="s2"&gt;"AKIA[0-9A-Z]{16}"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It uses git filter-branch under the hood but wraps the messy parts in a clean interface. No more staring at git documentation trying to remember the exact incantation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why git delete is not enough
&lt;/h2&gt;

&lt;p&gt;When you delete a file and commit, git records the deletion — but the old commits still exist. Anyone with access to your repo history can run &lt;code&gt;git log&lt;/code&gt; and find the file in a previous commit.&lt;/p&gt;

&lt;p&gt;This is why secret leaks are so dangerous even after you "fix" them. The fix only works if you:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Revoke and rotate the secret (always do this first)&lt;/li&gt;
&lt;li&gt;Remove it from git history so it cannot be retrieved&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;GitCleanse handles step 2.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;GitCleanse rewrites your git history by:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Identifying commits that contain the target secret or file&lt;/li&gt;
&lt;li&gt;Rewriting each affected commit to remove the secret&lt;/li&gt;
&lt;li&gt;Cleaning up refs and running garbage collection so the old data is not recoverable&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After running it you will need to force-push to your remote. This is the expected behaviour — you are rewriting history.&lt;/p&gt;

&lt;h2&gt;
  
  
  The companion tool
&lt;/h2&gt;

&lt;p&gt;GitCleanse pairs naturally with &lt;a href="https://incredibroxp.gumroad.com/l/ctansc" rel="noopener noreferrer"&gt;EnvGuard&lt;/a&gt;, which audits your .env files before commits and catches secrets before they reach git. EnvGuard is prevention. GitCleanse is the cure.&lt;/p&gt;

&lt;p&gt;If you are reading this because something already leaked: revoke the secret first, then run GitCleanse, then switch to EnvGuard to make sure it never happens again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get it
&lt;/h2&gt;

&lt;p&gt;GitCleanse is available on Gumroad for €15: &lt;a href="https://incredibroxp.gumroad.com/l/hcunuf" rel="noopener noreferrer"&gt;https://incredibroxp.gumroad.com/l/hcunuf&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One-time purchase, instant download.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Part of a series on building small developer tools. Also in this series: &lt;a href="https://dev.to/clay_pask_53467eeab521893/how-i-built-envguard-a-cli-tool-to-stop-leaking-env-secrets-to-git-k45"&gt;EnvGuard&lt;/a&gt; and &lt;a href="https://dev.to/clay_pask_53467eeab521893/how-i-built-readmegen-a-cli-tool-that-writes-your-readme-for-you-3ek5"&gt;ReadmeGen&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>devtools</category>
      <category>git</category>
      <category>security</category>
    </item>
    <item>
      <title>How I Built ReadmeGen: A CLI Tool That Writes Your README For You</title>
      <dc:creator>Clay Pask</dc:creator>
      <pubDate>Sat, 21 Mar 2026 10:12:54 +0000</pubDate>
      <link>https://dev.to/clay_pask_53467eeab521893/how-i-built-readmegen-a-cli-tool-that-writes-your-readme-for-you-3ek5</link>
      <guid>https://dev.to/clay_pask_53467eeab521893/how-i-built-readmegen-a-cli-tool-that-writes-your-readme-for-you-3ek5</guid>
      <description>&lt;p&gt;Every developer has that one (or ten) repos with no README. You know the project, you built it, but writing the docs always feels like a chore you will get to later. Later never comes.&lt;/p&gt;

&lt;p&gt;I built ReadmeGen to solve this for myself. It is a CLI tool that scans your codebase and generates a professional README automatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does
&lt;/h2&gt;

&lt;p&gt;Point it at any project directory and it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Detects your language, framework, and dependencies from package files&lt;/li&gt;
&lt;li&gt;Identifies the entry point and main purpose of the project&lt;/li&gt;
&lt;li&gt;Generates a structured README with description, installation, usage, and license&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;One command. Done.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I built it
&lt;/h2&gt;

&lt;p&gt;I was cleaning up side projects for my portfolio. Half had no README. The other half had a two-line placeholder from years ago.&lt;/p&gt;

&lt;p&gt;Writing READMEs is tedious. The structure is always the same: description, install, usage, license. The only thing that changes is the content. So I automated it.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;ReadmeGen reads your manifest files (package.json, requirements.txt, Cargo.toml) to understand the project. It uses heuristics to identify the entry point, scripts, and purpose. No AI, no API calls, no internet. Just static analysis and sensible templates.&lt;/p&gt;

&lt;h2&gt;
  
  
  The result
&lt;/h2&gt;

&lt;p&gt;I have used it on 8 projects. Gets you 80 percent of the way there in seconds. The remaining 20 percent is a quick edit rather than staring at a blank page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get it
&lt;/h2&gt;

&lt;p&gt;ReadmeGen is available on Gumroad for 9 EUR: &lt;a href="https://incredibroxp.gumroad.com/l/jfryv" rel="noopener noreferrer"&gt;https://incredibroxp.gumroad.com/l/jfryv&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One-time purchase, instant download, no subscription.&lt;/p&gt;




&lt;p&gt;Part of a series building small dev tools. Previous tool: EnvGuard (&lt;a href="https://dev.to/clay_pask_53467eeab521893/how-i-built-envguard-a-cli-tool-to-stop-leaking-env-secrets-to-git-k45"&gt;https://dev.to/clay_pask_53467eeab521893/how-i-built-envguard-a-cli-tool-to-stop-leaking-env-secrets-to-git-k45&lt;/a&gt;) which audits .env files for exposed secrets before they reach git.&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>devtools</category>
      <category>opensource</category>
      <category>productivity</category>
    </item>
    <item>
      <title>I automated README writing — here's what it generates</title>
      <dc:creator>Clay Pask</dc:creator>
      <pubDate>Sat, 21 Mar 2026 00:17:39 +0000</pubDate>
      <link>https://dev.to/clay_pask_53467eeab521893/i-automated-readme-writing-heres-what-it-generates-3eph</link>
      <guid>https://dev.to/clay_pask_53467eeab521893/i-automated-readme-writing-heres-what-it-generates-3eph</guid>
      <description>&lt;p&gt;Every developer has done it. You finish a project, push it to GitHub, and then stare at the empty README.md for 20 minutes before writing "# my-project" and calling it a day.&lt;/p&gt;

&lt;p&gt;A bad README costs you stars, contributors, and credibility. A good one takes forever to write. So I automated it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What ReadmeGen does
&lt;/h2&gt;

&lt;p&gt;ReadmeGen scans your project and generates a complete, structured README in seconds.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; readmegen
readmegen generate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It detects your stack automatically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Node.js&lt;/strong&gt; ‚Äî reads package.json, detects React/Vue/Next.js/Express, finds your scripts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Python&lt;/strong&gt; ‚Äî detects requirements.txt or pyproject.toml&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Go&lt;/strong&gt; ‚Äî reads go.mod&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rust&lt;/strong&gt; ‚Äî reads Cargo.toml&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And generates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Title with version and license badges&lt;/li&gt;
&lt;li&gt;Description (pulled from package.json or existing README)&lt;/li&gt;
&lt;li&gt;Table of contents&lt;/li&gt;
&lt;li&gt;Features section (with placeholders to fill in)&lt;/li&gt;
&lt;li&gt;Requirements with correct versions&lt;/li&gt;
&lt;li&gt;Installation instructions (correct for your package manager)&lt;/li&gt;
&lt;li&gt;Usage examples&lt;/li&gt;
&lt;li&gt;Configuration table for environment variables&lt;/li&gt;
&lt;li&gt;Docker setup (if you have a Dockerfile)&lt;/li&gt;
&lt;li&gt;Test instructions (if you have a test script)&lt;/li&gt;
&lt;li&gt;Contributing guide&lt;/li&gt;
&lt;li&gt;License section&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Example
&lt;/h2&gt;

&lt;p&gt;Running it on a Node.js CLI tool:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;readmegen generate

  üîç Detecting project type...
  üì¶ Detected: JavaScript / Express
  üìù Generating README...
  ‚úÖ README.md generated

  Tip: Fill &lt;span class="k"&gt;in &lt;/span&gt;the Features section and add real usage examples.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# my-api&lt;/span&gt;

&lt;span class="p"&gt;![&lt;/span&gt;&lt;span class="nv"&gt;Node.js&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://img.shields.io/badge/node-%3E%3D16-green&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="p"&gt;![&lt;/span&gt;&lt;span class="nv"&gt;Version&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://img.shields.io/badge/version-1.2.0-blue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;![License: MIT&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://img.shields.io/badge/License-MIT-yellow.svg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;](...)
&lt;span class="gt"&gt;
&amp;gt; A fast REST API built with Express&lt;/span&gt;

&lt;span class="gu"&gt;## Table of Contents&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Features&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;#features&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Installation&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;#installation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
...

&lt;span class="gu"&gt;## Installation&lt;/span&gt;
git clone https://github.com/you/my-api.git
cd my-api
npm install

&lt;span class="gu"&gt;## Usage&lt;/span&gt;
npm start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Needs some filling-in for the features section, but the structure and boilerplate is done.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 80/20 of README writing
&lt;/h2&gt;

&lt;p&gt;A good README needs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;What it does&lt;/strong&gt; ‚Äî one sentence, immediately&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;How to install it&lt;/strong&gt; ‚Äî exact commands that work&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;How to use it&lt;/strong&gt; ‚Äî a real example, not pseudocode&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;How to configure it&lt;/strong&gt; ‚Äî env vars, config files&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;How to contribute&lt;/strong&gt; ‚Äî if it's open source&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;ReadmeGen handles the structure and all the repetitive parts. You just fill in what only you know ‚Äî the actual features and examples.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get it
&lt;/h2&gt;

&lt;p&gt;‚Üí &lt;strong&gt;&lt;a href="https://incredibroxp.gumroad.com/l/jfryv" rel="noopener noreferrer"&gt;ReadmeGen on Gumroad&lt;/a&gt;&lt;/strong&gt; ‚Äî ‚Ç¨9, one-time purchase&lt;/p&gt;

&lt;p&gt;If you're building multiple projects, it pays for itself on the first README.&lt;/p&gt;

</description>
      <category>opensource</category>
    </item>
    <item>
      <title>Your AWS keys are in git history — here's how to remove them</title>
      <dc:creator>Clay Pask</dc:creator>
      <pubDate>Sat, 21 Mar 2026 00:16:04 +0000</pubDate>
      <link>https://dev.to/clay_pask_53467eeab521893/your-aws-keys-are-in-git-history-heres-how-to-remove-them-1cnh</link>
      <guid>https://dev.to/clay_pask_53467eeab521893/your-aws-keys-are-in-git-history-heres-how-to-remove-them-1cnh</guid>
      <description>&lt;p&gt;GitHub just sent you a secret scanning alert. Or maybe you noticed your AWS bill jumped overnight. Either way, you've got credentials in your git history and you need them gone.&lt;/p&gt;

&lt;p&gt;Here's the complete guide to removing secrets from git history ‚Äî and how to make sure it never happens again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why deleting the file isn't enough
&lt;/h2&gt;

&lt;p&gt;This is the most common mistake:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git &lt;span class="nb"&gt;rm&lt;/span&gt; .env
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"remove env file"&lt;/span&gt;
git push
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That removes the file from the current state of the repo. But anyone who clones it can still run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git log &lt;span class="nt"&gt;-p&lt;/span&gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;AWS_ACCESS_KEY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And see your secret in full. Every commit that ever contained your &lt;code&gt;.env&lt;/code&gt; file is permanently stored in git history ‚Äî until you rewrite that history.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Rotate your credentials immediately
&lt;/h2&gt;

&lt;p&gt;Before doing anything else ‚Äî &lt;strong&gt;rotate the exposed credentials&lt;/strong&gt;. Assume they're already compromised. AWS keys, Stripe keys, GitHub tokens ‚Äî rotate them all before proceeding.&lt;/p&gt;

&lt;p&gt;Git history rewrites take time. The keys might already have been scraped.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Check what's in your history
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Check if any .env files were ever committed&lt;/span&gt;
git log &lt;span class="nt"&gt;--all&lt;/span&gt; &lt;span class="nt"&gt;--full-history&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="s2"&gt;"*.env"&lt;/span&gt; &lt;span class="s2"&gt;".env*"&lt;/span&gt;

&lt;span class="c"&gt;# Search for specific patterns in history&lt;/span&gt;
git log &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="nt"&gt;--all&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s2"&gt;"AKIA[0-9A-Z]{16}"&lt;/span&gt;  &lt;span class="c"&gt;# AWS keys&lt;/span&gt;
git log &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="nt"&gt;--all&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s2"&gt;"sk_(live|test)_"&lt;/span&gt;    &lt;span class="c"&gt;# Stripe keys&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or use &lt;strong&gt;&lt;a href="https://incredibroxp.gumroad.com/l/hcunuf" rel="noopener noreferrer"&gt;GitCleanse&lt;/a&gt;&lt;/strong&gt; to do it automatically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; gitcleanse
gitcleanse scan           &lt;span class="c"&gt;# scans full history for secrets&lt;/span&gt;
gitcleanse check          &lt;span class="c"&gt;# quick .env check&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: Remove from history
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Option A: git-filter-repo (recommended)
&lt;/h3&gt;

&lt;p&gt;Install it first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;git-filter-repo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remove specific files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git filter-repo &lt;span class="nt"&gt;--path&lt;/span&gt; .env &lt;span class="nt"&gt;--invert-paths&lt;/span&gt; &lt;span class="nt"&gt;--force&lt;/span&gt;
git filter-repo &lt;span class="nt"&gt;--path&lt;/span&gt; .env.production &lt;span class="nt"&gt;--invert-paths&lt;/span&gt; &lt;span class="nt"&gt;--force&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Option B: BFG Repo Cleaner
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install BFG&lt;/span&gt;
brew &lt;span class="nb"&gt;install &lt;/span&gt;bfg  &lt;span class="c"&gt;# macOS&lt;/span&gt;

&lt;span class="c"&gt;# Remove files&lt;/span&gt;
bfg &lt;span class="nt"&gt;--delete-files&lt;/span&gt; .env
git reflog expire &lt;span class="nt"&gt;--expire&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;now &lt;span class="nt"&gt;--all&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git gc &lt;span class="nt"&gt;--prune&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;now &lt;span class="nt"&gt;--aggressive&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Option C: git filter-branch (always available, slower)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git filter-branch &lt;span class="nt"&gt;--force&lt;/span&gt; &lt;span class="nt"&gt;--index-filter&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s1"&gt;'git rm --cached --ignore-unmatch .env .env.production'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--prune-empty&lt;/span&gt; &lt;span class="nt"&gt;--tag-name-filter&lt;/span&gt; &lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--all&lt;/span&gt;

git reflog expire &lt;span class="nt"&gt;--expire&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;now &lt;span class="nt"&gt;--all&lt;/span&gt;
git gc &lt;span class="nt"&gt;--prune&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;now &lt;span class="nt"&gt;--aggressive&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or generate these commands automatically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gitcleanse clean &lt;span class="nt"&gt;--auto&lt;/span&gt; &lt;span class="nt"&gt;--output&lt;/span&gt; cleanup.sh
&lt;span class="c"&gt;# Review cleanup.sh, then:&lt;/span&gt;
bash cleanup.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4: Force push to remote
&lt;/h2&gt;

&lt;p&gt;‚ö†Ô∏è &lt;strong&gt;Coordinate with your team first.&lt;/strong&gt; This rewrites history ‚Äî everyone will need to re-clone.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git push origin &lt;span class="nt"&gt;--force&lt;/span&gt; &lt;span class="nt"&gt;--all&lt;/span&gt;
git push origin &lt;span class="nt"&gt;--force&lt;/span&gt; &lt;span class="nt"&gt;--tags&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 5: Ask GitHub/GitLab to purge caches
&lt;/h2&gt;

&lt;p&gt;Even after rewriting history, hosted services may cache old objects. Contact GitHub support or go to &lt;strong&gt;Settings ‚Üí Danger Zone&lt;/strong&gt; and request a cache purge.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6: Prevent it from happening again
&lt;/h2&gt;

&lt;p&gt;Add to &lt;code&gt;.gitignore&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;.&lt;span class="n"&gt;env&lt;/span&gt;
.&lt;span class="n"&gt;env&lt;/span&gt;.*
!.&lt;span class="n"&gt;env&lt;/span&gt;.&lt;span class="n"&gt;example&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use &lt;strong&gt;&lt;a href="https://incredibroxp.gumroad.com/l/ctansc" rel="noopener noreferrer"&gt;EnvGuard&lt;/a&gt;&lt;/strong&gt; as a pre-commit hook:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; envguard
&lt;span class="c"&gt;# .git/hooks/pre-commit:&lt;/span&gt;
envguard audit &lt;span class="nt"&gt;--strict&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It'll catch secrets before they're ever committed.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Rotate all exposed credentials immediately&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;git filter-repo&lt;/code&gt; to remove the file from history&lt;/li&gt;
&lt;li&gt;Force push to remote&lt;/li&gt;
&lt;li&gt;Ask GitHub to purge caches&lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;.env&lt;/code&gt; to &lt;code&gt;.gitignore&lt;/code&gt; and use a pre-commit hook&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The whole process takes about 15 minutes once you know the steps. The pain is in not knowing them at 2am when the alert hits.&lt;/p&gt;

</description>
      <category>tutorial</category>
    </item>
    <item>
      <title>How I built EnvGuard: a CLI tool to stop leaking .env secrets to git</title>
      <dc:creator>Clay Pask</dc:creator>
      <pubDate>Fri, 20 Mar 2026 23:59:01 +0000</pubDate>
      <link>https://dev.to/clay_pask_53467eeab521893/how-i-built-envguard-a-cli-tool-to-stop-leaking-env-secrets-to-git-k45</link>
      <guid>https://dev.to/clay_pask_53467eeab521893/how-i-built-envguard-a-cli-tool-to-stop-leaking-env-secrets-to-git-k45</guid>
      <description>&lt;p&gt;It happened on a Tuesday morning.&lt;/p&gt;

&lt;p&gt;I pushed a commit, went to get coffee, came back to find an AWS bill alert for $847. A crypto miner had been running on my dime for six hours ‚Äî because my &lt;code&gt;.env&lt;/code&gt; file with real AWS keys had just been committed to a public GitHub repo.&lt;/p&gt;

&lt;p&gt;I rotated the keys, cleaned up the history with &lt;code&gt;git filter-branch&lt;/code&gt;, filed a support ticket with AWS (they were actually great about it), and spent the rest of the day feeling sick.&lt;/p&gt;

&lt;p&gt;That was the day I decided to build &lt;strong&gt;EnvGuard&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What EnvGuard does
&lt;/h2&gt;

&lt;p&gt;EnvGuard is a CLI tool that audits your &lt;code&gt;.env&lt;/code&gt; files and catches dangerous secrets before they make it into git.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; envguard
envguard audit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It detects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;üî¥ &lt;strong&gt;AWS Access Key IDs and Secret Keys&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;üî¥ &lt;strong&gt;Stripe live/test secret keys&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;üî¥ &lt;strong&gt;GitHub tokens&lt;/strong&gt; (ghp_, ghs_, ghx_, etc.)&lt;/li&gt;
&lt;li&gt;üî¥ &lt;strong&gt;Slack tokens and webhook URLs&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;üî¥ &lt;strong&gt;Database URLs with embedded credentials&lt;/strong&gt; (postgres://user:pass@host)&lt;/li&gt;
&lt;li&gt;üî¥ &lt;strong&gt;PEM private keys&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;üü† &lt;strong&gt;JWT tokens&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;üü° &lt;strong&gt;Generic API keys&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;‚ö†Ô∏è &lt;strong&gt;Weak placeholder values&lt;/strong&gt; (changeme, password, secret, etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It also checks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Whether your &lt;code&gt;.env&lt;/code&gt; file is &lt;strong&gt;tracked by git&lt;/strong&gt; (the big one)&lt;/li&gt;
&lt;li&gt;Whether it's &lt;strong&gt;missing from &lt;code&gt;.gitignore&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Example output
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;‚ïî‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïó
‚ïë            EnvGuard Audit Report             ‚ïë
‚ïö‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïê‚ïù

  File: .env
  Variables found: 8
  Git tracked: ‚ö†Ô∏è  YES (danger!)
  In .gitignore: ‚ö†Ô∏è  No

  üî¥ [CRITICAL] This file is tracked by git!
     ‚Üí Fix: git rm --cached .env &amp;amp;&amp;amp; echo ".env" &amp;gt;&amp;gt; .gitignore

  üî¥ [CRITICAL] Possible AWS Access Key ID in "AWS_ACCESS_KEY_ID" (line 4)
     ‚Üí Fix: Rotate this credential immediately if real

  ‚ö†Ô∏è  [WARN] Weak value for "JWT_SECRET": looks like a placeholder
     ‚Üí Fix: Replace with a strong, randomly generated value
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Generate a safe .env.example
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;envguard example
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Strips all values, leaves just the keys ‚Äî safe to commit as a template for your team.&lt;/p&gt;

&lt;h2&gt;
  
  
  CI / pre-commit hooks
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# .git/hooks/pre-commit&lt;/span&gt;
envguard audit &lt;span class="nt"&gt;--strict&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Exits with code 1 if any high/critical issues found. Stops the commit before it happens.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why $12?
&lt;/h2&gt;

&lt;p&gt;I'm selling it for $12 as a one-time purchase. Cheap enough that it's an obvious yes for any developer, and it keeps the lights on so I can keep improving it.&lt;/p&gt;

&lt;p&gt;If you've ever had to rotate credentials at 2am or explain to your boss why the AWS bill tripled, you know it's worth it.&lt;/p&gt;

&lt;p&gt;‚Üí &lt;strong&gt;&lt;a href="https://incredibroxp.gumroad.com/l/ctansc" rel="noopener noreferrer"&gt;Get EnvGuard on Gumroad&lt;/a&gt;&lt;/strong&gt; ‚Äî $12, includes all future updates.&lt;/p&gt;

&lt;p&gt;Feedback welcome in the comments ‚Äî especially if there's a secret type you want me to add detection for.&lt;/p&gt;

</description>
      <category>javascript</category>
    </item>
  </channel>
</rss>
