Frank Ray

Software expert witness for IT and software development disputes.

  • Welcome
  • Expert Witness
  • Fees and Charges
  • Resources
  • Handbook
  • Writing
  • Blog
  • About
  • Contact

Reading Git Commit History as Forensic Evidence

How expert witnesses read git commit history as forensic evidence in supplier delivery disputes: cadence, message quality, author distribution, history integrity, and reporting under CPR Part 35.

Every commit is a small witness statement. Timestamped, attributed, signed with a diff. Nobody wrote it that way. Every one of them has that shape.

Version control history is one of the most underused sources of forensic evidence in software delivery disputes. It’s contemporaneous, machine-generated, and, kept in the way real projects keep repositories, hard to fabricate cleanly after the fact. It tells a story no witness statement written months after the event can tell without the risk of reconstruction.

This guide documents how I read a supplier’s git repository when instructed on a delivery dispute. The frame is deliberate. The same craft applies across cases where the question is whether one codebase was copied from another, and across cases where a departing employee is alleged to have taken code with them. I’ve written about the copying frame separately in source-code examination in IP disputes. This piece stays with the delivery-dispute frame: what the supplier actually did, when, and with what quality. It’s the most common shape of dispute in my instructions, and the one where the commit history’s evidential weight is most often misunderstood. The broader methodology for these cases is set out in failed software project assessment; this piece is a deep dive on one evidential thread within it.

It’s written for both audiences: solicitors and litigation teams who need to understand what a rigorous examination of commit history involves, and technical practitioners looking for a structured approach to something they mostly do by instinct.


What a Commit Records

A commit in a git repository is a small, structured record. It carries five pieces of information that, taken together, give it its evidential weight:

  • The author. The name and email as configured on the developer’s machine at the time of the commit.
  • The timestamp. When the commit was made, as recorded by the machine that made it.
  • The message. A human-written note describing what was changed and often why.
  • The parent commit. The commit that preceded this one, forming a chain back to the very first commit.
  • The diff. The exact lines added and removed, computable from the parent-child relationship.

Individually, none of these is uniquely powerful. Machine timestamps can be manipulated. Names and emails can be spoofed. Commit messages can be terse or absent. But the combination is unusually resistant to reconstruction.

Every commit’s identity is a cryptographic hash of the whole record: the diff, the parent hash, the author, the timestamp, the message, all of it. Change any one and the hash changes, which changes every downstream commit’s hash. A repository is, in effect, a signed chain of assertions, each one dependent on the ones before it. You can’t cleanly rewrite a single commit deep in the history without leaving traces everywhere later.

That’s what makes a git repository more than a snapshot of what was delivered. It’s a machine-generated record of how the delivery was assembled, over what period, by whom, and against what earlier state. It’s a record the parties often didn’t create for evidential purposes, and one that hasn’t therefore been polished for a court.


What to Preserve Now

Before an expert is engaged, the solicitor’s most useful contribution is often preservation of evidence that degrades in normal operation. The items below age out on schedules shorter than most litigation timelines, often through routine IT processes rather than deliberate destruction. Captured early, they materially expand what an eventual examination can find.

  • A full git repository export, including history. Not a ZIP of current files, not a tarball of HEAD. A repository contains history; an archive of the same files doesn’t.
  • SHA-256 hashes and timestamps of every artefact at the moment of capture, with a written note of who captured it, on what machine, at what date and time.
  • Access logs for the source control system covering the relevant window. GitHub, GitLab, Bitbucket, and Azure DevOps retain these on different schedules; many retention windows are shorter than litigation timelines.
  • Mailbox contents for the developers most closely involved in the disputed delivery, before mailboxes are archived and holders move on.
  • Forensic images of relevant work devices before they are reissued, wiped, or returned to leasing.
  • DLP and USB transfer reports for the relevant window, where such tooling was in place.

Preservation is cheap when done early and impossible when done late.


