How to generate and parse an interactive rebase TODO list in Python
Generate a Git interactive rebase TODO list from commit data and parse it back into structured records.
Python code
38 linesimport re
from collections import namedtuple
Commit = namedtuple("Commit", ["hash", "subject"])
def generate_rebase_todo(commits, action="pick"):
todo_lines = []
for i, commit in enumerate(commits):
if i == 0 and action == "reword":
todo_lines.append(f"reword {commit.hash} {commit.subject}")
elif action == "squash" and i == len(commits) - 1:
todo_lines.append(f"squash {commit.hash} {commit.subject}")
else:
todo_lines.append(f"pick {commit.hash} {commit.subject}")
return "\n".join(todo_lines)
def parse_todo(todo_text):
lines = todo_text.strip().splitlines()
parsed = []
for line in lines:
match = re.match(r"^(pick|reword|squash)\s+([a-f0-9]{7,40})\s+(.*)$", line)
if match:
parsed.append({"action": match.group(1), "hash": match.group(2), "subject": match.group(3)})
return parsed
if __name__ == "__main__":
commits = [
Commit("a1b2c3d", "Initial commit"),
Commit("e4f5a6b", "Add feature X"),
Commit("7c8d9e0", "Fix bug in feature X"),
]
todo = generate_rebase_todo(commits, action="squash")
print("Generated TODO:")
print(todo)
print("\nParsed TODO:")
for item in parse_todo(todo):
print(f" {item['action']:6s} {item['hash']} {item['subject']}")
Output
Generated TODO:
pick a1b2c3d Initial commit
pick e4f5a6b Add feature X
squash 7c8d9e0 Fix bug in feature X
Parsed TODO:
pick a1b2c3d Initial commit
pick e4f5a6b Add feature X
squash 7c8d9e0 Fix bug in feature X
How it works
The generate_rebase_todo function builds a standard Git TODO list by iterating over commit tuples and applying a chosen action to specific positions (first or last). The parse_todo function uses a regex to validate each line and extract action, hash, and subject into a list of dictionaries. Using namedtuple keeps the commit data lightweight and readable, and the script's __main__ block demonstrates the full flow. This pattern mirrors the real structure Git writes to .git/rebase-merge/git-rebase-todo, so you can read or simulate it from Python.
Common mistakes
- Forgetting that Git hashes can be full 40-char SHA-1, so the regex must allow 7 to 40 hex chars.
- Not stripping trailing whitespace or newlines from each line before parsing.
- Assuming the first commit is always 'reword' — the logic only rewrites based on the provided `action` parameter.
Variations
- Read an actual `git-rebase-todo` file with `pathlib.Path.read_text` and parse it directly.
- Use dataclasses instead of namedtuple for richer commit metadata.
Real-world use cases
- Automating a script to prepare a rebase for the last N commits with a specific action like squash.
- Validating a hand-written rebase TODO file before passing it to Git.
- Integrating with a CI pipeline that rewrites commit history or checks commit hygiene.
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.