How to Make a Git Commit Heatmap by Hour in Python
Parse a git log output and count commits by weekday and hour, then print a compact heatmap table.
Python code
42 linesimport re
from collections import Counter
from datetime import datetime
def parse_commits(log_text):
"""Parse git log lines and count commits by (weekday, hour)."""
pattern = re.compile(r"^Date:\s+(.+)$")
counts = Counter()
for line in log_text.splitlines():
match = pattern.match(line)
if match:
date_str = match.group(1)
try:
dt = datetime.strptime(date_str, "%a %b %d %H:%M:%S %Y %z")
except ValueError:
dt = datetime.strptime(date_str, "%a %b %d %H:%M:%S %Y")
key = (dt.strftime("%A"), dt.hour)
counts[key] += 1
return counts
def format_heatmap(counts):
"""Print a compact weekday-by-hour heatmap."""
days = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
print(f"{'Day':<10}" + "".join(f"{h:>4}" for h in range(24)))
for day in days:
row = f"{day:<10}"
for hour in range(24):
row += f"{counts.get((day, hour), 0):>4}"
print(row)
if __name__ == "__main__":
sample_log = """Date: Mon Mar 04 09:30:00 2024 +0000
Date: Mon Mar 04 14:15:00 2024 +0000
Date: Tue Mar 05 10:00:00 2024 +0000
Date: Wed Mar 06 09:45:00 2024 +0000
Date: Wed Mar 06 16:20:00 2024 +0000
Date: Fri Mar 08 11:00:00 2024 +0000
Date: Sun Mar 10 20:30:00 2024 +0000
"""
commits = parse_commits(sample_log)
format_heatmap(commits)
Output
Day 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
Monday 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0
Tuesday 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
Wednesday 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0
Thursday 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Friday 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
Saturday 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Sunday 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0
How it works
The parse_commits function uses a regular expression to extract the Date: line from each line of the git log output. It then tries to parse the date string with two formats: one with a timezone offset and one without, to be robust to different git configurations. Each parsed date is converted to a datetime object, and a key of (weekday, hour) is used to increment a Counter. The formatting function prints a header row with all 24 hours and then each day's counts, using counts.get to default to 0 for missing entries. This produces a compact text-based heatmap that shows commit activity patterns across the week.
Common mistakes
- Using `re.search` instead of `re.match` when the Date line might not be at the start of the string.
- Not handling timezone-aware vs naive datetime strings by providing two parse formats.
- Assuming all hours are present and not using `.get()` with a default value.
Variations
- Use `pandas` to create a DataFrame and plot a seaborn heatmap for a visual chart.
- Read the git log directly via `subprocess.run(['git', 'log', '--format=...']).stdout` instead of a hardcoded string.
Real-world use cases
- Analyze development team activity to identify peak coding hours and improve collaboration windows.
- Generate reports for sprint retrospectives to visually show when commits were made during the iteration.
- Monitor repository health by detecting unusual commit patterns, such as late-night or weekend bursts that might indicate overwork.
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.