How to Run Git Commands from Python with subprocess
This helper runs `git status --short` and `git log --oneline` from Python, captures their output, and returns readable strings with error handling for non-repo directories.
Python code
36 linesimport subprocess
def git_status():
"""Return a short, human-readable git status."""
try:
output = subprocess.run(
["git", "status", "--short"],
capture_output=True,
text=True,
check=True,
).stdout.strip()
return output if output else "Working directory is clean."
except subprocess.CalledProcessError:
return "Error: not a git repository."
def git_log(limit=5):
"""Return the last `limit` commit messages."""
try:
output = subprocess.run(
["git", "log", "--oneline", f"-{limit}"],
capture_output=True,
text=True,
check=True,
).stdout.strip()
return output if output else "No commits yet."
except subprocess.CalledProcessError:
return "Error: not a git repository."
if __name__ == "__main__":
print("=== Git Status ===")
print(git_status())
print("\n=== Recent Commits ===")
print(git_log())
Output
=== Git Status ===
M README.md
?? new_file.txt
=== Recent Commits ===
3f2e1a4 Add README
2b8c9d0 Fix typo
1a2b3c4 Initial commit
How it works
The subprocess.run function executes a command and captures its output when capture_output=True is set. Passing text=True makes the output a string instead of bytes, which is easier to handle. The check=True flag raises a CalledProcessError if the command exits with a non-zero status, allowing us to catch errors like running outside a git repository. The --short and --oneline flags produce concise, human-readable output, and stripping whitespace keeps the result clean. This pattern is safe for simple read-only Git commands and avoids shell injection by passing arguments as a list.
Common mistakes
- Using `shell=True` with command strings instead of a list of arguments, which risks injection and quoting bugs.
- Forgetting `text=True`, causing bytes output that needs manual decoding.
- Not handling `CalledProcessError` when running commands outside a git repo.
- Assuming `check=True` is optional; without it, failures go unnoticed.
Variations
- Use `git rev-parse --short HEAD` to get the current commit hash.
- Parse the output with `splitlines()` to get a list of status lines for programmatic use.
Real-world use cases
- A CI script that checks for uncommitted changes before deploying.
- A developer tool that shows repo status and recent commits without leaving the terminal.
- An automation bot that gathers commit history for changelog generation.
Sponsored
More from Git + Python
- Amend Last Commit Message in Python easy
- Bisect Good Bad Automation Script in Python easy
- Build a Simple Log Graph in Python easy
- Bump Semantic Version Git Tag in Python easy
- Count Unique Contributors from Git Shortlog in Python easy
- Create a Mock GitHub Release API in Python for Testing gh CLI easy
Keep learning
Related tutorials and quizzes for this topic.