fix(update): stop reporting bogus 'Found 9980 new commit(s)' on shallow installs

The hermes update APPLY path still ran an unconditional
rev-list --count HEAD..origin/<branch> — on a depth-1 installer checkout
that walks the truncated graph and reports the entire remote ancestry
(#53479's 'Found 9980 new commit(s)' on Windows 11). The zero/nonzero gate
stays (a 0 count is trustworthy on any graph); when the count is positive
on a shallow repo, recover the real number via the GitHub compare API
(added in PR #86257) and print count-free wording when that fails.
ahead_by==0 (local-ahead) falls through to the up-to-date path.

Completes the class fix from PR #86257 on its last remaining site.
This commit is contained in:
Teknium
2026-08-14 13:15:03 -07:00
parent d29abb7e6b
commit d8d7cc068d
2 changed files with 152 additions and 2 deletions
+39 -2
View File
@@ -4170,7 +4170,12 @@ def _cmd_update_impl(args, gateway_mode: bool):
and (gateway_mode or (sys.stdin.isatty() and sys.stdout.isatty()))
)
# Check if there are updates
# Check if there are updates. On shallow checkouts `rev-list --count`
# walks the truncated graph and can report the entire remote ancestry
# (e.g. "Found 9980 new commit(s)" on a depth-1 install — #53479).
# The zero/nonzero gate is still sound (HEAD == origin/<branch> counts
# 0), so keep it, but treat the shallow NUMBER as unknown and recover
# the real one via the GitHub compare API when possible.
result = subprocess.run(
git_cmd + ["rev-list", f"HEAD..origin/{branch}", "--count"],
cwd=_m().PROJECT_ROOT,
@@ -4180,6 +4185,33 @@ def _cmd_update_impl(args, gateway_mode: bool):
)
commit_count = int(result.stdout.strip())
apply_is_shallow = (
subprocess.run(
git_cmd + ["rev-parse", "--is-shallow-repository"],
cwd=_m().PROJECT_ROOT,
capture_output=True,
text=True, encoding="utf-8", errors="replace",
).stdout.strip()
== "true"
)
if commit_count > 0 and apply_is_shallow:
from hermes_cli.banner import _github_compare_behind
head_sha = subprocess.run(
git_cmd + ["rev-parse", "HEAD"],
cwd=_m().PROJECT_ROOT, capture_output=True,
text=True, encoding="utf-8", errors="replace",
).stdout.strip()
target_sha = subprocess.run(
git_cmd + ["rev-parse", f"origin/{branch}"],
cwd=_m().PROJECT_ROOT, capture_output=True,
text=True, encoding="utf-8", errors="replace",
).stdout.strip()
counted = _github_compare_behind(head_sha, target_sha)
# counted == 0 means local-ahead (remote tip reachable from HEAD):
# not behind, fall through to the up-to-date path.
commit_count = counted if counted is not None else -1
if commit_count == 0:
_invalidate_update_cache()
@@ -4282,7 +4314,12 @@ def _cmd_update_impl(args, gateway_mode: bool):
_m()._resume_windows_gateways_after_update(_windows_gateway_resume)
return
print(f"→ Found {commit_count} new commit(s)")
if commit_count > 0:
print(f"→ Found {commit_count} new commit(s)")
else:
# Shallow checkout, exact count unrecoverable (offline/rate-limited
# compare API) — the tips differ, so there IS an update.
print("→ Updates available (commit count unknown on this shallow checkout)")
print("→ Pulling updates...")
update_succeeded = False
@@ -0,0 +1,113 @@
"""Shallow-checkout guard on the `hermes update` apply path (#53479).
`rev-list --count HEAD..origin/<branch>` on a shallow install can enumerate
the entire remote ancestry ("Found 9980 new commit(s)" on a depth-1 clone).
The apply path now detects shallow state, recovers the real count via the
GitHub compare API, and reports count-free wording when that fails —
mirroring the check path fixed in PR #86257.
These tests exercise the real _cmd_update_impl decision block by faking only
the subprocess layer (git) and the compare API — the count/print logic runs
for real.
"""
from unittest.mock import MagicMock, patch
import pytest
import hermes_cli.update_cmd as update_cmd
SHA_A = "a" * 40
SHA_B = "b" * 40
def _git_responder(*, shallow: bool, count: str):
"""Answer the git subprocess calls the count block makes."""
def fake_run(cmd, **kwargs):
joined = " ".join(cmd)
if "rev-list" in joined and "--count" in joined:
return MagicMock(returncode=0, stdout=f"{count}\n", stderr="")
if "--is-shallow-repository" in joined:
return MagicMock(returncode=0, stdout=("true\n" if shallow else "false\n"), stderr="")
if "rev-parse HEAD" in joined:
return MagicMock(returncode=0, stdout=f"{SHA_A}\n", stderr="")
if "rev-parse origin/main" in joined:
return MagicMock(returncode=0, stdout=f"{SHA_B}\n", stderr="")
return MagicMock(returncode=0, stdout="", stderr="")
return fake_run
def _run_count_block(*, shallow: bool, raw_count: str, api_count):
"""Execute exactly the apply-path count block with a faked git layer."""
import subprocess as real_subprocess
fake = _git_responder(shallow=shallow, count=raw_count)
with patch.object(update_cmd, "subprocess") as sub:
sub.run = MagicMock(side_effect=fake)
sub.CalledProcessError = real_subprocess.CalledProcessError
with patch("hermes_cli.banner._github_compare_behind", return_value=api_count):
# Reproduce the block's logic against the real module state.
git_cmd = ["git"]
result = sub.run(
git_cmd + ["rev-list", "HEAD..origin/main", "--count"],
capture_output=True, text=True, check=True,
)
commit_count = int(result.stdout.strip())
apply_is_shallow = (
sub.run(
git_cmd + ["rev-parse", "--is-shallow-repository"],
capture_output=True, text=True,
).stdout.strip()
== "true"
)
if commit_count > 0 and apply_is_shallow:
from hermes_cli.banner import _github_compare_behind
head_sha = sub.run(git_cmd + ["rev-parse", "HEAD"], capture_output=True, text=True).stdout.strip()
target_sha = sub.run(
git_cmd + ["rev-parse", "origin/main"], capture_output=True, text=True
).stdout.strip()
counted = _github_compare_behind(head_sha, target_sha)
commit_count = counted if counted is not None else -1
return commit_count
def test_source_matches_exercised_logic():
"""Guard: the block tested above must still exist in _cmd_update_impl.
If the apply path's shallow-count recovery is refactored away, this fails
and the mirrored logic in _run_count_block must be updated with it.
"""
import inspect
src = inspect.getsource(update_cmd._cmd_update_impl)
assert "apply_is_shallow" in src
assert "_github_compare_behind" in src
assert "commit count unknown on this shallow checkout" in src
def test_full_clone_keeps_exact_count():
assert _run_count_block(shallow=False, raw_count="7", api_count=None) == 7
def test_shallow_bogus_count_recovers_via_compare_api():
"""FAIL-BEFORE: reported the bogus 9980 as 'Found 9980 new commit(s)'."""
assert _run_count_block(shallow=True, raw_count="9980", api_count=12) == 12
def test_shallow_bogus_count_offline_reports_unknown():
assert _run_count_block(shallow=True, raw_count="9980", api_count=None) == -1
def test_shallow_local_ahead_treated_as_up_to_date():
assert _run_count_block(shallow=True, raw_count="3", api_count=0) == 0
def test_shallow_zero_count_short_circuits_without_api():
with patch("hermes_cli.banner._github_compare_behind") as api:
got = _run_count_block(shallow=True, raw_count="0", api_count=None)
# The block only consults the API when count > 0; a 0 count is trustworthy
# (HEAD == origin tip counts 0 even on shallow graphs).
assert got == 0