Reading Patterns

There’s no single signal in a commit history that decides a delivery dispute. Instead, there’s a series of readable patterns. Each one alone is suggestive; several together are corroborating. What I’m doing when I read a supplier’s repository isn’t looking for a smoking gun. It’s building a picture of how the work was actually done, and comparing that picture against what the contract, the invoices, and the correspondence assert.

Cadence

Real development leaves a particular kind of trace. Commits are frequent and incremental. Small changes accumulate. Days without commits are unremarkable; weeks without them are worth asking about. What I find telling in a delivery dispute isn’t steady work, which is what I hope to see, but the bursty pre-milestone dump: a repository silent for six weeks and then, in the two days before an invoice date, a hundred commits that arrive together. That pattern shows me the supplier was building for the milestone rather than delivering against a plan.

Message Quality

Commit messages are the developer’s own contemporaneous note of what they were doing and why. Professional teams write them with care because the whole team reads them: “Add validation for empty postcode field”, “Fix off-by-one in retry loop”, “Refactor invoice adapter to handle backdated adjustments”. When I see one-word messages, or . alone, or blank messages, or the pattern “wip” followed by “wip 2” followed by “wip 3”, I read it as a signal about the standard of the practice, not the character of the developer. Teams under pressure to hit milestones without being reviewed produce messages of exactly this shape.

Author Distribution

A supplier’s proposal usually names the people who will do the work. The commit history shows me who actually did it. If the proposal named a lead engineer and two mids and the repository shows a single junior committing most of the code, with the seniors making occasional cosmetic changes and no design contributions, that’s a delivery reality worth surfacing. A sudden change of author distribution around a milestone (a new name appearing, doing the bulk, and disappearing) is worth understanding before drawing conclusions.

Traceability

In a well-run team, most commits reference something outside themselves: a ticket ID, a story number, a pull request that carries the review. Where that trace exists across the repository, it corroborates independently — the ticket exists in a separate system, with its own timestamps and its own participants. Where the trace doesn’t exist, the commits float. Commits that float aren’t, by themselves, evidence of anything. They’re less corroborable than commits that don’t.

History Integrity

Git allows history to be rewritten. amend, rebase, and push --force can retroactively change what a commit says or when it says it was made. In a normal, healthy repository these operations are used sparingly and locally, before a change is shared with the team. I look for their fingerprints across shared branches: commits whose author-timestamp and committer-timestamp differ suspiciously, force-pushes visible in access logs, branches whose history changed shape between one capture and the next. When I find them near the disputed period, I say so, and I explain what they can and can’t mean.

Working-Hours Patterns

Timestamps carry the developer’s local hour of work. A supplier’s team based nominally in London that commits consistently at 03:00 GMT isn’t necessarily doing anything wrong. Offshoring is legal and often disclosed. But if the contract represented the work as UK-based and the pattern is entirely otherwise, that’s a fact for the case. Out-of-hours reactive work concentrated around missed milestones is a signal about the state of the delivery, not about the individual developer.

Feature-to-Fix Ratio

Every mature codebase carries fixes as well as features. Bugs are found, root causes are traced, corrections are committed. When I see a repository with an unusually low ratio of fix commits to feature commits during periods where the supplier had gone live and users were exercising the system, I want to understand why. Either the software was unusually clean (possible, and I’ve seen it), or bugs were being handled outside the repository, without traceability. The latter is common, and it’s a quality-of-practice finding worth naming.


The Honest Limits

The methodology above assumes the repository can be read as a text about the delivery. It usually can. But there are limits that must be named plainly, because a report that overclaims from a commit history won’t survive cross-examination.

Timestamps are claims, not facts. A commit’s timestamp is whatever the machine that made it recorded. A developer with local access can, technically, set their system clock to any value and make commits that appear to come from a different day. In normal working conditions, nobody does this. But in a disputed delivery, the possibility is real and can’t be assumed away. When timestamps matter, I look for independent corroboration: CI pipeline logs (the automated build-and-deploy records that run on every push), deployment records, ticket timestamps in a separate system, hosting-provider audit logs. A single-source timestamp is a lead, not a finding.

