← Back to list

Git-Aware .env Diff Tool using Go

🔍 The Problem: Invisible .env Drift

Ashish Salunkhe in DevOps.dev · 2025-05-27 15:59 · 16 claps · 2.6 min read
#go-language #git #developer-tools #developer-productivity #platform-engineering
Open on Medium ↗
Wiki topics: 🔓 · Open Source ⏱️ · Productivity

Git-Aware .env Diff Tool using Go

🔍 The Problem: Invisible .env Drift

We’ve all been there.

You check out a new branch, deploy to staging, and suddenly nothing works. Logs point to missing API keys or unexpected ports. After digging, you realize someone changed a .env file on another branch. The change went unnoticed because .env files usually aren't tracked rigorously and most teams don't diff them during reviews.

This happened to me one too many times.

So I built goenvdiff: a CLI tool that compares .env files across Git branches or commits and shows what's added, removed, or changed.

But that was just the beginning.

⚙️ MVP: A Basic Diff Tool

The first version of goenvdiff was intentionally simple:

  • Written in Go
  • Used git show to pull .env files from refs
  • Parsed them with godotenv
  • Showed a colorized diff
  • Supported --json for pipelines
  • Powered by Cobra CLI

A typical usage:

goenvdiff --from main --to feature/login --path .env

Output:

+ API_KEY added (abc123)
- DEBUG removed (was true)
~ PORT changed from 8080 to 9090

Useful? Yes. Production-ready? Not quite.

❌ The Limitations

While the tool worked, it wasn’t very useful yet:

  • Only worked with one .env file at a time
  • No support for .env.production, .env.test, etc.
  • Couldn’t compare working directory vs Git history
  • No awareness of secrets drift
  • Not usable inside CI or GitHub workflows
  • No output formatting for markdown or HTML

The idea was good, but it needed a serious upgrade to be dev-ready.

🧪 From Toy to Tool: Making goenvdiff Actually Useful

I broke down the evolution into four product-focused phases.

Phase 1: Real Developer Use

  • Multi-file support: .env.* globs
  • Local vs Git diff: Compare uncommitted vs committed
  • Secret drift detection: Flag SECRET, API_KEY, etc.
  • Better output context: Show commit hashes and timestamps

Phase 2: Workflow Integration

  • Pre-commit hook: Prevent sensitive drift before commit
  • CI validation: Use in GitHub Actions to block unsafe merges
- name: Env Diff
  run: |
    goenvdiff --from main --to HEAD --json --path .env > diff.json
    jq '.[] | select(.Key=="API_KEY")' diff.json && exit 1 || exit 0

Phase 3: Output Polish

  • Markdown export: For GitHub PRs
  • HTML export: For CI dashboards
  • Custom color themes: Light/dark modes

Phase 4: Advanced Diffs

  • Semantic changes: Type-aware diffing
  • Explain mode: Suggest impacted systems or configs

🔬 Architecture & Flow

+------------+         +------------------+         +---------------+
| Git Commit |  --->   | Read .env file   |  --->   | Parse KeyVals |
+------------+         +------------------+         +---------------+
       |                                                  |
       |                                                  v
       |                                      +--------------------------+
       +---> another Git ref --->            | Diff Key-Value Pairs      |
                                             |  - Added / Removed / Mod  |
                                             +--------------------------+
                                                             |
                                                             v
                                      +------------------------------------+
                                      | Print Output / Export JSON / MD    |
                                      +------------------------------------+

🎓 Lessons Learned

  • Go was the right choice: fast, static binaries, easy CLI tools
  • **git show over go-git**: simpler and more reliable for small tools
  • Engineers love clean diffs: color-coded, commit-aware changes help catch real bugs
  • CI integration matters: A tool becomes useful when it can break the build for the right reasons

🚀 What’s Next

  • --match ".env*" support for multiple files
  • Markdown/HTML export
  • Severity tagging for high-risk env changes
  • Homebrew tap for one-line installs

📚 Try It Out

go install github.com/ashishsalunkhe/goenvdiff@latest

Or clone it:

git clone https://github.com/ashishsalunkhe/goenvdiff.git
cd goenvdiff
go build -o goenvdiff

Try it:

goenvdiff --from main --to feature/login --path .env

👋 Final Thoughts

If you’ve ever been burned by unseen .env changes, you’ll get why this tool exists.

But building a tool is one thing. Making it actually useful something a dev team wants to install, use in CI, and trust with secrets takes iteration, feedback, and a shift from “it works” to “it integrates.”

I’d love feedback, contributions, or just a GitHub star if you find it helpful.

Repo: github.com/ashishsalunkhe/goenvdiff


메타데이터
post_id
e705d9b0f244
slug
git-aware-env-diff-tool-using-go-e705d9b0f244
url
https://blog.devops.dev/git-aware-env-diff-tool-using-go-e705d9b0f244
canonical_url
https://blog.devops.dev/git-aware-env-diff-tool-using-go-e705d9b0f244
author_url
https://medium.com/@ashish-salunkhe
status
ok
fetched_at
2026-07-09 04:10:03