Skip to content

fix: harden hermes update against diverged history, non-main branches, and gateway edge cases (salvage #3489)#3492

Merged
teknium1 merged 2 commits intomainfrom
hermes/hermes-03f7719f
Mar 28, 2026
Merged

fix: harden hermes update against diverged history, non-main branches, and gateway edge cases (salvage #3489)#3492
teknium1 merged 2 commits intomainfrom
hermes/hermes-03f7719f

Conversation

@teknium1
Copy link
Copy Markdown
Contributor

Summary

Salvage of #3489 by @kshitijk4poor with a bug fix on top.

Hardens hermes update (CLI) and /update (gateway) for six edge cases:

# Edge Case Before After
1 Diverged history (upstream force-push) --ff-only throws raw traceback Falls back to git reset --hard origin/main
2 User on a feature branch Silently clobbers feature branch Auto-checkouts main first with warning
3 Detached HEAD Confusing fallback behavior Explicit warning + checkout main
4 Network/auth failure during fetch Cryptic subprocess error User-friendly messages with hints
5 reset --hard failure (disk full) Attempts stash restore on broken tree Skips restore, prints manual instructions
6 Gateway /update stash conflicts sys.exit(1) kills entire update Non-fatal — update succeeds, warns about changes

Fix on top of original PR

The original PR moved stash creation before the commit-count check (needed for branch-switching), but the "already up to date" early return didn't restore the stash or switch back to the original branch — leaving users stranded on main with changes in a dangling stash. Fixed by restoring stash and checking out the original branch on early return.

Tests

  • 25 tests in test_update_autostash.py (9 new including the early-return fix)
  • 10 tests in test_update_gateway_restart.py
kshitijk4poor and others added 2 commits March 27, 2026 23:10
…es, and gateway edge cases

The self-update command (`hermes update` / gateway `/update`) could fail
or silently corrupt state in several scenarios:

1. **Diverged history** — `git pull --ff-only` aborts with a cryptic
   subprocess error when upstream has force-pushed or rebased. Now falls
   back to `git reset --hard origin/main` since local changes are already
   stashed.

2. **User on a feature branch / detached HEAD** — the old code would
   either clobber the feature branch HEAD to point at origin/main, or
   silently pull against a non-existent remote branch. Now auto-checkouts
   main before pulling, with a clear warning.

3. **Fetch failures** — network or auth errors produced raw subprocess
   tracebacks. Now shows user-friendly messages ("Network error",
   "Authentication failed") with actionable hints.

4. **reset --hard failure** — if the fallback reset itself fails (disk
   full, permissions), the old code would still attempt stash restore on
   a broken working tree. Now skips restore and tells the user their
   changes are safe in stash.

5. **Gateway /update stash conflicts** — non-interactive mode (Telegram
   `/update`) called sys.exit(1) when stash restore had conflicts, making
   the entire update report as failed even though the code update itself
   succeeded. Now treats stash conflicts as non-fatal in non-interactive
   mode (returns False instead of exiting).
The PR moved stash creation before the commit-count check (needed for
the branch-switching feature), but the 'already up to date' early return
didn't restore the stash or switch back to the original branch — leaving
the user stranded on main with changes trapped in a stash.

Now the early-return path restores the stash and checks out the original
branch when applicable.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

2 participants