Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 27 additions & 20 deletions hermes_cli/banner.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,24 +191,13 @@ def _check_via_rev(local_rev: str) -> Optional[int]:
return 0 if upstream_rev == local_rev else UPDATE_AVAILABLE_NO_COUNT


def _check_via_local_git(repo_dir: Path) -> Optional[int]:
"""Count commits behind origin/main in a local checkout."""
origin_url = _git_stdout(["remote", "get-url", "origin"], cwd=repo_dir)
if _is_official_ssh_remote(origin_url):
head_rev = _git_stdout(["rev-parse", "HEAD"], cwd=repo_dir)
checked = _check_via_rev(head_rev) if head_rev else None
if checked == UPDATE_AVAILABLE_NO_COUNT:
return 1
return checked
def _count_behind_full(repo_dir: Path) -> Optional[int]:
"""Fetch origin and count actual commits-behind via rev-list.

# Installer checkouts are shallow (`git clone --depth 1`). On a shallow
# clone the history stops at a single commit, so a plain `git fetch` would
# unshallow the repo (dragging in the whole history) and
# `rev-list --count HEAD..origin/main` would report a huge bogus "behind"
# number (e.g. "12492 commits behind"). Detect shallow up front: fetch with
# --depth 1 to preserve the boundary and compare tip SHAs instead of
# counting. Full clones (developers, Docker dev images) keep the exact
# count path unchanged. Mirrors the desktop fix in apps/desktop/electron/main.cjs.
Reusable by both the official-SSH path (when _check_via_rev detects
a mismatch but can't distinguish ahead from behind) and the
non-official-remote path below.
"""
shallow = _git_stdout(["rev-parse", "--is-shallow-repository"], cwd=repo_dir)
is_shallow = shallow == "true"

Expand All @@ -226,9 +215,6 @@ def _check_via_local_git(repo_dir: Path) -> Optional[int]:
pass # Offline or timeout — use stale refs, that's fine

if is_shallow:
# No history to count across the shallow boundary. `origin/main` may not
# be a tracking ref in a `clone --depth 1`, so prefer FETCH_HEAD (just
# updated by the fetch above) and fall back to origin/main.
head_rev = _git_stdout(["rev-parse", "HEAD"], cwd=repo_dir)
target_rev = (
_git_stdout(["rev-parse", "FETCH_HEAD"], cwd=repo_dir)
Expand All @@ -251,6 +237,27 @@ def _check_via_local_git(repo_dir: Path) -> Optional[int]:
return None


def _check_via_local_git(repo_dir: Path) -> Optional[int]:
"""Count commits behind origin/main in a local checkout."""
origin_url = _git_stdout(["remote", "get-url", "origin"], cwd=repo_dir)
if _is_official_ssh_remote(origin_url):
head_rev = _git_stdout(["rev-parse", "HEAD"], cwd=repo_dir)
checked = _check_via_rev(head_rev) if head_rev else None
if checked == UPDATE_AVAILABLE_NO_COUNT:
# _check_via_rev only does SHA comparison against upstream HEAD.
# A mismatch can mean EITHER "behind" OR "ahead" (local carry
# commits). Fall through to the full fetch+rev-list path below
# to get an accurate behind count. If that fails, return 1 as
# the conservative fallback (the old behaviour).
behind = _count_behind_full(repo_dir)
if behind is not None:
return behind
return 1
return checked

return _count_behind_full(repo_dir)


def _version_tuple(v: str) -> tuple[int, ...]:
"""Parse '0.13.0' into (0, 13, 0) for comparison. Non-numeric segments become 0."""
parts = []
Expand Down