can1357/oh-my-pi · error · Error
Not a git repository
Error message
Not a git repository
What it means
GitTuiState.refresh polls repository status via statusPorcelain; if that call fails (caught to null) it treats the directory as no longer being a valid git repository and throws. This guards the state machine against operating on a repo that disappeared mid-session (e.g. .git removed) — the TUI data can no longer be trusted.
Source
Thrown at packages/coding-agent/src/cli/git-tui/state.ts:336
get clean(): boolean {
return this.unstaged.length === 0 && this.staged.length === 0;
}
/** Re-read fast repository state; expensive numstats load separately. */
async refresh(): Promise<boolean> {
if (this.pinnedSha) {
if (this.#fingerprint === this.pinnedSha) return false;
this.#fingerprint = this.pinnedSha;
this.#headFilesLoad = null;
this.headCommit = await this.#loadHeadMetadata(this.pinnedSha);
return true;
}
const [statusText, branchName, headSha] = await Promise.all([
this.#repo.statusPorcelain({ nulTerminated: true, untracked: "all" }).catch(() => null),
this.#repo.currentBranch(),
this.#repo.headSha(),
]);
if (statusText === null) throw new Error("Not a git repository");
const fingerprint = `${headSha ?? ""}\u0000${statusText}`;
if (fingerprint === this.#fingerprint) {
this.branch = branchName ?? null;
return false;
}
this.#fingerprint = fingerprint;
this.#statusStatsLoad = null;
this.branch = branchName ?? null;
this.#setChanges(statusText);
if ((headSha ?? null) !== this.headCommit?.sha) {
this.#headFilesLoad = null;
this.headCommit = headSha ? await this.#loadHeadMetadata(headSha) : null;
}
return true;
}
/** Populate changed-line counts after the file list is already interactive. */
async loadChangeStats(): Promise<boolean> {View on GitHub (pinned to 9690622007)
Solutions
- Close and reopen the git TUI from a valid repository.
- Restore the .git directory (undo deletion) or re-clone the repository.
- Run `git status` manually to confirm the repository is healthy.
Example fix
// before
state.refresh(); // throws if repo vanished
// after
try { await state.refresh(); } catch { closeGitTui(); } Defensive patterns
Strategy: try-catch
Validate before calling
import { $ } from "bun";
const ok = await $`git -C ${repoRoot} status --porcelain`.quiet().nothrow();
if (ok.exitCode !== 0) teardownGitTui(); // repo is gone/corrupt Try / catch
try {
await state.refresh();
} catch (e) {
if (e instanceof Error && e.message === "Not a git repository") {
ui.hide(gitOverlay); // repo vanished mid-session
return;
}
throw e;
} Prevention
- Don't delete/move .git while the git TUI is open.
- Wrap periodic refresh calls so failures close the overlay gracefully.
- Verify repository health with `git status` before long-running TUI sessions.
When it happens
Trigger: Calling refresh (directly or via create/loadStagedContents) on a state whose repo's statusPorcelain fails — .git directory deleted while the TUI is open, repo corrupted, or git binary failing.
Common situations: Deleting or moving the .git directory while the git TUI is open, checking out into a broken worktree, or disk/filesystem errors making git status fail.
Related errors
- directory stack is empty
- not a repository: {path}
- reference not found: {name}
- object not found: {spec}
- cherry-pick of {sha} is empty
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/c38f89aca45e0bbd.
Report an issue: GitHub.