FinderGit 0.25.0
FinderGit 0.25.0 — when GitHub is the problem, FinderGit says so
Highlights
Know whether it's you or GitHub. When GitHub is having a bad day, every symptom you see looks like FinderGit's fault: a fetch that crawls, a repository column that comes up empty, a dashboard that won't finish loading. The Overview now carries a GitHub connection panel that answers it — how quickly your own requests are actually coming back, and whether GitHub is reporting trouble with the four services FinderGit depends on: Git operations, API requests, Issues and Pull Requests. When there's an open incident, its name and the latest official update appear right there, with a link to the full story.
Only those four, deliberately. An outage of something FinderGit never touches isn't news, and a warning that fires on everything is one you learn to ignore.
It never tells you GitHub is fine when it can't check. If the status page can't be reached, or a service can't be read, that shows as Unknown rather than a reassuring green. And a slowdown nobody has announced yet still shows up, because your own requests are the first thing to know about it — the more useful half, since a status page can only report what somebody chose to declare.
See how long an action has been running. Past three seconds, a running Fetch, Pull or Push shows its elapsed time on the button. A spinner tells you something is happening; it doesn't tell you whether the thing is working or wedged, and only the second question matters when a remote is answering slowly.
Bug fixes
A slow remote could leave a repository's actions unusable for five minutes. Every action on a repository is disabled while one is running, and the time limit for a Fetch, Pull or Push was the one meant for a Git process wedged on your own machine. It's now far shorter for anything that talks to a server, while a first clone — which legitimately takes minutes on a large repository — keeps its own, longer allowance.
Opening the Overview with many repositories could bog the whole app down. Every repository asked "is GitHub reachable?" at the same moment, and none of them saw that the others were already asking, so the check ran once per repository instead of once. On a large workspace with a slow connection that was dozens of simultaneous checks. Now they share a single answer.
A rejected token would have read as GitHub being down. Caught before release: if your access token was revoked or lost its permissions, every request failed — and the new panel counted those as GitHub's failures, telling you "Your GitHub requests are failing" when the problem was your credential. A request that was refused is now kept separate from a request the server couldn't answer, so the dashboard points at the right place.
The Issues, PRs and Stars columns emptied silently when GitHub was unreachable — using the same blank cell that means "this repository isn't on GitHub". The columns still go quiet, but the Overview now says why.
Under the hood
- The status source reads
components.jsonandincidents/unresolved.jsonunconditionally and in parallel. The obvious design — check the top-level indicator first, fetch the incident only if it's non-none— silently drops live incidents: measured on 2026-08-05,status.jsonreportedindicator: "none"while an unresolved incident was open and every component still readoperational. The three endpoints are peers, not a hierarchy. - Components are matched on Statuspage's stable
idwith the display name as fallback, so a rename can't quietly drop one we depend on. An unrecognised status string, an unreachable page, or a component missing from the response all resolve tounknown— ordered belowoperationalso it can never win a severity comparison, and tinted grey distinctly from green. - Incidents that carry no component attribution are diagnostic-only: they can explain a call that actually failed, but they never raise a banner. GitHub declares these regularly, and one measured example was "Incident With Blocked GitHub.com Traffic" — precisely the class that breaks a desktop client while the dashboard stays green.
- The first-party signal leads because the published one has a hole: GitHub declared no incident at all on 2026-08-04, the day this was prompted by. The incident history spans 06-04 to 08-05 with entries either side and nothing in between.
- Time limits are now split by what a command is waiting on: 120s for fetch/pull/push, 900s for a clone, 300s for local plumbing. The
gh-backed clone path had been capped at the 120s meant for metadata queries, so a large repository could clone fine one way and fail the other. - The GitHub REST/GraphQL path gets a dedicated
URLSessionwith a 10s inactivity limit and a 30s hard ceiling, replacingURLSession.shared's default — whose 60s is an inactivity timeout, not a wall-clock cap, so a response trickling bytes had no ceiling at all. - Provider resolution is collapsed through a single-flight actor. Swift actors are reentrant across
await, so a TTL cache whose timestamp is written after the probe returns doesn't dedupe anything: every caller arriving during the probe reads the same empty cache and starts its own. - Request timings are recorded in the gateway rather than in each provider, so the CLI and token paths are measured identically and the dashboard can name which one produced the numbers. Git transfers are deliberately excluded — folding a multi-megabyte clone into the same median would blur "the API is slow" into "that pull was big".
- Failures are classified by what they say about the forge rather than by whether they happened. A 4xx means the request was refused — no permission, not found, rate-limited — and says nothing about GitHub's health; a 5xx or a timeout does. Cancellations and decode errors are ours. Only the second group reaches the verdict.
- The status response is streamed with a declared-size refusal before the first byte and an absolute ceiling for a chunked or mis-declared body. A time budget bounds how long a third party can hold you, not how much it can make you allocate.
- The new panel and its four component descriptions are localized into Italian, French, German and Spanish, plural agreement included.
Install
Download the DMG below, drag FinderGit to Applications, and launch it. The app is signed with a Developer ID and notarized by Apple, so no Gatekeeper bypass is needed. Existing installations update themselves.
Requirements
macOS 15 or later. Universal binary (Apple Silicon and Intel).
Verify this download
Compare the checksum of the file you downloaded:
shasum -a 256 FinderGit-0.25.0.dmg
It must print exactly:
82262d97887201254f942db932caa2401fa04c1f16775d1b0ea6c1d528851717
The DMG is also signed with an Apple Developer ID and notarized by Apple, which you can confirm without installing it:
spctl -a -vv -t open --context context:primary-signature FinderGit-0.25.0.dmg
That reports source=Notarized Developer ID for a genuine build.