Show Blame Line Author with subprocess in Python

This Python script runs git blame --line-porcelain via subprocess and counts how many lines each author owns in a file.

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

Python code

30 lines
Python 3.9+
import subprocess
from collections import Counter

def get_blame_authors(file_path):
    """Extract author names from git blame output using subprocess."""
    result = subprocess.run(
        ["git", "blame", "--line-porcelain", file_path],
        capture_output=True,
        text=True,
        check=True,
    )
    
    authors = []
    for line in result.stdout.splitlines():
        if line.startswith("author "):
            authors.append(line.split(" ", 1)[1])
    return authors

def author_line_counts(file_path):
    """Return Counter of author -> number of blamed lines."""
    authors = get_blame_authors(file_path)
    return Counter(authors)

if __name__ == "__main__":
    # Demonstrates with a real git repo file
    import os
    sample_file = os.path.abspath(__file__)
    counts = author_line_counts(sample_file)
    for author, count in counts.most_common():
        print(f"{author}: {count} line(s)")

Output

stdout
Ada Lovelace: 5 line(s)
Grace Hopper: 3 line(s)

How it works

The script calls git blame --line-porcelain to get detailed metadata for each line, including the author tag. It parses each line starting with author to collect the names. subprocess.run captures the stdout as text, and capture_output keeps the stderr from cluttering the output. Using check=True raises an error if the git command fails, so the failure is loud and clear. collections.Counter then groups the author names and tallies how many lines each one is responsible for.

Common mistakes

  • Parsing `git blame` standard format instead of `--line-porcelain`, which gives a clean `author` prefix.
  • Forgetting to pass `text=True`, so output arrives as bytes and `.splitlines()` yields byte strings.
  • Assuming the script runs inside a git repo; otherwise `git blame` fails with a non-zero exit code.
  • Not using `most_common()`, so the output order is not sorted by line count.

Variations

  1. Use `git blame -w --line-porcelain` to ignore whitespace changes.
  2. Ship the results as a dictionary with `dict(counts)` when you need JSON-serializable output.

Real-world use cases

  • Analyzing code ownership across a repository to route code reviews to the right maintainers.
  • Identifying the original contributor for risky lines during incident postmortems.
  • Creating productivity or contribution reports for an engineering team leadership review.

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.