can1357/oh-my-pi · error · GitCommandError

GitCommandError(["git", *args], proc.returncode, proc.stdout

Error message

GitCommandError(["git", *args], proc.returncode, proc.stdout, proc.stderr)

What it means

A helper building git argument lists (with `user`, `group`, `extra_groups`, `umask` execution options) runs `git *args` and raises `GitCommandError(["git", *args], returncode, stdout, stderr)` on non-zero exit. Like `_check`, it unifies git failures into one exception type carrying the command and redacted output; `rev_parse_head` uses it and its callers (`push`, `push_release`) rely on HEAD resolution succeeding.

Source

Thrown at python/robomp/src/git_ops.py:699

    user: int | None = None,
    group: int | None = None,
    extra_groups: list[int] | tuple[int, ...] | None = None,
    umask: int | None = None,
) -> str:
    """Return the SHA of HEAD or raise GitCommandError."""
    args = ["rev-parse", "HEAD"]
    proc = _run_git(
        args,
        cwd=repo_dir,
        token=None,
        safe_directory=safe_directory,
        user=user,
        group=group,
        extra_groups=extra_groups,
        umask=umask,
    )
    if proc.returncode != 0:
        raise GitCommandError(["git", *args], proc.returncode, proc.stdout, proc.stderr)
    return proc.stdout.strip()


def inspect_dirty_state(
    repo_dir: Path,
    *,
    slot_uid: int | None = None,
    safe_directory: Path | None = None,
) -> DirtyState:
    """Probe the worktree at `repo_dir` for uncommitted/unpushed work.

    Returns a {@link DirtyState}. Errors from the underlying git invocations
    are swallowed — the caller treats "we couldn't tell" as clean so a broken
    git binary can't pin the agent in a reminder loop forever.
    """
    slot_kwargs = _slot_subprocess_kwargs(slot_uid)
    uncommitted = 0
    uncommitted_sample: list[str] = []

View on GitHub (pinned to 9690622007)

Solutions

  1. Confirm repo_dir is a real git worktree with at least one commit
  2. Resolve 'dubious ownership' by adding the repo to git's safe.directory or passing the correct safe_directory option
  3. Call rev_parse_head only after a commit exists (e.g. after commit succeeds, not before the first one)
  4. Inspect the exception's stderr/returncode for git's specific fatal message

Example fix

// before
head = rev_parse_head(new_repo_dir)  # fails: no commits yet
// after
if (new_repo_dir / ".git").exists():
    rev_parse_head(new_repo_dir)  # only after initial commit
head = rev_parse_head(new_repo_dir)
Defensive patterns

Strategy: try-catch

Validate before calling

from pathlib import Path
import subprocess
d = Path(repo_dir)
if not (d / ".git").exists():
    raise ValueError(f"{repo_dir} is not a git repo")
r = subprocess.run(["git", "-C", str(d), "rev-parse", "--verify", "HEAD"], capture_output=True)
if r.returncode != 0:
    raise ValueError("repo has no commits yet (HEAD unborn)")

Type guard

def has_head(repo_dir) -> bool:
    import subprocess
    return subprocess.run(["git", "-C", str(repo_dir), "rev-parse", "--verify", "HEAD"],
                          capture_output=True).returncode == 0

Try / catch

try:
    head = rev_parse_head(repo_dir)
except GitCommandError as exc:
    if "dubious ownership" in (exc.stderr or ""):
        add_safe_directory(repo_dir); head = rev_parse_head(repo_dir)
    else:
        raise

Prevention

When it happens

Trigger: Calling `rev_parse_head(repo_dir, ...)` outside a git repository (fatal: not a git repository), in an empty repo with no commits (unknown revision HEAD), or with a `safe_directory` mismatch making git refuse the repo (dubious ownership).

Common situations: Running the tool against a freshly `git init`ed repo before the first commit, wrong repo_dir path, container bind-mount ownership causing git's safe.directory error.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/3680dc4077218543. Report an issue: GitHub.