To reconstruct a timesheet from git history, run git log --author="You" --since="last Monday" --format="%ai %s" --all. Group the commits into sessions with a 30-minute idle threshold, map each session to a project, and round to 15-minute increments.
It is Friday afternoon, timesheets are due in an hour, and Monday is a blur. Your memory has already compressed the week into a vague sense of “worked on the auth refactor, I think”. Your git history has not. Every commit you pushed is a timestamped record of exactly what you did and when.
This guide walks through the exact commands, the session-splitting logic, and the edge cases. You will rebuild a defensible weekly timesheet in about fifteen minutes. You will also learn how to automate the job so you never do it by hand again.
Why is git history your best timesheet backup?
Every commit records a precise UTC timestamp, the author’s name and email, the branch, and the message. That is more data than most commercial trackers capture. Unlike memory, git history does not fade, compress, or reshape itself to fit the story you want to tell.
Branch names tied to ticket IDs — feat/ACME-142, bugfix/PROJ-88 — give you the project attribution for free. Pull request merge timestamps mark the boundaries where one unit of work ended and another began. Co-author trailers preserve pair-programming sessions that would otherwise vanish.
What git log can and cannot tell you
The log is strong on the typing part of development. It is silent on everything around it — meetings, design reviews, Slack threads, and long debugging sessions that produced no commits. That gap is why commit-only reconstruction recovers roughly 70-85% of a developer’s real working time, with the remainder requiring supplementary sources. We will come back to the blending step in the automation section.
How do you extract your weekly activity from git?
The core command is short. It is the flags that matter.
Step 1: Pull your weekly log
Run this inside the repository you worked in most:
git log --author="Your Name" \
--since="last Monday" \
--until="now" \
--format="%ai %H %D %s" \
--all
--all is the flag people miss most often. Without it, git log only walks the current branch — so anything you pushed to feat/login, hotfix/payments, or a private WIP branch is invisible. The official git documentation on git log lists every format placeholder; %ai is the strict ISO 8601 author date you want for session maths.
Step 2: Include commits across every repo you touched
Most client work now spans several repositories. Run the same command in each repo, prefix each line with the repo name, and concatenate:
for repo in ~/work/*/; do
cd "$repo"
git log --author="Your Name" --since="last Monday" \
--format="%ai|$(basename $repo)|%D|%s" --all
done | sort
Sorting by the ISO timestamp produces a single chronological view of your week across every project. This is the raw material for the rest of the reconstruction.
Step 3: Do not forget the reflog
If you rebased or force-pushed, some original commit timestamps are gone from the branch history. git reflog keeps them locally for 90 days by default. Run git reflog show --date=iso --all to see every HEAD change with timestamps, which often recovers sessions that git log silently hides after a rebase.
For an overview of how timestamps behave under rewrites, the Atlassian guide to git reflog is a solid reference.
How do you turn commit timestamps into timesheet entries?
Raw commits are a list of moments. A timesheet is a list of durations. Four rules bridge the gap.
Rule 1: Group consecutive commits into sessions
Walk the sorted list in order. Inside each group of commits on the same branch or ticket, compute the gap between adjacent timestamps. A gap under 30 minutes is a continuous session. A gap over 30 minutes starts a new one.
According to the 2024 Stack Overflow Developer Survey, over 60% of developers work across three or more tools daily. Short commit gaps often hide quick tool switches rather than real breaks. A 30-minute idle threshold is the common default across open-source git-hours tools. It balances undercount and overcount for most teams.
Rule 2: Add a lead-in for the first commit
Nobody types their first line of code at 09:00 and commits at 09:02. Add a fixed 5 to 15-minute lead-in at the start of each session. This covers the setup work before the first commit — reading yesterday’s PR comments, pulling the branch, orienting in the code.
Rule 3: Assign each session to a project
Build a small mapping table once and reuse it weekly:
| Pattern | Project | Client |
|---|---|---|
repo acme-checkout | Checkout refactor | Client Acme |
branch feat/PROJ-* | Project PROJ | Internal R&D |
branch hotfix/* | Emergency support | Billable priority rate |
If you use different emails for different clients, keep a .mailmap so the log treats you as a single author everywhere. If you do not, add a manual tag per row when you pull the log.
Rule 4: Round to the nearest 15 minutes
Raw durations are untidy — 47 minutes, 1 hour 23 minutes. Most billing systems want tidy numbers. Rounding to the nearest 15-minute increment produces a timesheet that looks professional and is easy for a client to verify. This is the same maths used in most approaches to mapping git commits to billable time. The threshold and the rounding are where accuracy lives.
What about meetings, reviews, and non-commit work?
Commit data misses four categories that often carry the highest billing rates. Reconstructing a full timesheet means blending git with at least one other signal.
Code review time
Reviewing a colleague’s pull request produces review comments and approvals. These events appear in GitHub and GitLab APIs but never touch your local commit history. Pull the pull_request_review and pull_request_review_comment activity from your code host for the same week and merge it into the timeline. Senior engineers whose main output is reviews lose the most when review time is ignored.
Pair programming
When two developers share a keyboard, only one name lands in the log. Commit trailers help after the fact — Co-authored-by: Name <email> — and most activity-based trackers parse those trailers to split the session between authors. If yesterday’s pair session has no trailer, rely on a manual note or a calendar event for attribution.
Meetings and async discussion
A kick-off call, a product review, or a long design thread is real work. None of it appears in git log. Export your calendar for the week and overlay meetings onto the commit timeline. A meeting that carries a ticket ID in its title attaches cleanly to the same project as the surrounding commits. For the full pattern, overlay your calendar export onto the commit timeline and reconcile any mismatches manually.
Long investigations
A two-hour bug hunt that produced no code still counts. Capture these as calendar blocks tagged with the ticket, or as a single manual entry with a note in the final timesheet. The principle is to keep git as the primary evidence and treat everything else as a labelled supplement.
How do you automate timesheet reconstruction so you never do this again?
A one-off Friday scramble is fine. Doing it every week is a tax. Three levels of automation reduce the scramble to a click.
Level 1: A shell script that produces a weekly CSV
Point a script at every repo in your working directory, run the log extraction, apply the session maths, and write the output to a CSV your billing tool can import:
#!/bin/bash
# weekly-timesheet.sh
OUTPUT="$HOME/timesheets/$(date +%Y-W%V).csv"
echo "timestamp,repo,branch,message" > "$OUTPUT"
for repo in ~/work/*/; do
cd "$repo" || continue
git log --author="$(git config user.name)" \
--since="last Monday" \
--format="%ai,$(basename "$repo"),%D,%s" --all \
>> "$OUTPUT"
done
A second script — Python or Node — reads the CSV, applies the 30-minute split, rounds to 15 minutes, and emits a ready-to-paste timesheet. Total build time is an afternoon.
Level 2: A cron job that runs nightly
Schedule the script to run every evening at 19:00 and append the day’s sessions to a local log. On Friday, concatenate five files and review. The advantage is freshness — you are reviewing work you did earlier in the day, not trying to remember Monday from a distance.
Level 3: An activity-based time tracker
At a certain team size, maintaining scripts is its own part-time job. Activity-based trackers reconstruct your timesheet continuously in the background. They combine commits with pull request events, review comments, and calendar entries that git alone misses. The output is a draft timesheet that appears before you ask for it. That is how teams that already set up time tracking with GitHub cut timesheet effort to a few minutes per week.
The trade-off is trust. A good tool shows you every source event behind every entry, so you can verify rather than take it on faith. A bad one is a black box. Ask for the audit trail during evaluation.
How accurate is a git-reconstructed timesheet?
Better than your memory. Roughly on par with a diligent manual tracker. Short of a perfect record.
Under realistic settings, commit-only reconstruction recovers 70-85% of billable time. Realistic means a 30-minute idle threshold, a 5-minute lead-in, and commits every 30 to 60 minutes on average. Adding pull request and review events lifts accuracy to around 90%. Overlaying calendar entries closes most of the rest.
The real comparison is not “git activity versus a perfect timesheet”. It is “git activity versus the timesheet a human writes on Friday afternoon from memory”. Recall-based timesheets are routinely 20-30% off on both sides — some hours padded, others forgotten. A git-backed timesheet has a shorter error bar and a clear audit trail behind every entry. That audit trail is what clients care about when they query an invoice.
What should you do next?
Three moves turn this from a rescue operation into a working system.
First, run the extraction script once for last week, even if your timesheet is already in. Compare the output with what you submitted. The delta is your honest baseline and tells you whether you are over- or under-billing.
Second, pick an idle threshold and a lead-in value and keep them stable for a full month. Changing parameters mid-cycle makes trend data meaningless.
Third, decide whether scripts are enough or whether you need an activity-based tracker. For a solo contractor, a cron job and a CSV may be plenty. For a team of twenty, the script approach collapses under its own maintenance cost — and that is the point where automation pays for itself.
Key Takeaway:
git log --author --since --allplus a 30-minute idle threshold and repo-to-project mapping rebuilds a defensible weekly timesheet in about 15 minutes.
Frequently Asked Questions
Can I reconstruct a timesheet from git if I rebase or squash commits?
Partially. Rebasing rewrites commit timestamps and squashing collapses them. For the most accurate picture, capture the commit data before a squash merge — from the feature branch rather than main. git reflog also preserves the original commit timestamps locally for 90 days. Branch-level activity and pull request events are more resilient than individual commits for teams that rewrite history by policy.
How accurate is a timesheet built from git history?
Git-based timesheets typically capture 70-85% of a developer’s billable working time. The remainder covers meetings, design reviews, Slack discussions, and bug investigations that produced no commits. Supplementary data — calendar events and code review activity — lifts accuracy to around 90% when blended in.
What if I pair-program and my partner makes all the commits?
Use Co-authored-by: trailers in your commit messages so both authors are preserved in the log. Many git-based time tools parse these trailers and split the session evenly between both developers. For sessions that predate the trailer habit, fall back to a calendar entry or a manual adjustment in the final timesheet.
How do I reconstruct a timesheet across multiple git repos?
Run the same git log command in each repository, tag each row with the repo name, and merge into a single chronological timeline. Sort by ISO timestamp to see your real working order, then apply the same session-splitting rules across the combined list. A commit in Repo A five minutes after one in Repo B counts as a repo switch, not a new session.
What idle threshold works best when reconstructing from git?
A 30-minute threshold is the default in most open-source git-hours tools and produces the best balance between undercounting and overcounting. Teams that commit rarely — around half a dozen times a day — should raise it to 60 minutes. Teams that commit frequently can drop it to 15-20 minutes without losing much accuracy.
Does git reflog help recover a lost timesheet after a rebase?
Yes. git reflog keeps a local record of every HEAD change with timestamps for 90 days by default. This record survives rebases and force pushes that have rewritten branch history. Run git reflog show --date=iso --all to inspect the preserved timeline and pull sessions the regular log has lost.
Can I reconstruct hours I spent on code reviews from git alone?
No. Review comments and approvals are hosted events. They live in GitHub or GitLab APIs, not in the local git log. Pull pull_request_review and pull_request_review_comment activity from your code host for the same week and merge it into the timeline alongside your commits.
Ready to stop reconstructing timesheets by hand?
Connect your repositories to Keito and let your git activity build an accurate timesheet continuously. Review on Friday, approve in a click, export to your invoicing tool.