How to Parse git status --porcelain Output in Python

This code runs `git status --porcelain` and parses its output into a list of dictionaries with file paths and status descriptions.

Easy Python 3.8+ Aug 9, 2026 Git + Python 14 views 0 copies

Python code

34 lines
Python 3.8+
import subprocess

def parse_git_status_porcelain():
    try:
        output = subprocess.check_output(
            ["git", "status", "--porcelain"], 
            text=True, 
            stderr=subprocess.DEVNULL
        )
    except (subprocess.CalledProcessError, FileNotFoundError):
        return []

    entries = []
    for line in output.splitlines():
        if not line.strip():
            continue
        status_code = line[:2]
        file_path = line[3:].strip()
        status_desc = {
            "??": "untracked",
            "M ": "modified",
            " M": "modified",
            "A ": "added",
            "D ": "deleted",
            "R ": "renamed",
            "C ": "copied",
            "U": "conflicted"
        }.get(status_code, "changed")
        entries.append({"status": status_desc, "file": file_path})
    return entries

if __name__ == "__main__":
    for entry in parse_git_status_porcelain():
        print(f"{entry['status']}: {entry['file']}")

Output

stdout
modified: src/app.py
untracked: new_file.txt
added: README.md

How it works

subprocess.check_output runs the git command and captures its stdout. --porcelain gives a stable, machine-readable format with two-character status codes. The code maps common codes to human-readable descriptions and returns an empty list if git is not available or the command fails. Splitting on lines and slicing ensures only the status and filename are extracted.

Common mistakes

  • Forgetting to pass `text=True` so output is a string, not bytes.
  • Ignoring filenames with spaces by not using line[3:].strip() correctly.
  • Not handling `FileNotFoundError` when git is not installed.
  • Oversimplifying status codes for staged vs unstaged changes.

Variations

  1. Use `git status --porcelain=v1` to force the original format for backward compatibility.
  2. Use `--untracked-files=no` to skip untracked files in the output.

Real-world use cases

  • A pre-commit hook that automatically formats or lints only changed files.
  • A script that summarizes repo state in CI logs or notifications.
  • A tool that generates a change log from staged and unstaged file statuses.

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.