Multi-repo time tracking means mapping each git repository to a client or project upfront, then aggregating commits across all repos into a single dashboard. Set this up once and every future commit lands in the right bucket automatically.
When invoice day arrives, most developers are manually scrolling through half a dozen git logs trying to remember which hours went to which client. The root cause is almost always the same: time tracking was set up for one repository and never extended to the rest. This guide covers the specific challenges of polyrepo and monorepo architectures, five mapping strategies that prevent misattribution, and how to build a unified view that clients actually trust.
Why is multi-repo time tracking harder than it looks?
Developers rarely work in a single repository all day. A typical day might involve commits to a main application repo, a hotfix in a separate infrastructure repo, and a code review in a shared component library. Manual tracking requires remembering to switch timers every time you change repos. Most people do not.
The git log problem compounds this. Each repository holds its own commit history. There is no native query to pull commits across five repos into a single timeline. Without tooling, aggregation means opening five browser tabs, exporting five logs, and stitching them together in a spreadsheet.
Shared repositories add another layer of ambiguity. A utility library used by three clients generates commits that belong to all three projects in different proportions. Without explicit attribution rules, that time disappears into a catch-all overhead bucket, never reaching a client invoice.
Monorepo vs polyrepo: what are the time tracking implications?
The architecture decision you made for code reasons has direct consequences for how you attribute developer time.
Monorepo: simpler logs, harder attribution
A monorepo holds all code in one repository, typically organised by directory. The commit history lives in one place, which makes aggregation straightforward. The challenge is that a commit to packages/shared-auth could serve three different clients depending on which feature branch it was made on.
The standard approach is branch naming conventions: client-a/feature-xyz tells a time tracking tool exactly who the work belongs to. Combine that with directory-level mapping for shared packages — anything in packages/shared splits across all projects proportionally — and monorepo attribution becomes manageable.
Polyrepo: natural isolation, fragmented logs
Separate repositories per service or client offer the clearest attribution: the acme-checkout repo belongs to Acme, full stop. Tracking your GitHub activity for billable hours works cleanly in a polyrepo because the repository-to-client mapping is often one-to-one.
The cost is aggregation. A developer working across five client repos needs a tool that pulls all five feeds into a single timeline. Without that, the end-of-week view is five separate summaries that someone has to manually consolidate before building an invoice.
Hybrid: the most common real-world architecture
Most agencies and product teams end up with a hybrid: a monorepo for shared infrastructure, separate repos per client or per service. Time spent in the shared repo needs a default allocation rule. The rest maps cleanly to clients by repository.
What are the most effective repository-to-client mapping strategies?
The mapping you set at project kick-off determines whether every future commit lands in the right place automatically or requires manual correction later.
One repo, one client. The simplest case. Configure the mapping once and every commit to that repository bills to that client. There is no ambiguity and no ongoing maintenance. This works for agencies where each engagement has its own codebase.
Grouped repositories per client. A client with a web app, a mobile app, and a backend service has three repositories that all map to the same billing target. Group them under a client label — client-a/web, client-a/mobile, client-a/api — and commits across all three aggregate to a single client total. Per-repo breakdowns remain available when you need to investigate.
Branch-based attribution for shared repos. For repositories that multiple clients touch, use branch naming conventions to route commits. A branch named client-b/feature-authentication tells the tracking tool that this commit belongs to Client B, regardless of which repo it lives in. This is the most powerful approach for monorepo architectures.
Proportional allocation for infrastructure. Some repositories cannot be attributed to a single client — DevOps pipelines, shared testing frameworks, CI configuration. Set a default split across active clients based on their proportional share of total project hours. Revisit the split quarterly as project scope changes.
Tag-based attribution. Commit message conventions like [client-a] or [ACME-123] allow post-hoc attribution without branch restrictions. Developers working in a shared codebase can tag individual commits to specific clients. This works as a fallback when branch conventions are not in place, though it relies on developers remembering to add the tag.
All five strategies assume the mapping is configured somewhere before work begins. Most teams tracking billable hours across multiple projects set this up in a configuration file or admin panel at project start and revisit it only when scope changes.
How do you build a unified multi-repo time dashboard?
Aggregating five separate git feeds into one coherent view requires four things: a data model, a normalisation step, a grouping rule, and access controls.
The data model maps every event — commit, pull request, review, deployment — to three identifiers: developer, repository, and timestamp. That is the minimum. Client and project mappings layer on top.
The normalisation step converts raw git events into time blocks. A commit at 14:32 following a commit at 13:55 from the same developer on the same day represents a working session of roughly 37 minutes. This is the same logic behind reconstructing a timesheet from git commit history, applied across multiple repos simultaneously.
The grouping rule determines what the dashboard groups by. Group by client and project, not by repository. A client does not care whether their work happened in the api repo or the frontend repo. They care about total hours, by date, attributed to which team members.
The access controls ensure that Client A’s data is never visible to Client B, even if both were worked on by the same developer. Export views should be client-scoped by default, not as a manual filter.
A team of ten developers working across twenty repositories has two hundred potential repo-developer combinations. The dashboard has to collapse that to five or six client rows before it is useful for billing.
How do you ensure client isolation in time reporting?
Client isolation is both a data security requirement and a trust issue. Clients with strict confidentiality agreements need assurance that their project data is not visible to other clients, even in aggregate form.
At the repository level, isolation is usually structural: each client’s repos are separate, so the data never mingles in the source. The risk is in the reporting layer. A combined dashboard showing all developers and all clients in one view can accidentally expose data through filtering mistakes.
The safest approach is separate export templates per client. When generating a report for Acme, the export query filters to Acme-mapped repositories and excludes all other client data at the query level — not as a display filter that could be accidentally bypassed.
Audit logs matter too. If a client asks who had access to their time data and when, the answer should come from a system record rather than from memory.
Key Takeaway
Multi-repo time tracking fails when it relies on manual timer switching. Map every repository to a client at project kick-off, aggregate commits automatically, and group the dashboard by client — not by repo.
Frequently Asked Questions
How do I track developer time across multiple git repositories?
Connect your time tracking tool to all your git repositories and configure a repository-to-client mapping for each one. The tool aggregates commit activity across all repos into a unified timeline grouped by client and project. No manual timer switching is needed.
Should I use a monorepo or polyrepo for easier time tracking?
Polyrepos offer natural client isolation — each repository maps cleanly to one project. Monorepos require branch-level or directory-level attribution, which adds setup complexity. Choose based on your architecture requirements. Either approach works well with the right mapping configuration in place.
How do I attribute shared repository time to multiple clients?
Use branch naming conventions where each branch includes a client identifier, such as client-a/feature-name. For repositories where branch conventions are not in place, use a proportional allocation based on each client’s share of total project hours and review it quarterly.
Can I generate client-specific time reports from multi-repo data?
Yes. Aggregate all repository data, apply the client mapping, and export filtered reports that include only the repositories mapped to that client. Filter at the query level rather than as a display-layer toggle, so the data isolation is enforced in the system, not by a user action.
One dashboard for all your repos
Keito connects to all your git repositories and aggregates developer time into a unified client-level dashboard. Map repositories to clients once at project start and every commit lands in the right place automatically. No manual timers.