@gitkraken/core-gitlens 0.15.3 → 0.15.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +45 -1
- package/dist/git/cache.d.ts +28 -18
- package/dist/git/cache.js +71 -25
- package/dist/git/cache.js.map +1 -1
- package/dist/git/context.d.ts +19 -2
- package/dist/git/context.js.map +1 -1
- package/dist/git/models/pullRequest.d.ts +7 -5
- package/dist/git/models/pullRequest.js.map +1 -1
- package/dist/git/models/reference.d.ts +8 -0
- package/dist/git/providers/branches.d.ts +43 -0
- package/dist/git/providers/provider.d.ts +7 -0
- package/dist/git/service.d.ts +5 -1
- package/dist/git/service.js +8 -4
- package/dist/git/service.js.map +1 -1
- package/dist/git/watching/changeEvent.d.ts +29 -3
- package/dist/git/watching/changeEvent.js +39 -3
- package/dist/git/watching/changeEvent.js.map +1 -1
- package/dist/git/watching/configSections.d.ts +35 -0
- package/dist/git/watching/configSections.js +210 -0
- package/dist/git/watching/configSections.js.map +1 -0
- package/dist/git/watching/watchGroup.d.ts +37 -4
- package/dist/git/watching/watchGroup.js +108 -2
- package/dist/git/watching/watchGroup.js.map +1 -1
- package/dist/git/watching/watchService.d.ts +14 -3
- package/dist/git/watching/watchService.js +10 -7
- package/dist/git/watching/watchService.js.map +1 -1
- package/dist/git/watching/watchSession.d.ts +52 -20
- package/dist/git/watching/watchSession.js +166 -43
- package/dist/git/watching/watchSession.js.map +1 -1
- package/dist/git/watching/watcherPatterns.js +1 -0
- package/dist/git/watching/watcherPatterns.js.map +1 -1
- package/dist/git/watching/worktreeSummary.d.ts +21 -3
- package/dist/git/watching/worktreeSummary.js +118 -17
- package/dist/git/watching/worktreeSummary.js.map +1 -1
- package/dist/git-cli/cliGitProvider.d.ts +6 -1
- package/dist/git-cli/cliGitProvider.js +45 -5
- package/dist/git-cli/cliGitProvider.js.map +1 -1
- package/dist/git-cli/parsers/refParser.js +2 -1
- package/dist/git-cli/parsers/refParser.js.map +1 -1
- package/dist/git-cli/providers/branches.d.ts +10 -3
- package/dist/git-cli/providers/branches.js +99 -25
- package/dist/git-cli/providers/branches.js.map +1 -1
- package/dist/git-cli/providers/config.d.ts +45 -9
- package/dist/git-cli/providers/config.js +150 -24
- package/dist/git-cli/providers/config.js.map +1 -1
- package/dist/git-cli/providers/operations.d.ts +35 -1
- package/dist/git-cli/providers/operations.js +175 -16
- package/dist/git-cli/providers/operations.js.map +1 -1
- package/dist/git-cli/providers/stash.d.ts +1 -0
- package/dist/git-cli/providers/stash.js +9 -3
- package/dist/git-cli/providers/stash.js.map +1 -1
- package/dist/git-cli/providers/worktrees.js +11 -4
- package/dist/git-cli/providers/worktrees.js.map +1 -1
- package/dist/git-cli/service.js +5 -1
- package/dist/git-cli/service.js.map +1 -1
- package/dist/plus/integrations/models/gitHostIntegration.d.ts +29 -14
- package/dist/plus/integrations/models/gitHostIntegration.js +41 -19
- package/dist/plus/integrations/models/gitHostIntegration.js.map +1 -1
- package/dist/plus/integrations/providers/azure/azure.d.ts +16 -16
- package/dist/plus/integrations/providers/azure/azure.js +45 -25
- package/dist/plus/integrations/providers/azure/azure.js.map +1 -1
- package/dist/plus/integrations/providers/azure/azure.utils.d.ts +12 -0
- package/dist/plus/integrations/providers/azure/azure.utils.js +17 -1
- package/dist/plus/integrations/providers/azure/azure.utils.js.map +1 -1
- package/dist/plus/integrations/providers/azure/search.d.ts +4 -0
- package/dist/plus/integrations/providers/azure/search.js +46 -2
- package/dist/plus/integrations/providers/azure/search.js.map +1 -1
- package/dist/plus/integrations/providers/azure/workItemSearch.d.ts +11 -0
- package/dist/plus/integrations/providers/azure/workItemSearch.js +54 -0
- package/dist/plus/integrations/providers/azure/workItemSearch.js.map +1 -0
- package/dist/plus/integrations/providers/azure/workItemStateCategories.d.ts +2 -2
- package/dist/plus/integrations/providers/azure/workItemStateCategories.js +19 -15
- package/dist/plus/integrations/providers/azure/workItemStateCategories.js.map +1 -1
- package/dist/plus/integrations/providers/azureDevOps.d.ts +33 -20
- package/dist/plus/integrations/providers/azureDevOps.js +109 -48
- package/dist/plus/integrations/providers/azureDevOps.js.map +1 -1
- package/dist/plus/integrations/providers/azureDevOpsServer.d.ts +16 -47
- package/dist/plus/integrations/providers/azureDevOpsServer.js +52 -91
- package/dist/plus/integrations/providers/azureDevOpsServer.js.map +1 -1
- package/dist/plus/integrations/providers/issueSorts.d.ts +0 -1
- package/dist/plus/integrations/providers/models.d.ts +5 -0
- package/dist/plus/integrations/providers/models.js +14 -3
- package/dist/plus/integrations/providers/models.js.map +1 -1
- package/dist/plus/integrations/reads/drains.d.ts +2 -3
- package/dist/plus/integrations/reads/drains.js +4 -4
- package/dist/plus/integrations/reads/drains.js.map +1 -1
- package/dist/plus/integrations/reads/issues.js +7 -4
- package/dist/plus/integrations/reads/issues.js.map +1 -1
- package/dist/plus/integrations/reads/resolveRepository.js +5 -5
- package/dist/plus/integrations/reads/resolveRepository.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,48 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.15.5] - 2026-10-22
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- Adds optional `refs` and `options.configConfinedToRefs` to `GitServiceHooks.repository.onChanged`: `refs` are the full ref names a write created, moved or deleted, and a ref kind with names among them is fully described by them, so a host can skip work for refs it doesn't follow; `configConfinedToRefs` says the write changed `.git/config` only in the `branch.<name>` sections of the local branches `refs` names. Siblings sharing the repository hear the names and the flag with the shared kinds. Branch create, delete, rename and upstream changes, `checkout -b`, a worktree's new branch, a commit (its branch, read from the worktree's `HEAD` before and after the run, and named only when both agree) and stash writes (`refs/stash`, by a pop only when it dropped the entry) name their refs; a host that ignores them treats every kind as unnamed, as before (git, git-cli)
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- Changes how the watch layer tells a write's own reports from outside changes once announcements name refs: a raw report is the write's echo only when every ref it names, or every branch whose config section it changed, is among those the write announced (or it reports `HEAD`, which a commit locks, under a write that announced `head`), and it arrives within the debounce delay of the announcement, so an outside change to another ref or config section, or a later change to the same ref, is kept and reaches its subscribers unannounced. A watch group now diffs the shared `.git/config` by section on each report (one read for every worktree of the repository) and delivers a change confined to `branch.<name>` sections as confined to those branches (`WatcherRepoChangeEvent.configBranches`, `mayHaveChangedConfig`), whoever wrote it; anything else, an unreadable or unparsable file, a read that doesn't settle within 5 seconds, or another config file is unconfined. Ref-filtered subscriptions and worktree summaries narrow a confined change like a named ref (git)
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- Fixes worktree summaries keeping an outdated ahead-of-base target after checkout-specific Git configuration changes. Each checkout now compares its effective configuration, including branch-conditional includes, with the configuration used for its current base.
|
|
22
|
+
- Fixes a fetch announcing `remotes` to every worktree of the repository, and resetting the branch and tag caches, whether or not anything moved, so each worktree summary re-read its base after every fetch: in a Kepler daemon with ~60 worktrees one task launch cost ~490 git processes. A fetch now compares the refs it can write (its refspecs' destinations, the fetched remotes' configured destinations, symref targets included, and tags) before and after it runs, announces nothing when none moved, and otherwise names exactly what moved; a snapshot it can't read falls back to the previous announcement (git-cli)
|
|
23
|
+
- Fixes deleting, creating or renaming a branch making every worktree of the repository re-read its base, since the write's `.git/config` change and the watcher's later report of it reached every subscriber; one task removal cost ~460 git processes over ~60 worktrees (git, git-cli)
|
|
24
|
+
|
|
25
|
+
## [0.15.4] - 2026-10-22
|
|
26
|
+
|
|
27
|
+
### Added
|
|
28
|
+
|
|
29
|
+
- Adds an optional `getPushTarget` to `GitBranchesSubProvider`: where a branch (the checked-out one by default) pushes to and its upstream, each as a full ref name with its commit, read from the cached ref list so a warm call runs no git. The destination is git's own `%(push)`, which follows `push.default`, `remote.pushDefault`, `branch.<name>.pushRemote`, push refspecs and mirror remotes, and is named even before its ref exists (with no commit). `known: false` means the ref list couldn't be read; a detached HEAD has no destination. The shared `for-each-ref` now reads `%(push)` for every ref, so `RefRecord` gains a `push` field (git, git-cli)
|
|
30
|
+
- Adds an optional `getAheadOfBaseConfigKey` to `GitBranchesSubProvider`, an opaque snapshot of the Git config inputs to `getAheadOfBase` (every branch's tracking, the remotes and `init.defaultBranch`, not the stored gk merge targets or base): two equal snapshots mean that config can't have changed the base. `undefined` means it couldn't be read; the CLI provider reads it once for every worktree of a repository, and a provider without it leaves a worktree summary re-reading its base on every config change (git, git-cli)
|
|
31
|
+
|
|
32
|
+
### Changed
|
|
33
|
+
|
|
34
|
+
- Changes the `ref` that `WatchGroupHooks.onRepoChanged` and `RepositoryWatchSession.pushRepoChanges` take to `string | false`, where `false` reports a `.git/config` (or `config.worktree`) change that moved no ref. Its change kinds (`config`, `remotes`) still clear caches as before, but the event's `mayHaveChangedRef` no longer answers `true` for every remote-tracking ref because of it. A poll now also reads the `refs/remotes` directory, which `git remote remove` and `git remote rename` change whether the remote's refs are loose or packed, so a polled repository still reports a removed or renamed remote's refs as possibly moved, while a config write alone, like `git branch --set-upstream-to`, names no ref (git)
|
|
35
|
+
- Changes `getGkConfig`, `getGkConfigRegex`, `getStoredDetectedMergeTargetBranchName` and `getStoredUserMergeTargetBranchName` to log at trace level rather than debug, and a gk config lookup to no longer enter (and log) the one-time `.git/gk/config` migration once it ran for the repository: they are served from the cached map, and a cold read's `git config` still logs its own line (git-cli)
|
|
36
|
+
|
|
37
|
+
### Fixed
|
|
38
|
+
|
|
39
|
+
- Fixes Azure DevOps filtered work item searches failing across large sets of project workflows or when workflow metadata changes during pagination. Search and count queries stay within the server's query length limit, preserve its ordering, and can be canceled without interrupting other reads ([#6041](https://github.com/gitkraken/vscode-gitlens/issues/6041)).
|
|
40
|
+
- Fixes every checkout sharing a `.git/gk/config` re-reading the whole file (a `git config --get-regex` each) when the watcher reports a change to it, core's own writes included, so a branch-activity stamp reported by three checkouts read it four times. A report of a file unchanged since the cached map was read (same inode, size and change times, with the read's stat taken safely after the file's last change: 2 seconds for a filesystem keeping whole-second times, 50 ms otherwise) now keeps the map, and still diffs it against the reconcile's baseline, so a read landing between another process's write and its report doesn't lose the change; a changed file is re-read as before (git, git-cli)
|
|
41
|
+
- Fixes `getAheadOfBase` spawning a failing `git rev-parse <ref>@{u}` on every read whose candidate base is a remote-tracking ref or a tag (`origin/main`, the usual default branch), since git can't cache a failed lookup: a candidate the cached ref list shows can't have an upstream is no longer asked for one, and the result is unchanged. The base a branch's reflog says it was created from is checked the same way (git-cli)
|
|
42
|
+
- Fixes a `.git/config` write making every subscribed worktree summary of the repository re-read its base at once, a full `getAheadOfBase` each: in a Kepler daemon over ~100 worktrees of one repository, one write cost ~65 reads in a burst. A summary now keeps its base when the config inputs to it (every branch's tracking, the remotes and `init.defaultBranch`), its stored merge targets, HEAD and upstream are unchanged, and at most four summaries of a repository, and eight across repositories, read at once, so a burst in one repository, or reads hung in it, never holds up another repository's summaries, and a start over many repositories never runs four reads for each. The config read itself (`git config --null --get-regexp`) is shared by every worktree of the repository rather than spawned by each, and any config change hard-evicts it, core's own writes included, so a read after the change never joins one that started before it (git, git-cli)
|
|
43
|
+
- Fixes Azure DevOps Services account-wide pull request reads (`listPullRequestsPage`, the sweeps and the Launchpad search) returning no authored or review-requested pull requests, and failing the group read with "Azure DevOps returned no group membership for the current user", for accounts whose profile id differs from their identity in an organization: the creator and reviewer filters, the group read and each row's `viewer` and `authoredByMe` now use the user's identity in that organization, read from its `ConnectionData` once per credential and organization (in parallel, dropped on a re-sync), as Azure DevOps Server already did per collection; `getPullRequestsBatch` and `getPullRequestsForBranches` match authorship the same way. An organization whose identity can't be read is reported as a failure scoped to it while the others' pull requests are kept, as Azure DevOps Server already did per collection; an organization or collection refusing the credential (a 401 or 403) is now scoped the same way, where it failed the whole read, and a credential refused everywhere still fails it. A row with reviewers or assignees but no author now gets a `viewer`, and its `authoredByMe` is `undefined` rather than `false`, for every provider ([#6032](https://github.com/gitkraken/vscode-gitlens/issues/6032)) (plus/integrations)
|
|
44
|
+
- Fixes Azure DevOps Server repository scopes that a caller parsed from a remote. Before, they were settled once to order `listIssuesPage` and then again for the read. Now the read gets the scopes that were counted, and a discovery that expires in between can't change them. Other fixes in the same reads:
|
|
45
|
+
- A scope that settles to a repository the connection doesn't serve is read as given and flagged as unsettled. A batch or branch miss for it is now rejected, and a list read reports it in a warning, instead of reporting a proven absence.
|
|
46
|
+
- When the connection addresses a collection, a scope naming that collection is read as given while the collection list can't be read. Before, it was flagged as unsettled, and its batch and branch misses were rejected. The address is presumed to name a collection when its collection list answers 404 and the collection's own connection data can't be read, for as long as that failed discovery is kept.
|
|
47
|
+
- A connection path segment with an encoded `/` no longer splits into two virtual directory segments, which left a scope below it unsettled.
|
|
48
|
+
|
|
49
|
+
`resolveRepositoryScopes` now returns `{ repos, unsettled }`. A failure to settle is reported as `{ error }` instead of returning the scopes as given ([#6040](https://github.com/gitkraken/vscode-gitlens/issues/6040)) (plus/integrations)
|
|
50
|
+
|
|
9
51
|
## [0.15.3] - 2026-10-21
|
|
10
52
|
|
|
11
53
|
### Fixed
|
|
@@ -804,7 +846,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
|
|
|
804
846
|
|
|
805
847
|
- Initial release. Bundles `@gitlens/utils`, `@gitlens/git`, `@gitlens/git-cli`, `@gitlens/ai`, and `@gitlens/git-github` into a single core npm package with subpath exports.
|
|
806
848
|
|
|
807
|
-
[unreleased]: https://github.com/gitkraken/vscode-gitlens/compare/releases/core/v0.15.
|
|
849
|
+
[unreleased]: https://github.com/gitkraken/vscode-gitlens/compare/releases/core/v0.15.5...HEAD
|
|
850
|
+
[0.15.5]: https://github.com/gitkraken/vscode-gitlens/compare/releases/core/v0.15.4...gitkraken:releases/core/v0.15.5
|
|
851
|
+
[0.15.4]: https://github.com/gitkraken/vscode-gitlens/compare/releases/core/v0.15.3...gitkraken:releases/core/v0.15.4
|
|
808
852
|
[0.15.3]: https://github.com/gitkraken/vscode-gitlens/compare/releases/core/v0.15.2...gitkraken:releases/core/v0.15.3
|
|
809
853
|
[0.15.2]: https://github.com/gitkraken/vscode-gitlens/compare/releases/core/v0.15.1...gitkraken:releases/core/v0.15.2
|
|
810
854
|
[0.15.1]: https://github.com/gitkraken/vscode-gitlens/compare/releases/core/v0.15.0...gitkraken:releases/core/v0.15.1
|
package/dist/git/cache.d.ts
CHANGED
|
@@ -109,6 +109,7 @@ export declare class Cache implements Disposable {
|
|
|
109
109
|
dispose(): void;
|
|
110
110
|
/** Resource usage retained by instantiated sub-caches and their bookkeeping maps. */
|
|
111
111
|
getResourceUsage(): ResourceUsage;
|
|
112
|
+
get aheadOfBaseConfigKey(): PromiseMap<RepoPath, string | undefined>;
|
|
112
113
|
get bestRemotes(): PromiseMap<RepoPath, GitRemote<RemoteProvider>[]>;
|
|
113
114
|
get blame(): RepoPromiseCacheMap<string, ProgressiveGitBlame | undefined>;
|
|
114
115
|
get diff(): RepoPromiseCacheMap<string, ParsedGitDiffHunks | undefined>;
|
|
@@ -237,17 +238,17 @@ export declare class Cache implements Disposable {
|
|
|
237
238
|
* Call this when a worktree is deleted or a repo is closed so stale registry entries
|
|
238
239
|
* and derived cache entries don't persist.
|
|
239
240
|
*
|
|
240
|
-
* Targeted — does NOT cascade to sibling worktrees sharing the same commonPath.
|
|
241
|
-
*
|
|
242
|
-
*
|
|
243
|
-
*
|
|
244
|
-
*
|
|
241
|
+
* Targeted — does NOT cascade to sibling worktrees sharing the same commonPath. Shared caches
|
|
242
|
+
* stay warm until the last worktree closes, except raw git results co-located with a closing main
|
|
243
|
+
* checkout: those must retire with its config fingerprint so reopening cannot attest an old command
|
|
244
|
+
* with new config. Detached promises keep their existing callers and abort wiring. Other entries
|
|
245
|
+
* use soft-invalidate where supported so any in-flight factory/mapper keeps its abort
|
|
245
246
|
* wiring intact — a caller whose signal aborts after unregister can still propagate
|
|
246
247
|
* cancellation into the underlying work rather than leaving it orphaned. Controller-backed
|
|
247
248
|
* entries self-evict on settle; plain `.set()`-based entries hard-delete immediately.
|
|
248
249
|
*
|
|
249
|
-
*
|
|
250
|
-
*
|
|
250
|
+
* The status clock advances even for an unregistered path so a fresh registration cannot join a
|
|
251
|
+
* status read that started before it.
|
|
251
252
|
*/
|
|
252
253
|
unregisterRepoPath(repoPath: string): void;
|
|
253
254
|
reset(): void;
|
|
@@ -267,12 +268,12 @@ export declare class Cache implements Disposable {
|
|
|
267
268
|
worktreeOnly?: boolean;
|
|
268
269
|
}): CachedGitTypes[];
|
|
269
270
|
/**
|
|
270
|
-
* Handles a watcher-observed `'gkConfig'` change.
|
|
271
|
-
*
|
|
272
|
-
*
|
|
273
|
-
*
|
|
274
|
-
*
|
|
275
|
-
*
|
|
271
|
+
* Handles a watcher-observed `'gkConfig'` change. If a reconciler is registered (see {@link setGkConfigReconciler}),
|
|
272
|
+
* defers to it instead of coarsely clearing `baseBranchName`/`branchOverviews` — it evicts the cached bulk map
|
|
273
|
+
* unless the file is unchanged since the map was read, reads it, and diffs it against the snapshot captured here
|
|
274
|
+
* (i.e. as it stood right before this change), cascading only the refs whose merge-relevant keys actually
|
|
275
|
+
* changed. Falls back to evicting the map and the coarse clear when no reconciler is registered (e.g. the GitHub
|
|
276
|
+
* provider) so nothing can go stale.
|
|
276
277
|
*/
|
|
277
278
|
private handleGkConfigChanged;
|
|
278
279
|
/**
|
|
@@ -298,9 +299,9 @@ export declare class Cache implements Disposable {
|
|
|
298
299
|
/**
|
|
299
300
|
* The whole `.git/gk/config` is read once and cached as a single map per commonPath; per-key and
|
|
300
301
|
* per-namespace gk lookups are served from it in-memory (see `getGkConfigMap` in the CLI config
|
|
301
|
-
* sub-provider). Invalidated by `deleteGkConfig` (write) and, on a watcher `'gkConfig'` event, by
|
|
302
|
-
*
|
|
303
|
-
* clear
|
|
302
|
+
* sub-provider). Invalidated by `deleteGkConfig` (write) and, on a watcher `'gkConfig'` event, by the
|
|
303
|
+
* reconciler when the file changed since the map was read (see {@link setGkConfigReconciler}), or by
|
|
304
|
+
* `handleGkConfigChanged`'s coarse clear when none is registered. The first fresh read seeds the snapshot used by
|
|
304
305
|
* `reconcileGkConfigMap`; later refreshes of that snapshot are owned by the reconcile itself.
|
|
305
306
|
*/
|
|
306
307
|
getGkConfigMap(repoPath: string, factory: (cacheable: CacheController) => PromiseOrValue<Map<string, string>>): Promise<Map<string, string>>;
|
|
@@ -343,11 +344,18 @@ export declare class Cache implements Disposable {
|
|
|
343
344
|
* `'gkConfig'` change. Only one reconciler is kept — later registrations replace earlier ones,
|
|
344
345
|
* which is harmless since every CLI config sub-provider sharing this `Cache` reconciles the same
|
|
345
346
|
* underlying `.git/gk/config` file identically.
|
|
347
|
+
*
|
|
348
|
+
* The reconciler owns the cached bulk map: it is called synchronously as the change is reported, and must
|
|
349
|
+
* hard-delete the map ({@link deleteGkConfigMap}) before it returns unless it knows the map still reflects the
|
|
350
|
+
* file — a read after the change must see it, and the reconcile's own read must not ride a bulk read that
|
|
351
|
+
* started before it. Only the reconciler can inspect the file, and keeping the map spares a re-read for every
|
|
352
|
+
* report of an unchanged file (one per worktree sharing it, and one for each of core's own writes).
|
|
346
353
|
*/
|
|
347
354
|
setGkConfigReconciler(reconciler: (repoPath: string, priorSnapshot: ReadonlyMap<string, string> | undefined) => PromiseOrValue<GkReconcileOutcome>): void;
|
|
348
355
|
/**
|
|
349
|
-
* Diffs a
|
|
350
|
-
* `handleGkConfigChanged` before the reconcile started, so it reflects the
|
|
356
|
+
* Diffs the tracked subset of a gk config map (read after the change, or kept as still reflecting the file)
|
|
357
|
+
* against `priorSnapshot` (captured by `handleGkConfigChanged` before the reconcile started, so it reflects the
|
|
358
|
+
* pre-change state), cascading
|
|
351
359
|
* `baseBranchName`/`branchOverviews` for every ref whose merge-relevant key actually changed, then firing
|
|
352
360
|
* {@link onDidChangeMergeTargets} naming those refs. Changed branch metadata keys (another process's
|
|
353
361
|
* activity stamps or disposition) are patched into the cached branches in one call, and never fire the event.
|
|
@@ -415,6 +423,8 @@ export declare class Cache implements Disposable {
|
|
|
415
423
|
*/
|
|
416
424
|
deleteBranchMetadata(repoPath: string): void;
|
|
417
425
|
getBranchMergedStatus(repoPath: string, cacheKey: string, factory: (commonPath: string, cacheable: CacheController, cancellation?: AbortSignal) => PromiseOrValue<GitBranchMergedStatus>, cancellation?: AbortSignal): Promise<GitBranchMergedStatus>;
|
|
426
|
+
/** Config can differ by checkout through config.worktree and conditional includes. */
|
|
427
|
+
getAheadOfBaseConfigKey(repoPath: string, factory: (repoPath: string, cacheable: CacheController, cancellation?: AbortSignal) => PromiseOrValue<string | undefined>, cancellation?: AbortSignal): Promise<string | undefined>;
|
|
418
428
|
getBranchMetadataMap(repoPath: string, factory: (commonPath: string) => PromiseOrValue<Map<string, BranchMetadata>>): Promise<Map<string, BranchMetadata>>;
|
|
419
429
|
getDefaultBranchName(repoPath: string, remote: string, factory: (commonPath: string, cacheable: CacheController, cancellation?: AbortSignal) => PromiseOrValue<string | undefined>, cancellation?: AbortSignal): Promise<string | undefined>;
|
|
420
430
|
/** Clears the cached default branch for one `remote` key (the networked lookup or its `:local` variant). */
|
package/dist/git/cache.js
CHANGED
|
@@ -81,6 +81,7 @@ const sharedCacheKeys = new Set(exhaustiveArray()([
|
|
|
81
81
|
]));
|
|
82
82
|
function createEmptyCaches() {
|
|
83
83
|
return {
|
|
84
|
+
aheadOfBaseConfigKey: void 0,
|
|
84
85
|
baseBranchName: void 0,
|
|
85
86
|
bestRemotes: void 0,
|
|
86
87
|
blame: void 0,
|
|
@@ -183,6 +184,9 @@ var Cache = class Cache {
|
|
|
183
184
|
usage["cache.gkConfigSnapshots.entries.count"] = this._gkConfigSnapshots.size;
|
|
184
185
|
return usage;
|
|
185
186
|
}
|
|
187
|
+
get aheadOfBaseConfigKey() {
|
|
188
|
+
return this._caches.aheadOfBaseConfigKey ??= new PromiseMap();
|
|
189
|
+
}
|
|
186
190
|
get bestRemotes() {
|
|
187
191
|
return this._caches.bestRemotes ??= new PromiseMap();
|
|
188
192
|
}
|
|
@@ -414,7 +418,10 @@ var Cache = class Cache {
|
|
|
414
418
|
keysToClear.add("reachability");
|
|
415
419
|
keysToClear.add("resolvedRevisions");
|
|
416
420
|
}
|
|
417
|
-
if (types.includes("branch"))
|
|
421
|
+
if (types.includes("branch")) {
|
|
422
|
+
keysToClear.add("aheadOfBaseConfigKey");
|
|
423
|
+
keysToClear.add("baseBranchName");
|
|
424
|
+
}
|
|
418
425
|
if (types.includes("branches")) {
|
|
419
426
|
keysToClear.add("branchMetadataMap");
|
|
420
427
|
keysToClear.add("branches");
|
|
@@ -426,6 +433,7 @@ var Cache = class Cache {
|
|
|
426
433
|
keysToClear.add("refTips");
|
|
427
434
|
}
|
|
428
435
|
if (types.includes("config")) {
|
|
436
|
+
keysToClear.add("aheadOfBaseConfigKey");
|
|
429
437
|
keysToClear.add("baseBranchName");
|
|
430
438
|
keysToClear.add("configKeys");
|
|
431
439
|
keysToClear.add("configPatterns");
|
|
@@ -482,8 +490,12 @@ var Cache = class Cache {
|
|
|
482
490
|
const cache = this._caches[key];
|
|
483
491
|
if (cache == null) continue;
|
|
484
492
|
if (repoPath == null) cache.clear();
|
|
493
|
+
else if (key === "aheadOfBaseConfigKey" && !worktreeOnly && (!types.length || types.includes("config"))) this.evictShared(key, repoPath, "evict");
|
|
485
494
|
else if (sharedCacheKeys.has(key)) {
|
|
486
|
-
if (!worktreeOnly)
|
|
495
|
+
if (!worktreeOnly) {
|
|
496
|
+
const hardEvict = key === "gitResults" && (types.includes("config") || types.includes("branch"));
|
|
497
|
+
this.evictShared(key, repoPath, hardEvict ? "evict" : inFlight);
|
|
498
|
+
}
|
|
487
499
|
} else cache.delete(repoPath);
|
|
488
500
|
}
|
|
489
501
|
}
|
|
@@ -590,6 +602,12 @@ var Cache = class Cache {
|
|
|
590
602
|
registerRepoPath(repoPath, gitDir) {
|
|
591
603
|
const normalizedPath = getRepositoryOrWorktreePath(repoPath);
|
|
592
604
|
const commonPath = gitDir.commonUri != null ? getCommonRepositoryPath(gitDir.commonUri) : normalizedPath;
|
|
605
|
+
const previousCommonPath = this._commonPathRegistry.get(normalizedPath);
|
|
606
|
+
if (previousCommonPath != null && previousCommonPath !== commonPath) this.unregisterRepoPath(normalizedPath);
|
|
607
|
+
if (previousCommonPath !== commonPath) {
|
|
608
|
+
this._caches.aheadOfBaseConfigKey?.delete(normalizedPath);
|
|
609
|
+
this._caches.gitResults?.delete(normalizedPath);
|
|
610
|
+
}
|
|
593
611
|
this._commonPathRegistry.set(normalizedPath, commonPath);
|
|
594
612
|
let worktrees = this._worktreesByCommonPath.get(commonPath);
|
|
595
613
|
if (worktrees == null) {
|
|
@@ -605,17 +623,17 @@ var Cache = class Cache {
|
|
|
605
623
|
* Call this when a worktree is deleted or a repo is closed so stale registry entries
|
|
606
624
|
* and derived cache entries don't persist.
|
|
607
625
|
*
|
|
608
|
-
* Targeted — does NOT cascade to sibling worktrees sharing the same commonPath.
|
|
609
|
-
*
|
|
610
|
-
*
|
|
611
|
-
*
|
|
612
|
-
*
|
|
626
|
+
* Targeted — does NOT cascade to sibling worktrees sharing the same commonPath. Shared caches
|
|
627
|
+
* stay warm until the last worktree closes, except raw git results co-located with a closing main
|
|
628
|
+
* checkout: those must retire with its config fingerprint so reopening cannot attest an old command
|
|
629
|
+
* with new config. Detached promises keep their existing callers and abort wiring. Other entries
|
|
630
|
+
* use soft-invalidate where supported so any in-flight factory/mapper keeps its abort
|
|
613
631
|
* wiring intact — a caller whose signal aborts after unregister can still propagate
|
|
614
632
|
* cancellation into the underlying work rather than leaving it orphaned. Controller-backed
|
|
615
633
|
* entries self-evict on settle; plain `.set()`-based entries hard-delete immediately.
|
|
616
634
|
*
|
|
617
|
-
*
|
|
618
|
-
*
|
|
635
|
+
* The status clock advances even for an unregistered path so a fresh registration cannot join a
|
|
636
|
+
* status read that started before it.
|
|
619
637
|
*/
|
|
620
638
|
unregisterRepoPath(repoPath) {
|
|
621
639
|
this.incrementStatusGeneration(repoPath);
|
|
@@ -626,6 +644,11 @@ var Cache = class Cache {
|
|
|
626
644
|
for (const key of Object.keys(this._caches)) {
|
|
627
645
|
const cache = this._caches[key];
|
|
628
646
|
if (cache == null) continue;
|
|
647
|
+
if (key === "aheadOfBaseConfigKey" || key === "gitResults") {
|
|
648
|
+
cache.delete(repoPath);
|
|
649
|
+
if (key === "gitResults" && isLastWorktree && repoPath !== commonPath) cache.delete(commonPath);
|
|
650
|
+
continue;
|
|
651
|
+
}
|
|
629
652
|
const invalidate = cache.invalidate;
|
|
630
653
|
const evict = typeof invalidate === "function" ? (k) => invalidate.call(cache, k) : (k) => cache.delete(k);
|
|
631
654
|
if (sharedCacheKeys.has(key)) {
|
|
@@ -681,7 +704,11 @@ var Cache = class Cache {
|
|
|
681
704
|
types.add("fileLog");
|
|
682
705
|
}
|
|
683
706
|
if (hasAny("index")) types.add("tracking");
|
|
684
|
-
if (hasAny("config"))
|
|
707
|
+
if (hasAny("config")) {
|
|
708
|
+
types.add("config");
|
|
709
|
+
types.add("branches");
|
|
710
|
+
types.add("worktrees");
|
|
711
|
+
}
|
|
685
712
|
if (hasAny("heads")) {
|
|
686
713
|
types.add("branches");
|
|
687
714
|
types.add("contributors");
|
|
@@ -708,22 +735,30 @@ var Cache = class Cache {
|
|
|
708
735
|
return [...types];
|
|
709
736
|
}
|
|
710
737
|
/**
|
|
711
|
-
* Handles a watcher-observed `'gkConfig'` change.
|
|
712
|
-
*
|
|
713
|
-
*
|
|
714
|
-
*
|
|
715
|
-
*
|
|
716
|
-
*
|
|
738
|
+
* Handles a watcher-observed `'gkConfig'` change. If a reconciler is registered (see {@link setGkConfigReconciler}),
|
|
739
|
+
* defers to it instead of coarsely clearing `baseBranchName`/`branchOverviews` — it evicts the cached bulk map
|
|
740
|
+
* unless the file is unchanged since the map was read, reads it, and diffs it against the snapshot captured here
|
|
741
|
+
* (i.e. as it stood right before this change), cascading only the refs whose merge-relevant keys actually
|
|
742
|
+
* changed. Falls back to evicting the map and the coarse clear when no reconciler is registered (e.g. the GitHub
|
|
743
|
+
* provider) so nothing can go stale.
|
|
717
744
|
*/
|
|
718
745
|
handleGkConfigChanged(repoPath) {
|
|
719
746
|
const commonPath = this.getCommonPath(repoPath);
|
|
720
|
-
this._caches.gkConfigMap?.delete(commonPath);
|
|
721
747
|
if (this._gkConfigReconciler == null) {
|
|
748
|
+
this._caches.gkConfigMap?.delete(commonPath);
|
|
722
749
|
this.clearGkConfigCoarsely(repoPath);
|
|
723
750
|
return;
|
|
724
751
|
}
|
|
725
752
|
const priorSnapshot = this._gkConfigSnapshots.get(commonPath);
|
|
726
|
-
|
|
753
|
+
let outcome;
|
|
754
|
+
try {
|
|
755
|
+
outcome = this._gkConfigReconciler(repoPath, priorSnapshot);
|
|
756
|
+
} catch {
|
|
757
|
+
this._caches.gkConfigMap?.delete(commonPath);
|
|
758
|
+
this.clearGkConfigCoarsely(repoPath);
|
|
759
|
+
return;
|
|
760
|
+
}
|
|
761
|
+
Promise.resolve(outcome).then((outcome) => {
|
|
727
762
|
if (outcome === "failed") this.clearGkConfigCoarsely(repoPath);
|
|
728
763
|
}, () => this.clearGkConfigCoarsely(repoPath));
|
|
729
764
|
}
|
|
@@ -798,9 +833,9 @@ var Cache = class Cache {
|
|
|
798
833
|
/**
|
|
799
834
|
* The whole `.git/gk/config` is read once and cached as a single map per commonPath; per-key and
|
|
800
835
|
* per-namespace gk lookups are served from it in-memory (see `getGkConfigMap` in the CLI config
|
|
801
|
-
* sub-provider). Invalidated by `deleteGkConfig` (write) and, on a watcher `'gkConfig'` event, by
|
|
802
|
-
*
|
|
803
|
-
* clear
|
|
836
|
+
* sub-provider). Invalidated by `deleteGkConfig` (write) and, on a watcher `'gkConfig'` event, by the
|
|
837
|
+
* reconciler when the file changed since the map was read (see {@link setGkConfigReconciler}), or by
|
|
838
|
+
* `handleGkConfigChanged`'s coarse clear when none is registered. The first fresh read seeds the snapshot used by
|
|
804
839
|
* `reconcileGkConfigMap`; later refreshes of that snapshot are owned by the reconcile itself.
|
|
805
840
|
*/
|
|
806
841
|
getGkConfigMap(repoPath, factory) {
|
|
@@ -877,13 +912,20 @@ var Cache = class Cache {
|
|
|
877
912
|
* `'gkConfig'` change. Only one reconciler is kept — later registrations replace earlier ones,
|
|
878
913
|
* which is harmless since every CLI config sub-provider sharing this `Cache` reconciles the same
|
|
879
914
|
* underlying `.git/gk/config` file identically.
|
|
915
|
+
*
|
|
916
|
+
* The reconciler owns the cached bulk map: it is called synchronously as the change is reported, and must
|
|
917
|
+
* hard-delete the map ({@link deleteGkConfigMap}) before it returns unless it knows the map still reflects the
|
|
918
|
+
* file — a read after the change must see it, and the reconcile's own read must not ride a bulk read that
|
|
919
|
+
* started before it. Only the reconciler can inspect the file, and keeping the map spares a re-read for every
|
|
920
|
+
* report of an unchanged file (one per worktree sharing it, and one for each of core's own writes).
|
|
880
921
|
*/
|
|
881
922
|
setGkConfigReconciler(reconciler) {
|
|
882
923
|
this._gkConfigReconciler = reconciler;
|
|
883
924
|
}
|
|
884
925
|
/**
|
|
885
|
-
* Diffs a
|
|
886
|
-
* `handleGkConfigChanged` before the reconcile started, so it reflects the
|
|
926
|
+
* Diffs the tracked subset of a gk config map (read after the change, or kept as still reflecting the file)
|
|
927
|
+
* against `priorSnapshot` (captured by `handleGkConfigChanged` before the reconcile started, so it reflects the
|
|
928
|
+
* pre-change state), cascading
|
|
887
929
|
* `baseBranchName`/`branchOverviews` for every ref whose merge-relevant key actually changed, then firing
|
|
888
930
|
* {@link onDidChangeMergeTargets} naming those refs. Changed branch metadata keys (another process's
|
|
889
931
|
* activity stamps or disposition) are patched into the cached branches in one call, and never fire the event.
|
|
@@ -1083,6 +1125,10 @@ var Cache = class Cache {
|
|
|
1083
1125
|
};
|
|
1084
1126
|
}, { cancellation });
|
|
1085
1127
|
}
|
|
1128
|
+
/** Config can differ by checkout through config.worktree and conditional includes. */
|
|
1129
|
+
getAheadOfBaseConfigKey(repoPath, factory, cancellation) {
|
|
1130
|
+
return this.aheadOfBaseConfigKey.getOrCreate(repoPath, (cacheable, signal) => Promise.resolve(factory(repoPath, cacheable, signal)), cancellation);
|
|
1131
|
+
}
|
|
1086
1132
|
getBranchMetadataMap(repoPath, factory) {
|
|
1087
1133
|
return this.getSharedSimple(this.branchMetadataMap, repoPath, factory);
|
|
1088
1134
|
}
|
|
@@ -1176,10 +1222,10 @@ var Cache = class Cache {
|
|
|
1176
1222
|
}
|
|
1177
1223
|
return sharedPromise;
|
|
1178
1224
|
}
|
|
1179
|
-
async getSharedSimple(cache, repoPath, factory) {
|
|
1225
|
+
async getSharedSimple(cache, repoPath, factory, cancellation) {
|
|
1180
1226
|
const commonPath = this.getCommonPath(repoPath);
|
|
1181
1227
|
if (cache instanceof PromiseCache) return cache.getOrCreate(commonPath, (cacheable) => Promise.resolve(factory(commonPath, cacheable)));
|
|
1182
|
-
return cache.getOrCreate(commonPath, (cacheable) => Promise.resolve(factory(commonPath, cacheable)));
|
|
1228
|
+
return cache.getOrCreate(commonPath, (cacheable, signal) => Promise.resolve(factory(commonPath, cacheable, signal)), cancellation);
|
|
1183
1229
|
}
|
|
1184
1230
|
async getSharedSimpleWithKey(cache, repoPath, cacheKey, factory, options) {
|
|
1185
1231
|
const commonPath = this.getCommonPath(repoPath);
|