Skip to content

fix(update,banner): rebase feature branches after pull + measure distance to tracking ref - #40673

Closed
andrebrassfield wants to merge 2 commits into
NousResearch:mainfrom
andrebrassfield:fix/update-rebase-and-banner-tracking
Closed

fix(update,banner): rebase feature branches after pull + measure distance to tracking ref#40673
andrebrassfield wants to merge 2 commits into
NousResearch:mainfrom
andrebrassfield:fix/update-rebase-and-banner-tracking

Conversation

@andrebrassfield

Copy link
Copy Markdown

Problem

hermes update looks like a silent no-op when you're on a long-lived feature branch. The TUI banner keeps reporting the same "X commits behind" even after a "successful" update. Two bugs in the same project compound to produce this:

  1. banner.py::_check_via_local_git always measures HEAD..origin/main regardless of which branch is checked out.
  2. main.py::_cmd_update_impl pulls main but never switches back to the user's original feature branch.

A user on feat/X who forked from an old base sees this every time:

  • Run hermes update.
  • main advances 333 commits.
  • feat/X does not advance.
  • TUI still says "333 commits behind."

Fix

  • New _resolve_tracking_ref() helper in banner.py returns the current branch's upstream tracking ref (e.g. origin/feat-x) for any non-main branch, None for main / detached HEAD.
  • _check_via_local_git and get_git_banner_state both use the tracking ref so the "X commits behind" number refers to the same thing the user is actually diverged from.
  • _cmd_update_impl adds a post-pull step: if the user started on a non-main branch, switch back to it and rebase onto origin/<branch>. On rebase conflict, abort the rebase, switch back to main, and print a clear manual-resolution message.

Tested

Synthetic repo, 3 banner scenarios + 2 update scenarios, all pass:

  • Banner on main (unchanged): 0 behind.
  • Banner on feat/test up-to-date with origin/feat/test, 5 behind origin/main: 0 behind (previously 5 — the bug).
  • Banner on feat/test 2 ahead of origin/feat/test: 0 behind, banner state shows ahead=2 (newly surfaced; old code only measured against origin/main).
  • Update on feat/happy (clean rebase): rebases onto new main, no errors.
  • Update on feat/test (rebase conflict): rebase aborts, switches back to main, prints manual-resolution message, leaves repo in clean state.

The fix is one commit, 2 files, 112 insertions, 4 deletions. Cherry-pickable onto any commit on main. No new dependencies.

Mavis and others added 2 commits June 6, 2026 11:52
…ance to tracking ref

Two related bugs in `hermes update` and the TUI banner that compound
to make `hermes update` look like a silent no-op for anyone on a
long-lived feature branch.

1. banner.py::_check_via_local_git always measured
   `HEAD..origin/main`, regardless of which branch was checked out.
   On a feature branch that was deliberately forked from an older base,
   this reported "333 commits behind" even when `hermes update` had
   just pulled `main` to the same commit. Fixed by introducing
   `_resolve_tracking_ref` and using the current branch's @-upstream
   when one exists (falling back to `origin/main` on `main` /
   detached HEAD).

2. main.py::_cmd_update_impl pulled `origin/<branch>` (default main)
   but did not switch back to the user's original feature branch.
   `main` advanced, the feature branch did not, and the next TUI
   check still reported the same distance. Fixed by switching back
   to the original branch after a successful pull and running
   `git rebase origin/<branch>`. On rebase conflict, abort the
   rebase, switch back to `main`, and print a clear message with
   the manual resolution commands.

Tested with a synthetic repo: banner reports 0 behind on a feature
branch that's in sync with its own tracking ref even when 5 commits
behind `origin/main`; update successfully rebases a feature branch
onto the new `main` (with conflict-abort recovery) on a no-conflict
scenario.

Repro: be on `feat/cron-until-done` at base 1927ff2 with 11
carried commits, run `hermes update`, observe `main` advances
but `feat/cron-until-done` does not.
Per PR #40673 review: the stash was being restored in the finally block
while still on main, before the post-update block switches back to the
feature branch. This meant the rebase ran with a dirty working tree
(stash changes from feat/X applied to main's tree), causing a silent
abort that left the user on main — identical to the old buggy behavior.

Fix: gate the finally-block stash restore on current_branch in
{branch, 'HEAD'} (only run when user stays on main). In the post-update
block, restore stash after checkout-back but before rebase. On rebase
conflict, re-stash before switching to main so nothing is lost.

Also adds _stash_local_changes_if_needed call in the rebase-conflict
path to save any uncommitted state before the abort+checkout-main.

12 regression tests covering:
- Stash restored on feature branch, not on main (core regression)
- Stash not double-restored (finally + post-update)
- Stash restored in finally when staying on main (unchanged path)
- Rebase conflict: abort, re-stash, switch to main, print guidance
- No-stash feature branch update (just switchback + rebase)
- Banner _resolve_tracking_ref: main/detached/no-upstream/feature
- Banner distance uses tracking ref for feature branches

Refs: PR #40673, review comment on stash-restore ordering
@alt-glitch alt-glitch added type/bug Something isn't working P3 Low — cosmetic, nice to have comp/cli CLI entry point, hermes_cli/, setup wizard labels Jun 6, 2026
@andrebrassfield andrebrassfield closed this by deleting the head repository Jun 19, 2026
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 P3 Low — cosmetic, nice to have type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants