How to Filter Git History to Remove Secret File Entries in Python

A pure-Python mock that filters a repository's history to drop any commit that touched a secret file, so you can plan a cleanup before rewriting Git history.

Easy Python 3.9+ Aug 9, 2026 Git + Python 11 views 0 copies

Python code

20 lines
Python 3.9+
from pathlib import Path
import json

def filter_history(history, secret_path):
    """Remove entries that touch the secret file."""
    return [entry for entry in history if secret_path not in entry["files"]]

if __name__ == "__main__":
    repo_history = [
        {"commit": "a1b2c3", "message": "Add app", "files": ["main.py", "app.py"]},
        {"commit": "d4e5f6", "message": "Fix bug", "files": ["utils.py"]},
        {"commit": "g7h8i9", "message": "Leak", "files": ["secrets.env", "main.py"]},
        {"commit": "j0k1l2", "message": "Add feature", "files": ["features.py"]},
    ]

    cleaned = filter_history(repo_history, "secrets.env")

    print(json.dumps(cleaned, indent=2))
    print(f"\nOriginal commits: {len(repo_history)}")
    print(f"Filtered commits: {len(cleaned)}")

Output

stdout
[
  {
    "commit": "a1b2c3",
    "message": "Add app",
    "files": ["main.py", "app.py"]
  },
  {
    "commit": "d4e5f6",
    "message": "Fix bug",
    "files": ["utils.py"]
  },
  {
    "commit": "j0k1l2",
    "message": "Add feature",
    "files": ["features.py"]
  }
]
Original commits: 4
Filtered commits: 3

How it works

The filter_history function uses a list comprehension to keep only entries where the secret file is not in entry["files"]. This simulates the detection step before a real git filter-branch or git filter-repo cleanup. It works because each entry is a plain dict with a files field, and the in operator checks membership in that list. The script prints the cleaned history as JSON for easy inspection, plus counts so you can see how many commits would be removed. In a real repo, you'd feed this with git log --name-only output and then use the filtered result to craft a history-rewriting command.

Common mistakes

  • Checking the secret filename against the whole commit message instead of the `files` list.
  • Forgetting that `in` does a substring match, so `secrets.env` also matches `mysecrets.env2`.
  • Relying on shallow history that doesn't include the file in older commits.

Variations

  1. Use `git log --name-only --pretty=format:` in a subprocess to build history from a real repo.
  2. Simulate with `filter(lambda e: secret_path not in e["files"], history)` instead of a list comprehension.

Real-world use cases

  • Auditing a legacy repo before rewriting history to purge an accidentally committed API key.
  • Building a pre-commit check that flags any staged change touching a secrets file.
  • Planning a filter-branch script that sanitizes historical commits without touching current branches.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Git + Python

Related tutorials and quizzes for this topic.