Time Management
Why Your GitHub History Isn’t a Timesheet
GitHub isn’t a timesheet, even when the green squares look like a work ethic. A commit is a snapshot of code. An invoice is a story about a client, a project, and a task a human will defend. Those objects are not the same, and treating them as interchangeable is how freelance developers underbill the week they actually lived.
If you consult or freelance, GitHub is where the artifact lives. Time tracking is where the money lives. Mixing them up feels efficient until Friday, when you try to turn a pull-request list into a line item a non-technical client will pay.
The mismatch: git records what landed in a repo. It does not record which client owned the hour, whether the hour was a meeting, whether review was billable, or whether you were on a retainer that already covered the commit. A timesheet needs that structure. A contribution graph does not have it.
Why do contribution graphs lie about billable hours?
A busy Saturday of refactors can light up GitHub and still belong to a side project. A quiet Tuesday of architecture review, stakeholder calls, and a failed deploy can be your most expensive client day and leave almost no commit. The graph rewards visible diffs. Clients pay for outcomes, attention, and risk — including the hours that never become a SHA.
Even on a client repo, commits collapse the wrong dimensions:
- Who is the client? Agency work and subcontracting often land in someone else’s organization. The repo name is not the bill-to name.
- What is the project? One monorepo can hold three retainers. One “website” repo can hold discovery, a redesign, and a care plan.
- What is the task? “Fix login” in git may have been two hours of reproduction, twenty minutes of code, and an hour of handoff notes.
- When did the work happen? Author dates get amended. Time zones drift. Squash merges erase the afternoon you actually spent.
That is before you admit the unbillable pile every developer knows: CI babysitting, dependency upgrades, Slack “got a sec?”, and code review that never becomes your commit.
What should you track instead of SHAs?
Track against the work a client already understands, not against the tool you used to do it. A simple taxonomy beats a clever git script:
- Discovery
- Architecture
- Implementation
- Code review / QA
- Meetings
- Support
- Internal / admin / sales
Put those labels on tasks under a client and a project. Then a commit can happen during Implementation without pretending the commit is the timesheet. When you invoice, the line can say “Architecture — auth flow” instead of `a3f91c2`.
This is the same reason billable units have to be understandable. Clients do not buy hashes. They buy phases they recognized in the proposal.
Why do Jira keys make terrible invoice line items?
Ticket keys have the same disease as commit hashes, with better branding. `PROJ-1847` is meaningful inside the tracker. On a PDF it looks like you are billing them for your homework system.
Jira, Linear, and Asana are process tools. They can be excellent for a team that already lives there. They are a weak billing surface for a solo consultant. The ticket title is often a developer shorthand. The time logged on the ticket, if any, is often a different product’s timer, rounded by a different rule, missing the call that created the ticket in the first place.
If a client asks what they paid for, you want “Homepage mockups, revision round 2” or “Production support, week of March 3.” You do not want a column of keys they cannot open without a license.
A week git will not reconstruct
Monday: 45 minutes of sales on a new lead (unbillable, still real). Kickoff call on Client A. Two hours of discovery notes — no commit.
Tuesday: four hours of implementation on Client A, one hour of review on Client B’s PR in their org, thirty minutes of CI because a flaky test blocked deploy.
Wednesday: context switch tax. You touched three clients before noon. GitHub shows one repo. Your bank account cares about all three.
A log of pushes cannot allocate that week. A client → project → task tree can, if you actually start and stop on the task you were in.
Is code review billable if you didn’t push?
Often yes — if the contract says so. Review is work. So is writing a reproduction, sitting on a war room call, and explaining a tradeoff in a doc nobody will commit. So is waiting on CI when the client asked you to own the release.
The mistake is using “I didn’t commit” as a proxy for “I didn’t work.” The opposite mistake is dumping every Slack glance onto a client because you had the repo open. You need a place for internal/admin/sales so the client tasks stay honest. Billable vs non-billable only works when both exist as first-class buckets, not as a feeling at invoice time.
If you round time, round the timesheet, not the git activity. Six-minute (0.1 hour) rounding is a billing conversation. It is not something `git shortlog` can invent for you. See how time rounding is supposed to work if you bill in tenths.
What about “I can just export from GitHub”?
You can export events. You still have to map them onto clients. That mapping is the job. Scripts that guess the client from the remote URL fail the first time you commit to a shared OSS dependency, a fork, or a client’s org under a nickname.
Passive tools that watch applications try to skip the mapping. They are a different category. They can tell you that you were in a terminal. They cannot tell you whether that terminal hour was Client A’s production fire or your own product. Consultants who invoice from app usage spend the weekend reconstructing intent. Consultants who track on tasks spend Friday generating a report.
How do you capture the hour that never became a commit?
Start the task when the work starts — including meetings and review — and leave a note when the work was messy. If you forget, log it the same day in language you will still understand in two weeks: “Forgot 30 minutes on yesterday’s standup.” Do not go spelunking through `git log –since` and calling that evidence. The git log is a useful prompt for your memory. It is not the record.
That is the last twenty percent of this advice, and it is where a purpose-built tracker earns its keep. MinuteShark is built for that client → project → task (and subtask) tree, not as a GitHub companion app. There is no native GitHub sync to promise you, and we will not pretend commits flow into invoices. You track on the task. You generate a report by what/who/when. You invoice from that report.
If you want less clicking after a long stretch of flow, MinuteShark AI can propose a time entry in plain English — “Log 1 hour on Homepage mockups for today” — and you confirm a card before anything is written. Forgotten time is a first-class utterance, not a git archaeology project. Search on the dashboard still starts a timer when you would rather press play than chat. None of that requires your repo to be connected.
Use GitHub for the code. Use a timesheet for the hour. The freelance developers who stay solvent are the ones who stop asking a contribution graph to do billing.