Skip to content

fix(worktree): deepen shallow clones so worktree cleanup can verify push state - #86912

Merged
teknium1 merged 1 commit into
mainfrom
hermes/hermes-5e9a5669
Aug 15, 2026
Merged

fix(worktree): deepen shallow clones so worktree cleanup can verify push state#86912
teknium1 merged 1 commit into
mainfrom
hermes/hermes-5e9a5669

Conversation

@teknium1

Copy link
Copy Markdown
Contributor

Summary

Worktrees created by hermes -w on a default install are never cleaned up: the installer's --depth 1 shallow clone disconnects older worktree HEADs from current origin/main, so git log HEAD --not --remotes misreports thousands of already-public commits as "unpushed" and the fail-safe guard preserves every aged worktree forever. This PR makes the startup pruner deepen the clone once (bloblessly), after which the verdicts are correct and the accumulated backlog self-clears on the next hermes -w startup.

Real incident: 21 of 25 hermes-* worktrees stuck on one install, each kept with a misleading "has unpushed commits" message at session close. The git cherry squash-merge escape hatch can't rescue them either — a shallow-disconnected tree reports ~22k commits "ahead", far past max_ahead=20.

Changes

  • cli.py: new _repo_is_shallow() + _deepen_shallow_repo() — one-time git fetch --unshallow --filter=blob:none (plain --unshallow fallback), invoked from the background startup pruner thread before classification. Fail-soft: offline/no-remote keeps today's preserve-everything behavior.
  • cli.py _cleanup_worktree(): when the unpushed verdict comes from a shallow clone, print "Shallow clone — cannot verify push state" (with a pointer to the auto-deepen) instead of the false "has unpushed commits".
  • cli.py _worktree_has_unpushed_commits(): documents the shallow caveat; the primitive intentionally stays conservative.
  • tests/cli/test_worktree.py: TestShallowCloneDeepening — real shallow clone over file:// reproducing the disconnect shape.

Validation

Check Result
tests/cli/test_worktree.py 50/50 pass (43 existing + 7 new)
Sabotage run (deepen call disabled) E2E test fails as expected
False-unpushed repro test asserts the fixture still exercises the bug
Genuine unpushed work after deepen preserved
Offline deepen failure fail-soft, tree preserved
ruff check clean

Infographic

Omitted this once with maintainer approval — FAL image generation unavailable (billing balance exhausted at PR time).

…ush state

The installer clones with --depth 1, so every default install is shallow.
In a shallow repo, an older worktree HEAD (a past snapshot of main) is
disconnected from current origin/main by the shallow boundary, so
'git log HEAD --not --remotes' misreports thousands of already-public
commits as unpushed. The fail-safe unpushed guard then preserves every
aged 'hermes -w' worktree forever, and the git-cherry squash-merge
escape hatch never rescues them (22k 'ahead' >> max_ahead=20).
Real incident: 21 of 25 hermes-* worktrees stuck on one install.

Fix at the root, one owner:
- _deepen_shallow_repo(): one-time blobless unshallow
  (fetch --unshallow --filter=blob:none; plain --unshallow fallback)
  run from the background startup pruner thread before classification,
  so history verdicts become correct and the backlog self-clears on the
  next 'hermes -w' startup. Fail-soft offline: keep preserving.
- _cleanup_worktree(): when the unpushed verdict comes from a shallow
  clone, say 'Shallow clone — cannot verify push state' instead of the
  misleading 'has unpushed commits' message.
- Document the shallow caveat on _worktree_has_unpushed_commits (the
  primitive stays conservative on purpose).

Tests: real shallow clone over file:// reproducing the disconnect shape,
covering detection, deepen+verdict flip, pruner E2E reap, offline
fail-soft preserve, full-clone noop, and genuine-unpushed-work survival.
Sabotage-verified: the E2E test fails with the deepen call disabled.
@github-actions

github-actions Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

૮ >ﻌ< ა ci review

ran on ee51e70 — fix(worktree): deepen shallow clones so worktree cleanup can

⚠️ Warnings

OSV vulnerability scan · View job

5 known vulnerabilities found in pinned dependencies.

How to fix:

Review the findings in the Security tab. Update the affected dependencies if a patched version is available.


debug info

CI timings

CI timings · View report · View job

Wall time 4m1s vs 3m35s (+12.1%). 8 job(s) slower, 14 faster, 2 unchanged.

  • Python tests / Run tests slice 11/12: +48.0s
  • Detect affected areas: +31.0s
  • Python tests / Run tests slice 2/12: -25.0s
  • Python tests / Run tests slice 4/12: -15.0s
  • OS-specific tests / macOS-only tests: -15.0s

@alt-glitch alt-glitch added type/bug Something isn't working comp/cli CLI entry point, hermes_cli/, setup wizard P2 Medium — degraded but workaround exists sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades labels Aug 15, 2026
@teknium1
teknium1 merged commit bfd9cef into main Aug 15, 2026
48 checks passed
@teknium1
teknium1 deleted the hermes/hermes-5e9a5669 branch August 15, 2026 11:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/cli CLI entry point, hermes_cli/, setup wizard P2 Medium — degraded but workaround exists sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants