Skip to content

Commits list remains stale after switching agents and creating new commits #7416

Closed

Description

@xd-o-bx

Where did this happen?

Desktop app (macOS)

Version

1.28.0

What happened?

When working across multiple agents, new commits made by an agent are not reflected in the commits list after switching to or continuing the session with another agent. The commits view continues to display a stale commit history instead of automatically refreshing or syncing with the latest repository state.

Expected behavior:
The commit history should refresh automatically or reflect the latest HEAD/commits whenever an agent creates new commits, even when continuing across different agents.

Steps to reproduce

  1. Open a workspace and start a session with an agent.
  2. Have the agent create one or more commits (or let another agent make new commits on the branch).
  3. Continue the workflow with another agent via the "Continue with another agent" option
  4. Make additional commits using the new agent.
  5. Inspect the commits list in the UI.
  6. Observe that the list remains stale and does not show the newly created commits.

Logs, screenshots, or recordings

No response

Activity

  1. github-actions commented on Sep 11, 2026

    @github-actions
    Contributor

    Summary

    The report is plausible and I can point at a concrete gap in the desktop renderer. New commits made outside the app's own commit button — i.e. by an agent in a terminal, which is exactly what the "have the agent commit / continue with another agent / commit again" flow does — do refresh the changed-files list and status badge, but not the commits list. The server side is fine (git.listCommits shells out to git log on every call with no caching), and the host-side git:changed event does fire on an agent commit. The renderer just never invalidates the git.listCommits query when that event arrives, so the cached commit list sits there until something unrelated happens to refetch it. Switching agents is incidental to the cause — it's a reliable way to generate commits from outside the UI while the app window never loses focus.

    Affected code

    • apps/desktop/src/renderer/hooks/host-service/useGitStatus/useGitStatus.ts:65-87 — the single owner of the git:changed subscription for a v2 workspace. Its invalidate callback refreshes git.getStatus (via the trailing scheduler), git.getDiffPatch, git.getDiff, and git.getBaseBranch. git.listCommits is not in the list.
    • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/hooks/useChangesTab/useChangesTab.tsx:138-141 — the sidebar's commits query. Its only automatic refresh is refetchOnWindowFocus: true; the default staleTime is 5s (packages/workspace-client/src/providers/WorkspaceClientProvider/WorkspaceClientProvider.tsx:7). There's no interval and no event subscription. utils.git.listCommits.invalidate is called in exactly one place in the renderer — the base-branch mutation at useChangesTab.tsx:113-119.
    • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/ChangesControl/components/ShipControl/ShipControl.tsx:96-107 — issues the same query key ({ workspaceId, baseBranch }) with refetchInterval: 10_000, so while that component is mounted its poll incidentally keeps the sidebar list fresh. It's gated on canCreatePr = projectId != null (ShipControl.tsx:62) and only rendered on the no-PR half of the top-bar control, so the list goes permanently stale in session workspaces (no project) and once a PR exists. That's the likely reason this looks intermittent between workspaces.
    • For contrast, the legacy v1 Changes view reads commits out of the status payload itself (.../RightSidebar/ChangesView/ChangesView.tsx:521, shared/changes-types.ts:46), so it rode along with the status refresh. The v2 sidebar split commits into a separate query and that query was left out of the invalidation set.

    Suspected root cause

    Missing git.listCommits invalidation in the git:changed handler at useGitStatus.ts:65-85. An agent commit produces a broad git:changed (no paths, since .git/ was touched — packages/host-service/src/events/git-watcher.ts:482-524), the handler runs, status/diffs refresh, and the commits query is left untouched. With the Electron window continuously focused during an agent session, refetchOnWindowFocus never fires either, so the list stays as it was until the user blurs and refocuses the app, changes the base branch, commits through the UI (ShipControl.tsx:113-122 refetches explicitly), or happens to have ShipControl's 10s poll mounted.

    Ruled out: server-side staleness. git.listCommits (packages/host-service/src/trpc/router/git/git.ts:313-351) runs git log <baseRef>..HEAD per request with no cache or worker dedupe, and packages/host-service/test/integration/git-history.integration.test.ts covers it returning fresh commits.

    One adjacent gap worth a look while in here, though I don't think it's what this report hit: GitWatcher.attachWatcher watches git rev-parse --git-dir (git-watcher.ts:625-654), which for a linked worktree is <repo>/.git/worktrees/<name> — the common dir holding refs/heads/* and packed-refs is not watched. A commit in the workspace's own worktree still writes index/COMMIT_EDITMSG under the watched dir so the event fires, but ref movement originating elsewhere in the repo (a fetch moving the base ref, a commit in a sibling worktree, git update-ref) is invisible to the watcher. packages/host-service/src/trpc/router/git/utils/base-ref-freshness.ts:37 already reaches for --git-common-dir for this reason.

    Reproduction

    1. Open a v2 workspace whose project has an open PR already (or a session workspace with no project) so ShipControl's incidental 10s poll isn't mounted.
    2. Open the sidebar Changes tab and open the scope dropdown — note the commits listed.
    3. In a terminal inside that worktree (or via an agent), run git commit --allow-empty -m "probe". Keep the app window focused the whole time.
    4. The changed-files list and the top-bar diff stats update within ~1s; reopen the scope dropdown — the new commit is absent.
    5. Cmd-Tab away and back: the list now shows it. That focus-only recovery is the tell.

    Unit-level sketch (bun:test) against useGitStatus: mock workspaceTrpc.useUtils() and useWorkspaceEvent so the registered handler is capturable, render the hook, invoke the handler with {} (broad change) and with { paths: ["a.ts"] }, and assert utils.git.listCommits.invalidate was called with { workspaceId } for the broad case. There's no existing test file for this hook, so it would be a new useGitStatus.test.ts next to it.

    Suggested fix direction

    Add git.listCommits to the broad-change branch of invalidate in useGitStatus.ts:72-82, alongside the existing getBaseBranch invalidation:

    } else {
        void utils.git.getDiff.invalidate({ workspaceId });
        void utils.git.getBaseBranch.invalidate({ workspaceId });
        void utils.git.listCommits.invalidate({ workspaceId });
    }

    Gating it on the no-paths branch is deliberate and cheap: paths present means the batch was worktree-only, which can't move HEAD, so ordinary file-edit churn won't spawn a git log per keystroke. Note that listCommits's key includes baseBranch, so invalidating with just { workspaceId } covers every base variant (the existing call at useChangesTab.tsx:117 already relies on that). git.getBranchSyncStatus is in the same boat conceptually but is already polled at 10s by usePRFlowState, so it's a smaller win.

    Adding a refetchInterval to the sidebar query would also mask the symptom, but the event-driven invalidation is the established pattern in this hook and avoids a permanent git log poll per open workspace.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions