Skip to content

fix(update): don't reset --hard when local carries unpushed commits, not a rewrite - #93499

Closed
aaramos wants to merge 1 commit into
NousResearch:mainfrom
aaramos:deploy/hermes-update-preserve-local-commits
Closed

aaramos wants to merge 1 commit into
NousResearch:mainfrom
aaramos:deploy/hermes-update-preserve-local-commits

Conversation

@aaramos

@aaramos aaramos commented Aug 24, 2026

Copy link
Copy Markdown

Summary

hermes update treated any git merge --ff-only origin/<branch> failure — while already checked out on <branch> — as proof of an upstream force-push, and unconditionally ran git reset --hard origin/<branch> to recover. That's also exactly what happens when the local checkout simply has commits origin doesn't have yet (e.g. a fix committed directly to a live deployment checkout instead of through a PR): merge --ff-only fails identically in both cases.

Live incident, 2026-08-23: a reviewed and tested host-hygiene fix (see companion PR) was committed directly onto a live checkout's main. Origin's main later advanced normally (unrelated commits, no rewrite). The next hermes update hit the ff-only failure, assumed a force-push, and reset --hard silently discarded the commit — no warning, no stash, no trace.

  • Before the update's fetch, capture the origin tip the checkout already knew about.
  • After a same-branch ff-only failure, check whether that old tip is still an ancestor of the freshly-fetched tip.
    • Yes → origin only advanced, nothing was rewritten → merge instead of reset, exactly like the existing custom-branch-with-local-commits path already does (tag safety ref, merge --no-edit, abort-and-report cleanly on conflict — never destroy local commits).
    • No (or no prior tip to compare against, e.g. a fresh clone) → genuine rewrite → the original reset --hard behavior is unchanged.

Test plan

New tests/hermes_cli/test_update_local_commit_preservation.py, using real throwaway git repos (no mocking of the ancestry logic itself):

  • reproduces the 2026-08-23 incident shape exactly and asserts the commit now survives (merge, not reset)
  • a genuine git commit --amend history rewrite is still correctly detected and still resets
  • no prior origin tip to compare against still defaults to the original safe behavior (reset)

All 3 pass. Note: exercising the surrounding hermes update flow for validation surfaced that this codebase's existing test_cmd_update.py / test_update_autostash.py suites aren't fully isolated from a live install's real gateway processes when run in-place — pre-existing test-hygiene gap, unrelated to this change, not addressed here.

🤖 Generated with Claude Code

…not a rewrite

hermes update assumed any `merge --ff-only origin/<branch>` failure while
already on <branch> meant an upstream force-push, and reset --hard to
match — discarding local history unconditionally. That's also exactly
what happens when local simply has commits origin doesn't have yet (e.g.
a host-ops fix committed directly to a live checkout instead of through a
PR). Live incident 2026-08-23: a reviewed, tested host-hygiene fix was
silently wiped this way when origin/main next advanced normally.

Distinguish the two cases with a merge-base ancestry check against the
origin tip captured before the fetch: if that old tip is still an
ancestor of the new one, origin only moved forward — merge, never reset.
Only fall through to reset --hard on a genuine rewrite (old tip no longer
reachable) or when there's no prior tip to compare against (unchanged,
safe-by-default behavior).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/cli CLI entry point, hermes_cli/, setup wizard area/install-update Installer, updater, packaging, wheels, doctor sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades labels Aug 24, 2026
@aaramos

aaramos commented Aug 24, 2026

Copy link
Copy Markdown
Author

Flagging urgency: without this fix, any local-only deploy commit on a live checkout is one hermes update away from silent, total loss (see the incident in the description — it's what happened to the companion PR #93498's fix before it was re-ported here). Happy to address any review feedback.

@aaramos

aaramos commented Aug 24, 2026

Copy link
Copy Markdown
Author

Closing — same as #93498, pushed upstream by mistake. Meant for local use only.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/install-update Installer, updater, packaging, wheels, doctor 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