Skip to content

feat(log): review contiguous commit ranges - #1031

Merged
benvinegar merged 1 commit into
mainfrom
feat/history-ranges
Sep 7, 2026
Merged

benvinegar merged 1 commit into
mainfrom
feat/history-ranges

Conversation

@benvinegar

@benvinegar benvinegar commented Sep 7, 2026 •

Copy link
Copy Markdown
Member

Summary

  • add contiguous multi-commit selection to interactive hunk log
  • support Shift+Arrow, uppercase J/K, and forwarded Shift+click selection
  • open inclusive ranges through provider-owned Git and Jujutsu planning, including root and merge baselines
  • preserve selection across review return and history refresh
  • add extension API v21 range planning, docs, tests, and a Changeset

Semantics

The selected range compares the chosen parent (or empty/root baseline) of the oldest commit directly with the newest commit. Git never uses triple-dot semantics. Non-ancestral endpoint selections are rejected clearly.

Stack

  1. This PR — contiguous history selection and range review
  2. fix(ui): show info for comparison reviews #1032 — keep the review-info panel visible for comparison reviews

Merge this PR before #1032.

Validation

  • bun run typecheck
  • bun run deps:check
  • bun run test (2243 passed, 9 skipped on the complete stack)
  • bun run test:integration (155 passed, 1 skipped)
  • focused Git/Jujutsu history tests
  • PTY coverage for J/K selection, forwarded Shift+click, inclusive root review, and retained return state

Not tested on Windows or in a physical SSH/Mosh session.

This PR description was generated by Pi using gpt-5.6-sol

@vercel

vercel Bot commented Sep 7, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
hunk-web Ready Ready Preview Sep 7, 2026 6:11pm UTC

Request Review

@greptile-apps

greptile-apps Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds contiguous multi-commit selection to interactive Git and Jujutsu history, introduces provider-owned range planning in extension API version 21, and routes selected ranges into embedded reviews.

  • Adds Shift+Arrow, uppercase J/K, and Shift-click range selection.
  • Adds direct parent-to-newest range planning for Git, JJ, and third-party adapters.
  • Preserves range state across refreshes and embedded-review navigation.
  • Adds unit, session-host, and PTY coverage plus public documentation.
  • Range planning currently blocks cancellation, and filtered histories can understate the reviewed commit span.

Confidence Score: 3/5

The PR is not yet safe to merge because opening ranges can freeze the interactive UI during uncancellable provider queries, and filtered histories can open a broader commit span than the selection reports.

Two concrete range-review failures remain: synchronous Git/JJ planning blocks the event loop and cancellation, while displayed-row counting does not account for commits omitted by active history filters.

Files Needing Attention: packages/hunk-git/src/history.ts, packages/hunk-jj/src/history.ts, packages/hunk/src/ui/log/controller.ts

Important Files Changed

Filename Overview
packages/hunk/src/ui/log/controller.ts Adds retained range anchors, asynchronous navigation settling, refresh reconciliation, and displayed-row endpoint calculation; filtered gaps can make its count understate the actual ancestry span.
packages/hunk/src/ui/log/LogApp.tsx Adds keyboard and mouse range selection, range rendering, parent selection, and range-opening outcomes.
packages/hunk/src/ui/session/HunkSessionHost.tsx Routes single selections and multi-commit ranges through provider planning into embedded review preparation.
packages/hunk-git/src/history.ts Adds ancestry validation and direct Git range planning, but performs the new planning subprocesses synchronously on the interactive path.
packages/hunk-jj/src/history.ts Adds JJ ancestry and root-baseline range planning using synchronous subprocess queries that cannot be interrupted during planning.
packages/hunk/src/extension-api/types.ts Advances the extension API to version 21 and publishes optional provider-owned inclusive range planning.

Sequence Diagram

sequenceDiagram
  actor User
  participant Log as LogApp / LogController
  participant Host as HunkSessionHost
  participant Provider as Git or JJ range planner
  participant Review as Embedded review

  User->>Log: Extend selection
  Log->>Log: Derive displayed endpoints and count
  User->>Log: Open selection
  Log->>Host: selection, count, optional parent
  Host->>Provider: planRangeReview(endpoints)
  Provider-->>Host: revision-range action
  Host->>Review: Prepare parent-to-newest diff
  Review-->>User: Render cumulative changes
