You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Browse filesBrowse the repository at this point in the historyBrowse files
Test
committed
refactor: remove StackTreeDataProvider and implement StackWebViewProvider
- Deleted StackTreeDataProvider.ts to streamline stack management.
- Introduced StackWebViewProvider.ts to handle rendering of the current branch's PR stack.
- Added webview HTML generation and state management for the stack view.
- Implemented React components for stack display, including StackList, StackRow, and StackTargetChip.
- Created context menu for stack actions and integrated logging for user interactions.
- Updated TypeScript configuration and Webpack setup to include new stack-related components.
Copy file name to clipboardExpand all lines: .claude/rules/architecture.md
+13-8Lines changed: 13 additions & 8 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -26,9 +26,13 @@ Business logic decoupled from VS Code UI:
26
26
-`JiraService` — fetches Jira issue data via REST API using stored token
27
27
-`RefDetailsCache` — caches ref→commit lookups to avoid redundant git calls
28
28
-`PRReviewWorktreeStore` — persists active PR-review worktree paths across sessions
29
-
-`StackStore` — Memento wrapper over `context.workspaceState` persisting the detected stack forest (`{ branch, parent, source }`); manual entries always win over `github`/`heuristic` detection on merge (`mergeStackEntries`)
30
-
-`stackDetectionService` — detects chains of dependent branches ("stacks") from two sources, merged: GitHub PR base chains (authoritative, via `GitHubClient.listOpenPullRequests`) and a local ancestry heuristic (`git merge-base --is-ancestor` / `git rev-list --count`, offline fallback). Pure functions (`computeLocalAncestryParents`, `computeGithubParents`, `mergeDetectedParents`) are unit-tested against fixtures; `detectStacks` is the async orchestrator
31
-
-`stackTopology` — pure forest/tree helpers (`buildStackForest`, `topoOrder`, `findStackContaining`) shared by `StackTreeDataProvider` and the status bar indicator
29
+
-`StackStore` — Memento wrapper over `context.workspaceState`; now scoped to the local-ancestry **fallback** path only (`{ branch, parent, source: 'heuristic' | 'manual' }`), plus manual overrides (`mergeStackEntries`). PR-derived stacks are never persisted as edges here — see `prStack`/`stackModel` below
30
+
-`stackDetectionService` — the local ancestry heuristic (`computeLocalAncestryParents`, `detectLocalAncestryStacks` via `git merge-base --is-ancestor` / `git rev-list --count`, `heuristicEntriesFrom`). Offline-only; consulted by `StackService` solely as a fallback, never merged with PR data
31
+
-`stackTopology` — pure forest/tree helpers (`buildStackForest`, `topoOrder`, `findStackContaining`) used by the heuristic fallback path
32
+
-`prStack` — pure PR-chain walker: `buildPrStack(prs, currentBranch, { trunk })` walks `head -> base` links both directions from the current branch and returns the ordered chain plus the target branch (which may be trunk or any other branch); no `localBranches` filter, so remote-only chain members and chains targeting trunk are both valid
33
+
-`stackModel` — the `StackView` shape both the Stacks webview and the status bar render (`stackViewFromPrStack` / `stackViewFromForest`, `indicatorBranchesOf`, `stackInfoMapOf`)
34
+
-`PrStackCache` — Memento-backed cache of the raw open-PR list per repository (TTL-based `isPrCacheFresh`), so a refresh fetches PRs at most once and a stale/offline fetch can still render from the last known list
35
+
-`StackService` — orchestrates a refresh: GitHub PR chains are authoritative and fetched once (`GitHubClient.listOpenPullRequestsOrThrow`); the heuristic only runs when GitHub data is genuinely unusable (no remote, or the API call failed with no fresh cache) — the two sources are structurally never merged into one view
|`autoStashAndPop`| Stash is popped onto target branch (destructive) |
49
53
|`autoStashAndApply`| Stash applied to target branch, original preserved |
50
54
51
-
## Stacks Tree View & Status Bar Indicator
55
+
## Stacks View & Status Bar Indicator
52
56
53
-
`StackTreeDataProvider` (`src/view/`, view id `git-smart-checkout.stacks`, same activity-bar container as Worktrees) follows the two-phase render pattern from `WorktreeTreeDataProvider`: fast phase 1 builds the forest topology from `StackStore` alone, phase 2 asynchronously enriches each branch with PR number/state, ahead/behind vs. parent, and a needs-restack flag (`NOT git merge-base --is-ancestor <parent-tip> <branch-tip>`). Detection itself is driven externally from `extension.ts` (`refreshStacks`, debounced on git state/config changes), not by the provider.
57
+
`StackWebViewProvider` (`src/view/`, view id `git-smart-checkout.stacks`, same activity-bar container as Worktrees) renders **only the stack containing the current branch** — data is pushed in via `setStack(view)`, the provider itself has no git/GitHub access. Detection is driven externally from `extension.ts` (`refreshStacks`, debounced on git state/config changes) via `StackService.refresh()`, which fetches the open-PR list **once** per refresh (shared by the webview and the status bar), unlike the tree-view era which fetched per branch.
54
58
55
-
`StatusBarManager` owns a second status bar item (priority = mode item's priority + 1, so it renders immediately to its left) showing `$(layers) <position>/<size>` for the current branch's stack, gated by `shouldShowStackIndicator` (pure, unit-tested) — hidden when stacks are disabled, the status bar is off, HEAD is detached, or the branch isn't stacked.
59
+
`StatusBarManager` owns a second status bar item (priority = mode item's priority + 1, so it renders immediately to its left) showing `$(layers) <position>/<size>` for the current branch's stack (`<size>` counts stacked PRs/branches only — the target is excluded, so sitting on the target itself shows no position), gated by `shouldShowStackIndicator` (pure, unit-tested) — hidden when stacks are disabled, the status bar is off, HEAD is detached (`isDetached` is a real signal from `StackService`, not derived from data presence), or the branch isn't stacked.
56
60
57
61
## WebView Integration
58
62
59
-
Two React-based webviews in `src/view/` (providers) + `src/webview/Apps/` (React roots):
63
+
Three React-based webviews in `src/view/` (providers) + `src/webview/Apps/` (React roots):
-**PR Commits** (`PrCommitsWebViewProvider` → `Apps/Commits/`) — commit list with per-commit selection for cherry-pick
67
+
-**Stacks** (`StackWebViewProvider` → `Apps/Stacks/`) — the current branch's PR stack (`StackList`/`StackRow`/`StackTargetChip`/`ContextMenu` components); click a row to check it out via `git-smart-checkout.checkoutBranch` (argument-only, not palette-visible — reuses `AutoStashService` through the shared `checkoutRefWithStash` tail), right-click for "Open PR in Browser". The target chip additionally shows a read-only `⇡N ⇣N` ahead/behind indicator (`StackView.targetAheadBehind`, sourced from `%(upstream:track)` the same way `WorktreeTreeDataProvider` does) and a "Fetch latest changes" icon button that runs `git-smart-checkout.fetchBranch` (argument-only; `GitExecutor.fetchSpecificBranch`) then re-refreshes
63
68
64
-
Webpack builds separate bundles (`main.js`, `commits.js`) via `webpack.webview.config.js`. WebView↔extension communication uses `postMessage` / `onDidReceiveMessage`. VS Code CSS variables handle theming.
69
+
`src/view/webviewHtml.ts` (`buildWebviewHtml`) is the single place that rewrites a built webview's HTML for use in a `WebviewView`: asset URIs, script nonce, and CSP injection — shared by all three providers. Webpack builds separate bundles (`main.js`, `commits.js`, `stacks.js`) via `webpack.webview.config.js`. WebView↔extension communication uses `postMessage` / `onDidReceiveMessage`. VS Code CSS variables handle theming.
Copy file name to clipboardExpand all lines: README.md
+3-3Lines changed: 3 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -40,7 +40,7 @@ All commands are grouped under the `GSC:` prefix in the Command Palette.
40
40
| Open a terminal in a selected worktree's directory |`GSC: Open Worktree Dev Terminal...`|[Open worktree dev terminal](docs/open-worktree-dev-terminal.md)|
41
41
| Remove several Git worktrees at once with a single confirmation |`GSC: Remove Multiple Worktrees...`|[Remove multiple worktrees](docs/remove-multiple-worktrees.md)|
42
42
| Browse all worktrees for the open repositories in a dedicated "Worktrees" view (activity bar), with dirty/ahead-behind/PR-review status and inline Open/Terminal/Copy WIP/Remove actions |*(tree view — right-click an item for Add to Workspace, Copy Path, Reveal in Finder/Explorer)*| — |
43
-
| Detect chains of dependent local branches ("stacks") from GitHub PR base chains and/or local ancestry, and browse them in a dedicated "Stacks" view (activity bar) with PR number, ahead/behind, and needs-restack status per branch. A status bar indicator (`$(layers) <position>/<size>`) shows where the current branch sits in its stack; click it to reveal the Stacks view. |*(tree view — passive, zero-config)*| —|
43
+
| Detect the chain of open GitHub PRs the current branch belongs to (a "stack"), and browse it in a dedicated "Stacks" view (activity bar) showing each PR's title and branch plus the branch the stack is ultimately targeting. Click a row (or its target chip) to check it out using the currently selected checkout/stash strategy; right-click for "Open PR in Browser". Falls back to a local-ancestry heuristic when there's no GitHub remote. A status bar indicator (`$(layers) <position>/<size>`) appears only while the current branch is part of a stack; click it to reveal the Stacks view. |`GSC: Refresh Stacks`|[Stacks](docs/stacks.md)|
44
44
| Create a new PR from selected commits in another GitHub PR |`GSC: Clone Pull Request...`|[GitHub PR clone](docs/github-pr-clone.md)|
45
45
| Generate and optionally push a tag from a reusable template |`GSC: Create Tag from Template...`|[Create tag from template](docs/create-tag-from-template.md)|
46
46
| Create and check out a branch from a template (Jira, file, regex, scripts) |`GSC: Create Branch from Template...`|[Create branch from template](docs/create-branch-from-template.md)|
@@ -83,8 +83,8 @@ Click a setting ID to open that setting in VS Code.
83
83
| ⚙️ [`git-smart-checkout.pushTagWithoutConfirmation`](vscode://settings/git-smart-checkout.pushTagWithoutConfirmation) (Push tag without confirmation) |`boolean`| Pushes the created Git tag to the remote without asking for confirmation. |
84
84
| ⚙️ [`git-smart-checkout.tagRemote`](vscode://settings/git-smart-checkout.tagRemote) (Tag remote) |`string`| Git remote used when pushing created tags. |
85
85
| ⚙️ [`git-smart-checkout.telemetry.enabled`](vscode://settings/git-smart-checkout.telemetry.enabled) (Telemetry enabled) |`boolean`| Enables anonymous Git Smart Checkout analytics while respecting VS Code's global telemetry settings. |
86
-
| ⚙️ [`git-smart-checkout.stacks.enabled`](vscode://settings/git-smart-checkout.stacks.enabled) (Stacks enabled) |`boolean`| Detects and visualizes stacks of dependent branches (Stacks view and status bar indicator). Default `true`. |
87
-
| ⚙️ [`git-smart-checkout.stacks.detection`](vscode://settings/git-smart-checkout.stacks.detection) (Stacks detection mode) |`string`| How stacks are detected. Available values: `auto` (default; GitHub PR base chains, falling back to the local ancestry heuristic), `github` (PR base chains only), `local` (local ancestry heuristic only, no GitHub API calls), `manual` (no automatic detection). |
86
+
| ⚙️ [`git-smart-checkout.stacks.enabled`](vscode://settings/git-smart-checkout.stacks.enabled) (Stacks enabled) |`boolean`| Detects and visualizes the current branch's PR stack (Stacks view and status bar indicator). Default `true`. |
87
+
| ⚙️ [`git-smart-checkout.stacks.detection`](vscode://settings/git-smart-checkout.stacks.detection) (Stacks detection mode) |`string`| How stacks are detected. Available values: `auto` (default; GitHub PR chains, falling back to the local ancestry heuristic only when GitHub data is unavailable), `github` (PR chains only, no heuristic fallback), `local` (local ancestry heuristic only, no GitHub API calls), `manual` (no automatic detection). |
Detects the chain of open GitHub pull requests the current branch belongs to (a "stack") and shows it in the "Stacks" view (Git Smart Checkout activity bar container), alongside a status bar indicator.
6
+
7
+
## What Counts as a Stack
8
+
9
+
A stack is a chain of open PRs linked `head -> base`, ending at a **target** branch that has no open PR of its own (often `main`, but it can be any branch — a release branch, another feature branch, etc.). For example:
- A single PR onto the default branch (trunk) is **not** a stack — that's just an ordinary PR.
20
+
- A single PR onto any other branch **is** a stack (the target chip is the point).
21
+
- Sitting on trunk itself never shows a stack.
22
+
- If a branch is the base of more than one open PR (a fork in the stack), the PR with the lowest number is followed; the others aren't shown.
23
+
24
+
## The Stacks View
25
+
26
+
Shows the stack containing the **current branch**, top PR first, target branch as a chip at the bottom. Each row shows the PR title and `#number · branch`; the current branch/target is highlighted.
27
+
28
+
-**Click a row (or the target chip)** to check out that branch, using whichever [stash mode](switch-mode.md) is currently active — including the manual prompt if that's what's configured.
29
+
-**Right-click a row** (or use the inline external-link icon) for "Open PR in Browser".
30
+
- The target chip shows **⇡N ⇣N** (commits waiting to be pushed / commits to pull), read directly from the branch's upstream tracking info — the same convention as the Worktrees view — whenever the target branch has an upstream configured. Next to it, a **fetch icon (⟳, "Fetch latest changes")** fetches the target branch from its remote (updating the remote-tracking ref only, no checkout, no merge) and refreshes the indicator.
31
+
- When the current branch isn't part of any stack, the view shows an empty state with a Refresh button.
32
+
33
+
## Status Bar Indicator
34
+
35
+
`$(layers) <position>/<size>` appears immediately to the left of the stash-mode item, but **only** while the current branch is part of a detected stack — it's hidden when stacks are disabled, the extension's status bar is off, HEAD is detached, or the branch simply isn't stacked. The count is of **stacked PRs (or heuristic branches) only** — the target branch doesn't count toward `<size>`, so sitting on the target itself shows no position (there's no PR there). Its tooltip lists the chain top-to-bottom with PR numbers/titles, plus the target branch on its own line. Click it to reveal the Stacks view.
36
+
37
+
## Detection Sources
38
+
39
+
Controlled by `git-smart-checkout.stacks.detection`:
40
+
41
+
| Value | Behavior |
42
+
| --- | --- |
43
+
|`auto` (default) | GitHub PR chains; falls back to the local ancestry heuristic only when GitHub data is genuinely unavailable (no GitHub remote/token, or the API call fails with no usable cache). |
44
+
|`github`| GitHub PR chains only — no heuristic fallback. |
45
+
|`local`| Local ancestry heuristic only (no GitHub API calls); useful offline or without a GitHub remote. |
46
+
|`manual`| No automatic detection. |
47
+
48
+
GitHub PR chains are **authoritative** — the two sources are never merged into one stack. The heuristic (closest ancestor branch by commit distance) is a fallback for when there's no usable PR data at all, so it never grafts extra branches onto a genuine PR stack.
0 commit comments