From 5cb0a5073bfa9ebf9850335ebe2bc033210fe055 Mon Sep 17 00:00:00 2001 From: ethernet Date: Fri, 18 Sep 2026 02:57:30 -0400 Subject: [PATCH] fix(install): a diverged checkout cannot keep its old tree `stage_repository` treated a failed `pull --ff-only` as "keep local state" and carried on. Every later stage reads files only the new tree has (`pm/`), so an install whose checkout could not fast-forward failed further down with `ModuleNotFoundError: No module named 'pm'` instead of updating. A release cut off the main line diverges for every user who installed from it: v2026.5.29.2 is not an ancestor of main, so its checkout can never fast-forward to a later main. Match the remote the way `hermes update` already does, after parking the old tip behind refs/hermes-install-backup/- and stashing any local work so neither is destroyed silently. Verified against a real diverged repository: before, the checkout stayed on the old line (HEAD=6a2e091, remote=43eea63) with no backup; after, HEAD equals the new main, the backup ref and an autostash exist, and both are named in the installer's output. --- scripts/install.sh | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/scripts/install.sh b/scripts/install.sh index 5fbaacfc80..06ab9b5dd3 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -288,7 +288,27 @@ stage_repository() { log "updating $INSTALL_DIR" git -C "$INSTALL_DIR" fetch origin "$BRANCH" || fail "git fetch failed" git -C "$INSTALL_DIR" checkout "$BRANCH" || fail "git checkout failed" - git -C "$INSTALL_DIR" pull --ff-only origin "$BRANCH" || log "not fast-forwardable; keeping local state" + if ! git -C "$INSTALL_DIR" merge --ff-only "origin/$BRANCH"; then + # A release cut off the main line, a force-pushed remote, or the + # user's own commits cannot fast-forward. Every stage below reads + # files only the new tree has (pm/), so an install left on the old + # tree cannot finish -- match the remote the way `hermes update` + # does, after parking the old tip and any local work. + local stamp prior rescue + stamp="$(date -u +%Y%m%d-%H%M%S)" + prior="$(git -C "$INSTALL_DIR" rev-parse --short HEAD 2>/dev/null || echo unknown)" + rescue="refs/hermes-install-backup/$stamp-$prior" + if [ -n "$(git -C "$INSTALL_DIR" status --porcelain)" ]; then + git -C "$INSTALL_DIR" stash push --include-untracked -m "hermes-install-autostash-$stamp" \ + && log "local changes stashed as hermes-install-autostash-$stamp" \ + || log "could not stash local changes; they are overwritten below" + fi + git -C "$INSTALL_DIR" update-ref "$rescue" HEAD 2>/dev/null \ + && log "previous HEAD backed up to $rescue" \ + || log "could not back up the previous HEAD" + git -C "$INSTALL_DIR" reset --hard "origin/$BRANCH" || fail "git reset failed" + log "not fast-forwardable; reset to origin/$BRANCH" + fi else log "cloning $REPO_URL ($BRANCH) into $INSTALL_DIR" mkdir -p "$(dirname "$INSTALL_DIR")"