Find the Commit That Introduced a String in Git History Using Python

Use git log -S with Python subprocess to find the earliest commit that introduced a specific string across your repository history.

Medium Python 3.9+ Aug 9, 2026 Git + Python 12 views 0 copies

Python code

23 lines
Python 3.9+
import subprocess
import sys


def find_introducing_commit(repo_path: str, search_string: str, file_glob: str = "*") -> str:
    """Find the first commit that introduced a given string in a git repository."""
    result = subprocess.run(
        ["git", "-C", repo_path, "log", "--all", "--oneline", "-S", search_string,
         "--", file_glob],
        capture_output=True,
        text=True,
        check=True,
    )
    lines = [line for line in result.stdout.strip().splitlines() if line.strip()]
    if not lines:
        return "String not found in repository history."
    return lines[-1].split()[0]  # Oldest commit hash from the log tail


if __name__ == "__main__":
    repo = sys.argv[1] if len(sys.argv) > 1 else "."
    commit = find_introducing_commit(repo, "mock")
    print(f"Introducing commit: {commit}")

Output

stdout
Introducing commit: 4f2a9c1

How it works

The git log -S pickaxe option finds commits where the number of occurrences of a string changed. Running with --all covers every branch, and --oneline keeps output compact. We reverse the order by taking the last line, which corresponds to the oldest commit. The -C repo_path flag runs git without changing directories, so relative paths stay stable. Filtering empty lines handles repositories with no matches gracefully.

Common mistakes

  • Taking the first commit instead of the last — git log returns newest first
  • Forgetting `--all` so commits on other branches are missed
  • Using the file path without `--` separator when it contains special characters

Variations

  1. Use `git log -G` with a regex pattern instead of a literal string
  2. Add `--reverse` to the command and take the first line for cleaner logic

Real-world use cases

  • Blame tracing: find where a buggy function name was first introduced in a legacy codebase.
  • Audit deep links: identify the PR that added a dependency version string for compliance reports.
  • Incident postmortems: discover which release commit introduced a new error message that triggered alerts.

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.