Loading
Prompt To Fix All With AI
### Issue 1
packages/hunk-git/src/history.ts:76
**Range planning blocks cancellation**

Opening a range runs `git merge-base` synchronously on the renderer thread; the JJ planner also uses `Bun.spawnSync`. The preparation signal is checked only after planning returns, so a slow or stuck VCS query freezes the history UI and prevents quit or cancellation from taking effect. These queries need to use the existing asynchronous, signal-aware provider command path.

### Issue 2
packages/hunk/src/ui/log/controller.ts:392-401
**Filtered ranges hide commits**

The selection count comes from adjacent displayed rows, but filtered histories can omit intermediate commits. Git and JJ only verify that the endpoints share ancestry, so selecting two adjacent filtered results can show “2 commits selected” while the resulting diff includes changes from hidden commits between them. Range selection should either reject filtered gaps or clearly represent the full ancestry span being reviewed.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Reviews (1): Last reviewed commit: "feat(log): review contiguous commit rang..." | Re-trigger Greptile

Comment thread packages/hunk-git/src/history.ts Outdated
): ExtensionVcsHistoryRangeReviewAction {
const newest = requireRevision(selection.newestCommit.revisionId);
const oldest = requireRevision(selection.oldestCommit.revisionId);
const ancestry = runGitResult(["merge-base", "--is-ancestor", oldest, newest], options, [0, 1]);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Range planning blocks cancellation

Opening a range runs git merge-base synchronously on the renderer thread; the JJ planner also uses Bun.spawnSync. The preparation signal is checked only after planning returns, so a slow or stuck VCS query freezes the history UI and prevents quit or cancellation from taking effect. These queries need to use the existing asynchronous, signal-aware provider command path.

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/hunk-git/src/history.ts
Line: 76

Comment:
**Range planning blocks cancellation**

Opening a range runs `git merge-base` synchronously on the renderer thread; the JJ planner also uses `Bun.spawnSync`. The preparation signal is checked only after planning returns, so a slow or stuck VCS query freezes the history UI and prevents quit or cancellation from taking effect. These queries need to use the existing asynchronous, signal-aware provider command path.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. Git and Jujutsu range planning now use the shared asynchronous, signal-aware provider command runner. The history host forwards its preparation signal into provider planning, cancellation terminates the owned process tree, and provider plus host regression tests cover the path.

This comment was generated by Pi using gpt-5.6-sol

Comment on lines +392 to +401
const anchor = this.snapshot.selectionAnchor ?? this.snapshot.selected;
const newestIndex = Math.min(anchor, this.snapshot.selected);
const oldestIndex = Math.max(anchor, this.snapshot.selected);
return {
focus,
newest: this.snapshot.rows[newestIndex]!,
oldest: this.snapshot.rows[oldestIndex]!,
newestIndex,
oldestIndex,
count: oldestIndex - newestIndex + 1,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Filtered ranges hide commits

The selection count comes from adjacent displayed rows, but filtered histories can omit intermediate commits. Git and JJ only verify that the endpoints share ancestry, so selecting two adjacent filtered results can show “2 commits selected” while the resulting diff includes changes from hidden commits between them. Range selection should either reject filtered gaps or clearly represent the full ancestry span being reviewed.

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/hunk/src/ui/log/controller.ts
Line: 392-401

Comment:
**Filtered ranges hide commits**

The selection count comes from adjacent displayed rows, but filtered histories can omit intermediate commits. Git and JJ only verify that the endpoints share ancestry, so selecting two adjacent filtered results can show “2 commits selected” while the resulting diff includes changes from hidden commits between them. Range selection should either reject filtered gaps or clearly represent the full ancestry span being reviewed.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed conservatively. Multi-commit selection is now refused whenever author, message, date, or path traversal filters can omit intermediate commits, with a clear in-app notice. Unfiltered ranges retain their existing behavior, and controller coverage verifies that filtered ranges cannot be formed.

This comment was generated by Pi using gpt-5.6-sol

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Follow-up from the independent review: --all is now covered by the same refusal because multiple-head topology can interleave unrelated commits between selected endpoints. Documentation and regression coverage were updated accordingly.

This comment was generated by Pi using gpt-5.6-sol

@benvinegar
benvinegar merged commit e3e4a6a into main Sep 7, 2026
12 checks passed

This branch was successfully deployed

1 active deployment
Preview — 89c037d0 Deployed Sep 7, 2026 by vercel[bot]
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