Skip to content

fix(toolbar): refresh the branch list after a commit so the Push badge follows - #546

Merged
Tlahey merged 1 commit into
mainfrom
claude/commit-push-pending-badge-a2ab05
Sep 7, 2026
Merged

Tlahey merged 1 commit into
mainfrom
claude/commit-push-pending-badge-a2ab05

Conversation

@Tlahey

@Tlahey Tlahey commented Sep 7, 2026

Copy link
Copy Markdown
Owner

What changed

Committing now updates the toolbar's Push badge. Before this, you committed and the Push button went
on showing nothing β€” or the previous count β€” while the graph beneath it already showed the new
commit. Same for every other action that moves the branch tip: amend, cherry-pick, reset, revert,
fixup, autosquash, rebase, bisect, and the board's background auto-sync (which committed and
pushed without refreshing anything at all).

The badge markup itself was already there and correct; nothing about it changed.

Why

aheadCount/behindCount come from the ['branches', repoPath] query β€” they live on GitBranch,
not on the log. Every flow that wrote a commit invalidated git-log and git-status only, so the
graph redrew correctly while the toolbar kept claiming there was nothing to push. useBranches has
a 15s staleTime, and react-query only refetches a stale query on a trigger the toolbar never gets:
it is never remounted, so in practice the badge stayed wrong until the window lost and regained
focus.

It was not an isolated omission β€” the git-log + git-status pair was copied by hand into about a
dozen call sites and branches was missing from nearly all of them, so the fix is one shared
refreshAfterHistoryChange(queryClient, repoPath) in lib/repoRefresh.ts with the invariant written
into its doc comment, and every history-changing flow routed through it. refreshAfterHeadMove now
delegates to it.

Notes for the reviewer

  • features/graph/lib/graphQueryRefresh.ts is deleted. Its refreshLogAndStatus was precisely
    the function that froze the incomplete pair and handed it to six graph hooks, so keeping it as a
    wrapper would keep the trap. Its six callers now import the shared helper.
  • Two call sites gain an invalidation they did not strictly need. useStashMenu and the branch
    menu's run() now also invalidate branches (a stash pop changes no commit). It is one cheap
    local query, and a refresh helper that is almost right per caller is how this bug happened β€” I
    preferred one rule over six judgements. useBranchMenuActions had a duplicate branches
    invalidation right after; that line is gone.
  • useBoardConfigAutoSync imports the queryClient singleton directly, like useAutoFetch
    does β€” there is no component around syncIfDirty to hold a useQueryClient.
  • Deliberately left out: on a branch with no upstream, libgit2 reports ahead = 0, so the badge
    is empty even though everything is unpushed. That is a separate design decision (should it count
    from the base?), not a regression this introduces.
  • CommitDetailsPanel.test.tsx loses its legacy key-returning i18n mock and asserts the real
    English copy instead, per CLAUDE.md's rule for touching such a file. That is why its diff is bigger
    than the one assertion I added.

Verification

  • pnpm typecheck
  • pnpm lint (warnings only, all pre-existing)
  • pnpm --filter @git-manager/desktop test β€” 762 files / 8317 tests green. One earlier run had
    main.test.tsx hit its 5s timeout under CPU load; green on its own and on a full re-run.
  • Rust β€” untouched, this is frontend-only
  • cargo test β€” n/a
  • Not run in the app. It is a Tauri window, not previewable from this session. The invariant
    is pinned by unit tests instead: refreshAfterHistoryChange invalidates all three keys
    (asserted per key β€” branches is the one that went missing), and the commit panel's refresh
    reaches the branch query. No e2e scenario covers the Push badge after a commit either: the
    remote-ahead fixture has an upstream but a clean working tree, and dirtying it would change
    the doc screenshots that fixture feeds. Happy to build that scenario if you want it.

If this PR touches…

  • A new or changed source file β€” has its co-located test (repoRefresh.test.ts,
    CommitDetailsPanel.test.tsx)
  • An invariant someone could plausibly break later β€” "the badges read the branch list, so a
    refresh that skips it is silently wrong" is recorded in refreshAfterHistoryChange's doc
    comment, beside the code that enforces it

…e follows

The Push and Pull badges count the commits ahead of / behind the upstream, and
those two numbers ride on the branch query (`GitBranch.aheadCount`/`behindCount`),
not on the log. Every flow that wrote a commit invalidated `git-log` and
`git-status` only, so the graph redrew correctly while the toolbar went on
claiming there was nothing to push β€” `useBranches` has a 15s `staleTime`, and
react-query only refetches a stale query on a trigger the toolbar never gets
(it is never remounted).

Replace the copied-by-hand pair with one shared `refreshAfterHistoryChange`
in `lib/repoRefresh.ts`, holding the invariant in its doc comment, and route
every action that writes, removes or rewrites a commit through it: the commit /
amend / staging panel, cherry-pick (graph menu and palette), reset, revert,
fixup, autosquash, rebase (controls and the dedicated window's events), bisect,
and the board auto-sync, which committed and pushed in the background without
refreshing anything at all. `features/graph/lib/graphQueryRefresh.ts` was the
function that froze the incomplete pair, so it goes away.

Also drops the legacy key-returning i18n mock from `CommitDetailsPanel.test.tsx`
and asserts the real English copy instead, per CLAUDE.md.
@Tlahey
Tlahey merged commit 76201a8 into main Sep 7, 2026
3 checks passed
@Tlahey
Tlahey deleted the claude/commit-push-pending-badge-a2ab05 branch September 7, 2026 13:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant