fix(update,banner): rebase feature branches after pull + measure distance to tracking ref - #40673
Closed
andrebrassfield wants to merge 2 commits into
Closed
Conversation
…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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
hermes updatelooks 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:banner.py::_check_via_local_gitalways measuresHEAD..origin/mainregardless of which branch is checked out.main.py::_cmd_update_implpullsmainbut never switches back to the user's original feature branch.A user on
feat/Xwho forked from an old base sees this every time:hermes update.Fix
_resolve_tracking_ref()helper inbanner.pyreturns the current branch's upstream tracking ref (e.g.origin/feat-x) for any non-main branch,Noneformain/ detached HEAD._check_via_local_gitandget_git_banner_stateboth use the tracking ref so the "X commits behind" number refers to the same thing the user is actually diverged from._cmd_update_impladds a post-pull step: if the user started on a non-main branch, switch back to it and rebase ontoorigin/<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:
main(unchanged): 0 behind.feat/testup-to-date withorigin/feat/test, 5 behindorigin/main: 0 behind (previously 5 — the bug).feat/test2 ahead oforigin/feat/test: 0 behind, banner state showsahead=2(newly surfaced; old code only measured againstorigin/main).feat/happy(clean rebase): rebases onto new main, no errors.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.