Skip to content

Return an empty Log() on a repository with no commits yet [patch] - #236

Merged
matt-edmondson merged 2 commits into
mainfrom
fix/233-log-unborn-head
Oct 20, 2026
Merged

matt-edmondson merged 2 commits into
mainfrom
fix/233-log-unborn-head

Conversation

@matt-edmondson

Copy link
Copy Markdown
Contributor

Fixes #233

Problem

On a freshly initialised repository (unborn HEAD), git log exits 128. Whether Log() threw or returned an empty list depended only on which options the caller chose:

Call Before After
Log() throws (does not have any commits yet) empty list
Log().ForPath(p) throws empty list
Log().ExcludingRemoteTrackingRefs() throws (unknown revision 'HEAD') empty list
Log().IncludingAllRefs() empty list empty list
Log().ForRevision("does-not-exist") throws still throws

Change

GitLogBuilder now overrides ExecuteAsync and TryExecuteAsync. When git log fails and the caller named no revision (and did not ask for IncludingAllRefs, which already succeeds), it probes git rev-parse --verify -q HEAD:

  • Exit 1, meaning HEAD does not resolve, is read as unborn, and the result is an empty list.
  • Anything else, such as exit 128 for "not a git repository", rethrows the original GitCommandException or returns the original failed result.

The probe runs only after log has already failed, so a normal Log() still costs one git invocation. I used a probe instead of matching error text, because the two failures carry different messages. This follows the triage note.

Tests

  • New integration test LogReturnsAnEmptyListBeforeTheFirstCommitAsync: on an Init()-only repository, Log(), Log().ForPath(...), Log().ExcludingRemoteTrackingRefs() and Log().IncludingAllRefs() all return an empty list, and TryExecuteAsync succeeds.
  • New integration test LogStillRefusesAnUnknownRevisionBeforeTheFirstCommitAsync: ForRevision("does-not-exist") still throws GitCommandException and still fails through TryExecuteAsync.

With the builder change reverted, the first test fails. With it in place, the full suite passes: 885 tests, 0 failed (dotnet test, git 2.43).


Generated by Claude Code

On an unborn HEAD, git log exits 128 ("does not have any commits yet", or
"unknown revision 'HEAD'" once ExcludingRemoteTrackingRefs names HEAD), while
IncludingAllRefs on the same repository exits 0 with no output. So Log()
returned an empty list or threw depending only on the options chosen.

When log fails and the caller named no revision of their own, Log() now probes
`rev-parse --verify -q HEAD`. Exit 1 (HEAD does not resolve) means unborn, and
the result is an empty list. Any other failure, and any explicit ForRevision,
still throws as before. The probe runs only after a failure, so the common
case still costs one invocation.

Fixes #233

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_018CRjG9vX7hK9TShFL3iJh3
Resolve GitRoundTripTests.cs: main added RevParse tag-peeling tests at the
same spot as this branch's unborn-HEAD Log tests; keep both.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MBvWhCTdazHGpnqRd3FD7s
@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Log() throws GitCommandException on a repository with no commits yet instead of returning an empty list

2 participants