From b486215c43f1c0d52d68e9c7fb7c224ed21ad8c8 Mon Sep 17 00:00:00 2001 From: Erwin Wee Date: Tue, 22 Sep 2026 18:20:10 +0800 Subject: [PATCH 1/2] fix(history): reload commit list after off-tab ref changes Commits made while the History tab was inactive (e.g. by an agent) did not appear until an unrelated later watcher event. handleRepoChanged only reloaded history when view === 'history', setView reloaded only when the list was empty, and window.focus refreshes status only. Track a stale flag on HistoryState: set it when refs change off-tab, consume it on History tab entry, and clear it on a reset load (preserving a flag re-raised mid-request and never clearing on paginated append). --- src/renderer/src/state/actions.ts | 5 +++-- src/renderer/src/state/store.ts | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/renderer/src/state/actions.ts b/src/renderer/src/state/actions.ts index 7db7e37..1f1cc24 100644 --- a/src/renderer/src/state/actions.ts +++ b/src/renderer/src/state/actions.ts @@ -193,6 +193,7 @@ async function handleRepoChanged(reason: 'worktree' | 'refs' | 'both'): Promise< if (reason !== 'worktree') { await Promise.all([refreshBranches(), refreshStashes()]); if (store.get().view === 'history') await loadHistory(true); + else patchHistory({ stale: true }); } await loadDiff(true); if (store.get().precommitReview.run) void refreshPrecommitStaleness(); @@ -760,7 +761,7 @@ export function setView(view: View): void { store.set({ view }); if (view === 'history') { const h = store.get().history; - if (!h.commits.length) void loadHistory(true); + if (!h.commits.length || h.stale) void loadHistory(true); else if (!h.selectedShas.length) selectCommit(h.commits[0].sha); } else if (view === 'stashes') { void loadStashesView(); @@ -931,7 +932,7 @@ export async function loadHistory(reset: boolean): Promise { if (store.get().currentRepo?.path !== repo.path) return; const commits = reset ? page.commits : [...h.commits, ...page.commits]; const stillSelected = store.get().history.selectedShas.filter((sha) => commits.some((c) => c.sha === sha)); - patchHistory({ commits, hasMore: page.hasMore, loading: false, slowSearch: false, error: null, selectedShas: stillSelected, details: stillSelected.length === 1 ? store.get().history.details : null }); + patchHistory({ commits, hasMore: page.hasMore, loading: false, slowSearch: false, error: null, selectedShas: stillSelected, details: stillSelected.length === 1 ? store.get().history.details : null, stale: store.get().history.stale && !(reset && h.stale) }); if (store.get().view === 'history' && stillSelected.length === 0 && commits.length) selectCommit(commits[0].sha); else if (stillSelected.length === 1 && reset) void loadCommitDetails(stillSelected[0]); } catch (err) { diff --git a/src/renderer/src/state/store.ts b/src/renderer/src/state/store.ts index c365874..6bbd200 100644 --- a/src/renderer/src/state/store.ts +++ b/src/renderer/src/state/store.ts @@ -131,6 +131,8 @@ export interface HistoryState { error: string | null; /** Set when the most recent commit-details load failed; cleared on the next successful load and when a new load starts. */ detailsError: string | null; + /** Set when refs changed (commit/branch move) while the History tab was not the active view, so switching back reloads instead of showing a cached list. */ + stale: boolean; } export interface ReviewState { @@ -484,7 +486,7 @@ export const initialChanges: ChangesState = { export const initialStashesView: StashesViewState = { loading: false, selectedSha: null, files: [], filesLoading: false, selectedFile: null }; -export const initialHistory: HistoryState = { commits: [], hasMore: false, loading: false, search: '', query: EMPTY_HISTORY_QUERY, freeText: '', queryError: null, slowSearch: false, selectedShas: [], details: null, detailsLoading: false, selectedFile: null, matchingFiles: null, dragging: null, path: null, pathHistory: null, error: null, detailsError: null }; +export const initialHistory: HistoryState = { commits: [], hasMore: false, loading: false, search: '', query: EMPTY_HISTORY_QUERY, freeText: '', queryError: null, slowSearch: false, selectedShas: [], details: null, detailsLoading: false, selectedFile: null, matchingFiles: null, dragging: null, path: null, pathHistory: null, error: null, detailsError: null, stale: false }; export const initialDiff: DiffState = { key: null, diff: null, loading: false, error: null, selectedLines: null, blameOn: false, blame: null, blameLoading: false, activeBlameId: null, highlightTerm: null }; From fcf49ec973facba7e7ddc89d109e76b0d69e8b63 Mon Sep 17 00:00:00 2001 From: Erwin Wee Date: Tue, 22 Sep 2026 18:23:54 +0800 Subject: [PATCH 2/2] fix(pr): refresh current-PR association on fetch and pull The View Pull Request command read a cached prs.current that was only populated on repo open, push/checkout/PR actions in-app, and a 3-minute background poll. A PR created outside gitgood was invisible until that poll ticked, so the command could report "No pull request for this branch" despite an open PR. fetchRemote() and pull() now force-refresh the current PR, so an explicit remote sync surfaces an externally-created (or merged/closed) PR immediately, without checking on every local commit. --- src/renderer/src/state/actions.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/renderer/src/state/actions.ts b/src/renderer/src/state/actions.ts index 1f1cc24..b50609f 100644 --- a/src/renderer/src/state/actions.ts +++ b/src/renderer/src/state/actions.ts @@ -1345,6 +1345,7 @@ export async function fetchRemote(): Promise { const repo = store.get().currentRepo; if (!repo) return; await runOperation('Fetch', () => invoke('git.fetch', repo.path, null)); + void loadCurrentPullRequest(true); } export async function pull(): Promise { @@ -1353,6 +1354,7 @@ export async function pull(): Promise { const outcome = await runOperation('Pull', () => invoke('git.pull', repo.path)); if (outcome?.status === 'conflicts') reportOutcome(outcome, 'Pull'); else if (outcome?.status === 'complete') showToast({ kind: 'success', title: 'Pulled latest changes' }); + void loadCurrentPullRequest(true); } export async function push(force = false): Promise {