test(git): stop two empty commits in the divergence fixture from hashing alike

`counts drift in both directions` builds 100 empty commits, resets to the fork
point, then adds one more — expecting 100 ahead + 1 behind to clear the cap of
100. An empty commit's hash covers only parent, tree, message and a
one-second-granularity timestamp, and every commit in the fixture reuses
`commit ${index}` starting from 0. On a runner fast enough to finish the whole
build inside one wall-clock second (CI: 1059ms for the case, ~7ms per commit),
the post-reset `commit 0` hashed identically to the first `commit 0` of the
chain, so Git handed back that same object and left the branch 99/0 apart
instead of 100/1 — `within`, not `exceeded`.

Numbering the empty commits across calls makes the fixture build the 101
distinct commits it already claimed to. Reproduced deterministically by pinning
GIT_AUTHOR_DATE/GIT_COMMITTER_DATE, which forces the timestamp collision the
fast runner hits by chance: fails with the exact CI assertion before, passes
after.
This commit is contained in:
Neil
2026-09-02 03:42:10 -07:00
parent e3411152bc
commit a55aedcbe9
@@ -32,9 +32,17 @@ async function createRepo(): Promise<string> {
return repoPath
}
// Why unique across calls: an empty commit's hash covers only parent, tree, message and a
// one-second-granularity timestamp. On a fast runner the whole 100-commit build finishes inside
// one second, so a post-reset `commit 0` off the same fork point hashed identically to the first
// `commit 0` of the chain and Git handed back that same object — leaving the branch 99/0 apart
// instead of 100/1.
let emptyCommitSequence = 0
function commitEmpty(repoPath: string, count: number): void {
for (let index = 0; index < count; index += 1) {
git(repoPath, ['commit', '--quiet', '--allow-empty', '-m', `commit ${index}`])
emptyCommitSequence += 1
git(repoPath, ['commit', '--quiet', '--allow-empty', '-m', `commit ${emptyCommitSequence}`])
}
}