feat(web): add per-commit diff views - #6102
Conversation
The Diff pane could only show cumulative branch changes or checkpoint turns, so there was no way to see what an individual commit changed. The review diff preview now returns the commits in the active branch comparison range, and accepts a commit sha to fetch that commit's first-parent patch on demand. The Diff pane lists those commits in a Commits submenu beside Turns and renders the selected one through the existing diff renderer, file expansion, and view controls. Commit selections keep the chosen comparison base and fall back to Branch changes when history is rewritten. Closes pingdotgg#5881.
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 290469294f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| branchCommits: Schema.Array(ReviewBranchCommit), | ||
| branchCommitsTruncated: Schema.Boolean, |
There was a problem hiding this comment.
Make the new preview fields optional for older servers
When an updated hosted web or mobile client connects to an older remote T3 server, that server's review.getDiffPreview response lacks these newly required properties, so the RPC success schema rejects the entire response and the existing diff pane stops working. Keep these fields optional on the wire and treat them as []/false in clients so independently updated remote clients remain compatible.
AGENTS.md reference: AGENTS.md:L19-L21
Useful? React with 👍 / 👎.
| import * as Order from "effect/Order"; | ||
|
|
||
| export type ReviewSectionKind = "turn" | "working-tree" | "branch-range"; | ||
| export type ReviewSectionKind = "turn" | ReviewDiffPreviewSourceKind; |
There was a problem hiding this comment.
Add commit selection to the mobile review surface
This widens mobile's section kind to include commit, but useReviewSections.ts:35-40 still requests only the ordinary preview and review-section-menu.ts:3-20 exposes only working-tree, branch, and turn sections. Consequently mobile users cannot list or request any of the per-commit diffs added here, even though mobile already has the corresponding review surface; wire branchCommits and commit requests into that menu rather than changing only its type.
AGENTS.md reference: AGENTS.md:L65-L72
Useful? React with 👍 / 👎.
| {branchCommits.length === 0 ? ( | ||
| <DropdownMenuItem disabled> | ||
| {branchDiffPreview.isPending | ||
| ? "Loading commits..." | ||
| : "No commits in the branch range."} | ||
| </DropdownMenuItem> |
There was a problem hiding this comment.
Load commits while a turn diff is selected
When the current selection is a turn, the branch-preview query is disabled by the selectedTurnId === null condition at lines 257-268, leaving branchCommits empty. This new submenu therefore reports “No commits in the branch range” and offers no commit actions until the user first switches to Branch changes and reopens the menu, even when the branch has commits; keep the lightweight branch/commit-list query available for this menu state.
Useful? React with 👍 / 👎.
ApprovabilityVerdict: Needs human review 1 blocking correctness issue found. This PR introduces a new per-commit diff view feature spanning server, web, and contracts layers with significant new logic. Multiple unresolved review comments identify potential bugs around base ref handling and backward compatibility concerns. You can customize Macroscope's approvability policy. Learn more. |
The new preview fields are required on the wire, so an updated client talking to an older server fails to decode the whole diff preview. They now carry decoding defaults: an older server that omits them decodes to an empty, untruncated commit list. The Commits submenu read the branch preview, which only ran when no turn was selected, so the menu was empty from any turn scope. The branch preview now runs for every selection. The branch commit listing capped output bytes without allowing truncation, so an oversized listing raised instead of truncating and degraded to no commits at all. It now truncates, and byte truncation reports through branchCommitsTruncated. Reconciling a commit selection cleared it whenever the sha was missing from the listing, including when the listing was capped, empty, or had not loaded. Only a complete, non-empty listing now proves a commit left the range. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
| ); | ||
| // Runs for every selection: the scope menu lists this preview's commits even while a | ||
| // turn or a single commit is being viewed. | ||
| const primaryBranchDiffPreview = useEnvironmentQuery( |
There was a problem hiding this comment.
🟠 High components/DiffPanel.tsx:259
When a user picks a custom branch base ref and then switches to a turn, primaryBranchDiffPreview now always runs but uses selectedBaseRef, which is null for turn selections. The Commits submenu is therefore populated from the automatic range, not the user's custom range. Selecting one of those commits restores the custom baseRef, and reconcileCommitSelection immediately rejects that commit (it is not in the custom-range listing) and bounces back to branch view — so the user cannot select a commit that was shown to them. Consider preserving the last-selected baseRef when switching to a turn so the commit list stays scoped to the custom range.
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/components/DiffPanel.tsx around line 259:
When a user picks a custom branch base ref and then switches to a turn, `primaryBranchDiffPreview` now always runs but uses `selectedBaseRef`, which is `null` for turn selections. The Commits submenu is therefore populated from the automatic range, not the user's custom range. Selecting one of those commits restores the custom `baseRef`, and `reconcileCommitSelection` immediately rejects that commit (it is not in the custom-range listing) and bounces back to branch view — so the user cannot select a commit that was shown to them. Consider preserving the last-selected `baseRef` when switching to a turn so the commit list stays scoped to the custom range.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 50023e3eee
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const primaryBranchDiffPreview = useEnvironmentQuery( | ||
| selectedTurnId === null && activeThread && activeCwd | ||
| activeThread && activeCwd |
There was a problem hiding this comment.
Avoid loading full branch patches for turn views
When the pane opens or restores with a turn selected, this unconditional query runs review.getDiffPreview in addition to the checkpoint-diff query merely to populate the Commits submenu. In GitVcsDriverCore, that RPC computes and returns the tracked and untracked working-tree patches plus the branch-range patch before returning commit metadata, so a closed submenu can add substantial Git work and WebSocket traffic—especially for remote clients and repositories with many untracked files. Use a metadata-only request or load the commit list lazily instead of running the full preview for every selection.
AGENTS.md reference: AGENTS.md:L15-L17
Useful? React with 👍 / 👎.
| const selectedBaseRef = | ||
| diffSelection.kind === "branch" || diffSelection.kind === "commit" | ||
| ? diffSelection.baseRef | ||
| : null; |
There was a problem hiding this comment.
Preserve the remembered base when listing commits
After a user chooses a custom base and switches to a turn or the working tree, this sets selectedBaseRef to null, so the Commits submenu is populated from the automatically resolved range. However, selectCommit restores the custom value from branchBaseRefByThreadKey; clicking an item therefore immediately changes the range used for reconciliation, which can bounce back to Branch changes when that SHA is absent from the custom range or display an out-of-range commit when the custom range is empty. The menu query and stored commit selection need to use the same remembered base.
Useful? React with 👍 / 👎.
| previous?.kind !== "commit" || | ||
| !listIsComplete || | ||
| availableCommitShas.length === 0 || | ||
| availableCommitShas.includes(previous.commitSha) |
There was a problem hiding this comment.
Reconcile a selected commit against an empty completed range
When a rebase/reset removes all branch-range commits, or the user changes the base to the current head, a successful current-server preview returns a complete empty branchCommits list. This length guard preserves the old selection indefinitely; because the commit object commonly remains reachable through the reflog, its preview can continue showing a commit that is no longer in the selected range while the submenu says there are no commits. Distinguish unavailable/legacy listings from an authoritative empty result and fall back to the branch view for the latter.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 50023e3. Configure here.
| // turn or a single commit is being viewed. | ||
| const primaryBranchDiffPreview = useEnvironmentQuery( | ||
| selectedTurnId === null && activeThread && activeCwd | ||
| activeThread && activeCwd |
There was a problem hiding this comment.
Commits list ignores persisted base
Medium Severity
The branch preview now runs while a turn is selected so the Commits menu stays populated, but selectedBaseRef is still null for turn selections. That fetches commits against the automatic base instead of the persisted branch comparison in branchBaseRefByThreadKey. With a custom base, the menu can list the wrong commits; picking one restores the custom base via selectCommit, then reconcileCommitSelection can immediately fall back to branch changes.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 50023e3. Configure here.


Add a "Commits" submenu to the Diff pane (beside the existing "Turns" picker) that lists the current branch's commits; selecting one shows that commit's first-parent diff through the existing diff renderer. Backed by a new GitVcsDriver method that lists commits and loads a single commit's diff on demand. Tests included (185 passing).
Closes #5881.
Note
Add per-commit diff views to the web diff panel
ReviewDiffPreviewResultin review.ts gainsbranchCommitsandbranchCommitsTruncatedfields with backward-compatible defaults for older servers.GitVcsDriverCoregains commit-specific diff generation viagit diff-tree --rootfor root commits andgit difffor others, plus NUL-separatedgit logparsing for branch commit listings.diffPanelStoreaddsselectCommitandreconcileCommitSelectionactions; commit selection auto-reverts to branch view when the selected commit leaves the branch range.Macroscope summarized 50023e3.
Note
Medium Risk
Touches Git subprocess parsing, review RPC contracts, and diff-panel selection persistence; behavior is well covered by driver and store tests but incorrect commit/base handling could show wrong patches.
Overview
Per-commit review in the Diff pane lets users pick a commit from a Commits submenu (scoped to the current branch vs base comparison) and view that commit’s first-parent patch in the existing diff UI, including file expansion for the new
"commit"source kind.Review API and Git backend gain optional
commitShaon diff preview input,branchCommits/branchCommitsTruncatedon the result (with backward-compatible decode defaults), and Git logic to list up to 100 commits onbaseRef..HEAD, load a single commit diff (parent vs empty tree for root commits), and serve file contents for commit-scoped hunks.Client state adds a
commitdiff-panel selection that keeps the branchbaseRef, reconciles when the commit drops out of a complete listing, and loads branch preview commits even while viewing a turn or a single commit so the menu stays populated.Reviewed by Cursor Bugbot for commit 50023e3. Bugbot is set up for automated code reviews on this repo. Configure here.