Absence is ambiguous. A repository that doesn’t show a particular kind of work doesn’t, by itself, prove that the work wasn’t done. Bugs may have been fixed outside version control, in a hotfix branch that was never merged, or in a separate repository. What I can say from an absence is that the record I’d expect to see isn’t there; what the absence means requires the fuller picture, and often other evidence.

Retention windows are shorter than people think. Access logs and audit trails on hosted providers age out on schedules the parties often don’t know without asking. GitHub retains a subset of activity for defined windows; other providers do the same in their own terms. What can be captured now, if the solicitor asks now, is a different question from what could have been captured six months ago.

And obtaining the history is often contested. A supplier who hasn’t produced their repository voluntarily won’t always produce it under standard disclosure. Whether the history is discoverable is a matter for the solicitors and, ultimately, the court; my point is only that it’s prudent to expect resistance and to factor it into the strategy. A repository that can’t be obtained can’t be examined. What an examination might have shown, if the history had been available, isn’t the same as what was actually found.


In the Report

A finding from commit history sits in a Part 35 report the same way any technical finding does: method first, finding second. The reader needs to see how I looked before they can weigh what I found. Which commits, hashes and lines of history were examined. What the pattern looks like. What the pattern is consistent with, and what it isn’t. What the alternative explanations are, and why I set them aside. That’s the sequence.

Where a finding rests on a single source, I say so plainly. Where it’s corroborated by other evidence (the CI pipeline, the ticket system, the hosting-provider audit trail), I say so. The reader should be able to see the load-bearing points and know which of them would fall if the underlying assumption failed.

The duty is to the court, per the Ikarian Reefer principles and CPR Part 35, and it’s felt in every paragraph.


In the Letter of Instruction

A Letter of Instruction to a source-code expert in a delivery dispute lives or dies by its specificity. Vague questions produce vague reports; vague reports don’t survive cross-examination. Practice Direction 35 requires written instructions to the expert, and the questions in those instructions are what scope the report.

The strongest LOIs ask the expert to apply a named methodology to a specified artefact set and to state the result objectively. They don’t ask the expert to reach a conclusion the solicitor would prefer, and they don’t ask the expert to opine on liability or fault; those are the court’s questions, not the expert’s. Some example framings drawn from delivery disputes:

  • “Examine the repository at commit hash [X] and report on the cadence, message quality, author distribution, and traceability of commits between [date range]. State whether the pattern is consistent with the supplier’s described working practice.”
  • “Compare the commit activity across the disputed milestone period against the pattern before it. Identify any change in cadence, author distribution, or history operations, and state whether the change is consistent with normal development.”
  • “Trace the introduction of [feature Y] through the repository history. Identify the commits that introduced it, their authors and timestamps, and any subsequent modifications. State what the trace shows about when and by whom the feature was delivered.”
  • “Assess whether the commit history shows evidence of fixes to defects during [period]. Identify the ratio of fix commits to feature commits, and state whether the pattern is consistent with an actively-supported live system.”

Each specifies an artefact set, a methodology to apply, and a form of answer. If the framing is unclear, the expert can help draft it; that collaboration is permitted under the Rules and produces better instructions than guessing.

On this page

What a Commit RecordsWhat to Preserve NowReading Patterns The Honest LimitsIn the ReportIn the Letter of Instruction

Facing a software or IT dispute?

A confidential, no-obligation discussion, at any stage from pre-action assessment to trial.

info@bettersoftware.uk 0786 8349 426 (UK)

Practice

  • Expert Witness
  • Fees and Charges
  • Resources
  • Contact

Background

  • About
  • Handbook
  • Writing
  • Blog

Software expert witness services. © 2026 Frank Ray