@gitkraken/core-gitlens 0.15.4 → 0.15.6
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 +25 -1
- package/dist/git/cache.d.ts +9 -12
- package/dist/git/cache.js +34 -16
- 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/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 +25 -1
- package/dist/git/watching/changeEvent.js +36 -2
- 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 +36 -3
- package/dist/git/watching/watchGroup.js +107 -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 -21
- package/dist/git/watching/watchSession.js +164 -42
- package/dist/git/watching/watchSession.js.map +1 -1
- package/dist/git/watching/worktreeSummary.d.ts +9 -7
- package/dist/git/watching/worktreeSummary.js +21 -10
- 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/providers/branches.d.ts +2 -2
- package/dist/git-cli/providers/branches.js +17 -15
- package/dist/git-cli/providers/branches.js.map +1 -1
- package/dist/git-cli/providers/config.d.ts +13 -0
- package/dist/git-cli/providers/config.js +38 -1
- 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/collectionMetadata.js +4 -2
- package/dist/plus/integrations/collectionMetadata.js.map +1 -1
- package/dist/plus/integrations/providers/issueSorts.d.ts +0 -1
- package/dist/plus/integrations/providers/providerErrors.d.ts +22 -0
- package/dist/plus/integrations/providers/providerErrors.js +43 -2
- package/dist/plus/integrations/providers/providerErrors.js.map +1 -1
- package/dist/plus/integrations/providers/providersApi.js +12 -8
- package/dist/plus/integrations/providers/providersApi.js.map +1 -1
- package/dist/plus/integrations/reads/drains.d.ts +0 -1
- package/dist/plus/integrations/results.d.ts +13 -3
- package/dist/plus/integrations/results.js +12 -2
- package/dist/plus/integrations/results.js.map +1 -1
- package/docs/integrations.md +14 -0
- package/package.json +1 -1
|
@@ -2,10 +2,12 @@ import { chunkByStringLength } from "../../utils/iterable.js";
|
|
|
2
2
|
import { Logger as _logger } from "../../utils/logger.js";
|
|
3
3
|
import { getScopedLogger } from "../../utils/logger.scoped.js";
|
|
4
4
|
import { debug } from "../../utils/decorators/log.js";
|
|
5
|
+
import { joinUriPath } from "../../utils/uri.js";
|
|
5
6
|
import { normalizePath, splitPath } from "../../utils/path.js";
|
|
6
7
|
import { isBranchReference } from "../../git/utils/reference.utils.js";
|
|
7
8
|
import __decorate from "../../_virtual/@oxc-project+runtime/helpers/esm/decorate.js";
|
|
8
9
|
import { CheckoutError, CherryPickError, CommitError, FetchError, MergeError, PullError, PushError, RebaseError, ResetError, RevertError, SigningError } from "../../git/errors.js";
|
|
10
|
+
import { getRefChangeKind } from "../../git/watching/changeEvent.js";
|
|
9
11
|
import { mayWriteTracking } from "../exec/commandClassifier.js";
|
|
10
12
|
import { GitErrors, classifySigningError, getGitCommandError, gitConfigsPull, inferSigningFormatFromError, isRunHookFailure, maxGitCliLength } from "../exec/git.js";
|
|
11
13
|
import { resolveBranchRemote } from "./branchRemote.js";
|
|
@@ -13,6 +15,51 @@ import { parseGitBoolean } from "./config.js";
|
|
|
13
15
|
import { sequentialize } from "../../utils/decorators/sequentialize.js";
|
|
14
16
|
import * as l10n from "@vscode/l10n";
|
|
15
17
|
//#region ../git-cli/src/providers/operations.ts
|
|
18
|
+
/** The ref kinds a fetch can move, in the order its announcement lists them */
|
|
19
|
+
const fetchRefChangeKinds = [
|
|
20
|
+
"remotes",
|
|
21
|
+
"heads",
|
|
22
|
+
"tags",
|
|
23
|
+
"stash"
|
|
24
|
+
];
|
|
25
|
+
/** The destinations a fetch's snapshot covers when the remotes' configured refspecs can't be read */
|
|
26
|
+
const broadFetchDestinations = ["refs/heads", "refs/remotes"];
|
|
27
|
+
/**
|
|
28
|
+
* The ref a fetch refspec stores into, qualified as git's fetch does — `heads/`, `tags/` and `remotes/` get `refs/`,
|
|
29
|
+
* and any other unqualified name is a local branch — or `undefined` when it stores nothing (no `:`, or nothing after
|
|
30
|
+
* it). A glob destination keeps its glob.
|
|
31
|
+
*/
|
|
32
|
+
function getRefspecDestination(refspec) {
|
|
33
|
+
const stripped = refspec.startsWith("+") ? refspec.slice(1) : refspec;
|
|
34
|
+
const colonIndex = stripped.indexOf(":");
|
|
35
|
+
if (colonIndex === -1) return void 0;
|
|
36
|
+
const destination = stripped.slice(colonIndex + 1);
|
|
37
|
+
if (!destination) return void 0;
|
|
38
|
+
if (destination.startsWith("refs/")) return destination;
|
|
39
|
+
return /^(?:heads|tags|remotes)\//.test(destination) ? `refs/${destination}` : `refs/heads/${destination}`;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* The for-each-ref patterns covering `destinations` (the refs a fetch may store into) and tags, which a fetch follows
|
|
43
|
+
* into what it fetched. A pattern's `*` doesn't match across `/`, so a glob destination is widened to the directory
|
|
44
|
+
* above its first glob.
|
|
45
|
+
*/
|
|
46
|
+
function getFetchSnapshotPatterns(destinations) {
|
|
47
|
+
const patterns = ["refs/tags"];
|
|
48
|
+
for (let destination of destinations) {
|
|
49
|
+
const globIndex = destination.search(/[*?[]/);
|
|
50
|
+
if (globIndex !== -1) destination = destination.substring(0, destination.lastIndexOf("/", globIndex));
|
|
51
|
+
if (patterns.some((p) => destination === p || destination.startsWith(`${p}/`))) continue;
|
|
52
|
+
patterns.push(destination);
|
|
53
|
+
}
|
|
54
|
+
return patterns;
|
|
55
|
+
}
|
|
56
|
+
/** The refs created, moved, retargeted or deleted between two snapshots */
|
|
57
|
+
function getMovedRefs(before, after) {
|
|
58
|
+
const moved = [];
|
|
59
|
+
for (const [ref, sha] of after) if (before.get(ref) !== sha) moved.push(ref);
|
|
60
|
+
for (const ref of before.keys()) if (!after.has(ref)) moved.push(ref);
|
|
61
|
+
return moved;
|
|
62
|
+
}
|
|
16
63
|
var OperationsGitSubProvider = class {
|
|
17
64
|
context;
|
|
18
65
|
git;
|
|
@@ -53,7 +100,7 @@ var OperationsGitSubProvider = class {
|
|
|
53
100
|
}
|
|
54
101
|
}, ex));
|
|
55
102
|
} finally {
|
|
56
|
-
this.announceHeadChanged(repoPath, Boolean(options?.createBranch) && mayWriteTracking(ref, options?.noTracking));
|
|
103
|
+
this.announceHeadChanged(repoPath, options?.createBranch ? `refs/heads/${options.createBranch}` : void 0, Boolean(options?.createBranch) && mayWriteTracking(ref, options?.noTracking));
|
|
57
104
|
}
|
|
58
105
|
}
|
|
59
106
|
async cherryPick(repoPath, revs, options, runOptions) {
|
|
@@ -111,6 +158,7 @@ var OperationsGitSubProvider = class {
|
|
|
111
158
|
const sign = this.context.config?.signing?.enabled === true;
|
|
112
159
|
if (sign) params.push("-S");
|
|
113
160
|
params.push("-F", "-");
|
|
161
|
+
const headBranchBefore = await this.readHeadBranchRef(repoPath);
|
|
114
162
|
try {
|
|
115
163
|
try {
|
|
116
164
|
await this.git.run({
|
|
@@ -121,7 +169,8 @@ var OperationsGitSubProvider = class {
|
|
|
121
169
|
...runOptions
|
|
122
170
|
}, ...params);
|
|
123
171
|
} finally {
|
|
124
|
-
this.
|
|
172
|
+
const headBranch = await this.readHeadBranchRef(repoPath);
|
|
173
|
+
this.announceHeadChanged(repoPath, headBranch === headBranchBefore ? headBranch : void 0);
|
|
125
174
|
}
|
|
126
175
|
if (sign) {
|
|
127
176
|
let format;
|
|
@@ -148,10 +197,16 @@ var OperationsGitSubProvider = class {
|
|
|
148
197
|
const { branch, ...opts } = options ?? {};
|
|
149
198
|
let ran = false;
|
|
150
199
|
let fetched;
|
|
200
|
+
let snapshot;
|
|
151
201
|
try {
|
|
152
202
|
if (isBranchReference(branch)) {
|
|
153
203
|
const resolved = await resolveBranchRemote(this.provider, repoPath, branch, runOptions?.cancellation);
|
|
154
204
|
if (resolved.remote == null) return;
|
|
205
|
+
const patterns = await this.getFetchSnapshotPatterns(repoPath, resolved.remote, options?.pull ? [`${resolved.upstream}:${resolved.name}`] : void 0);
|
|
206
|
+
snapshot = {
|
|
207
|
+
patterns,
|
|
208
|
+
before: await this.snapshotRefs(repoPath, patterns)
|
|
209
|
+
};
|
|
155
210
|
ran = true;
|
|
156
211
|
await this.fetchCore(repoPath, {
|
|
157
212
|
branch: resolved.name,
|
|
@@ -161,6 +216,11 @@ var OperationsGitSubProvider = class {
|
|
|
161
216
|
preserveFetchHead: options?.preserveFetchHead
|
|
162
217
|
}, runOptions);
|
|
163
218
|
} else {
|
|
219
|
+
const patterns = await this.getFetchSnapshotPatterns(repoPath, opts.remote, opts.refspecs);
|
|
220
|
+
snapshot = {
|
|
221
|
+
patterns,
|
|
222
|
+
before: await this.snapshotRefs(repoPath, patterns)
|
|
223
|
+
};
|
|
164
224
|
ran = true;
|
|
165
225
|
await this.fetchCore(repoPath, opts, runOptions);
|
|
166
226
|
if (!opts.refspecs?.length) fetched = opts.remote != null ? { remote: opts.remote } : opts.all ? "all" : "default";
|
|
@@ -169,10 +229,7 @@ var OperationsGitSubProvider = class {
|
|
|
169
229
|
scope?.error(ex);
|
|
170
230
|
throw ex;
|
|
171
231
|
} finally {
|
|
172
|
-
if (ran)
|
|
173
|
-
this.context.hooks?.cache?.onReset?.(repoPath, "branches", "tags");
|
|
174
|
-
this.context.hooks?.repository?.onChanged?.(repoPath, this.getFetchChanges(branch, options));
|
|
175
|
-
}
|
|
232
|
+
if (ran) await this.announceFetch(repoPath, snapshot, () => this.getFetchChanges(branch, options));
|
|
176
233
|
if (fetched != null) this.followRemoteHeads(repoPath, fetched);
|
|
177
234
|
}
|
|
178
235
|
}
|
|
@@ -213,18 +270,97 @@ var OperationsGitSubProvider = class {
|
|
|
213
270
|
const remotes = await this.provider.remotes.getRemotes(repoPath);
|
|
214
271
|
return remotes.length === 1 ? remotes[0].name : "origin";
|
|
215
272
|
}
|
|
273
|
+
/**
|
|
274
|
+
* The for-each-ref patterns covering every ref a fetch from `remote` (`undefined`: from any remote) may write: the
|
|
275
|
+
* destinations of `refspecs`, those of the remote's configured `remote.<name>.fetch` refspecs (which a fetch of
|
|
276
|
+
* explicit refspecs still updates opportunistically, and which may store into local branches, as a mirror's do),
|
|
277
|
+
* and tags. A `remote` with no refspecs of its own may be a remote group (`remotes.<group>`), which fetches each of
|
|
278
|
+
* its remotes, so every remote's destinations stand for it. When the configuration can't be read, all local and
|
|
279
|
+
* remote-tracking branches stand for the configured destinations.
|
|
280
|
+
*/
|
|
281
|
+
async getFetchSnapshotPatterns(repoPath, remote, refspecs) {
|
|
282
|
+
const destinations = [];
|
|
283
|
+
const add = (refspec) => {
|
|
284
|
+
const destination = getRefspecDestination(refspec);
|
|
285
|
+
if (destination != null) destinations.push(destination);
|
|
286
|
+
};
|
|
287
|
+
for (const refspec of refspecs ?? []) add(refspec);
|
|
288
|
+
let configured;
|
|
289
|
+
try {
|
|
290
|
+
configured = await this.provider.config.getConfigRegexAll(repoPath, "^remote\\..+\\.fetch$");
|
|
291
|
+
} catch {
|
|
292
|
+
destinations.unshift(...broadFetchDestinations);
|
|
293
|
+
}
|
|
294
|
+
const ownKey = remote != null ? `remote.${remote}.fetch` : void 0;
|
|
295
|
+
const onlyKey = ownKey != null && configured?.has(ownKey) ? ownKey : void 0;
|
|
296
|
+
for (const [key, values] of configured ?? []) {
|
|
297
|
+
if (onlyKey != null && key !== onlyKey) continue;
|
|
298
|
+
for (const refspec of values) add(refspec);
|
|
299
|
+
}
|
|
300
|
+
return getFetchSnapshotPatterns(destinations);
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Announces what a fetch moved. Its refs are compared with the snapshot taken before it ran, so a fetch that
|
|
304
|
+
* brought nothing new announces nothing (and resets nothing), and one that did names exactly the refs it moved,
|
|
305
|
+
* letting every worktree that doesn't track them skip its refresh. When either snapshot is missing, it announces
|
|
306
|
+
* `fallback()`'s kinds unnamed, as if every ref of them may have moved; when a ref moved outside the kinds an
|
|
307
|
+
* announcement can name (`refs/notes/*`), the kinds it did see, together with `fallback()`'s, unnamed.
|
|
308
|
+
*/
|
|
309
|
+
async announceFetch(repoPath, snapshot, fallback) {
|
|
310
|
+
const after = snapshot?.before != null ? await this.snapshotRefs(repoPath, snapshot.patterns) : void 0;
|
|
311
|
+
let changes;
|
|
312
|
+
let moved;
|
|
313
|
+
if (snapshot?.before != null && after != null) {
|
|
314
|
+
moved = getMovedRefs(snapshot.before, after);
|
|
315
|
+
if (!moved.length) return;
|
|
316
|
+
const kinds = /* @__PURE__ */ new Set();
|
|
317
|
+
let unnameable = false;
|
|
318
|
+
for (const ref of moved) {
|
|
319
|
+
const kind = ref.startsWith("refs/") ? getRefChangeKind(ref) : void 0;
|
|
320
|
+
if (kind != null) kinds.add(kind);
|
|
321
|
+
else unnameable = true;
|
|
322
|
+
}
|
|
323
|
+
if (unnameable) {
|
|
324
|
+
for (const kind of fallback()) kinds.add(kind);
|
|
325
|
+
moved = void 0;
|
|
326
|
+
}
|
|
327
|
+
changes = fetchRefChangeKinds.filter((k) => kinds.has(k));
|
|
328
|
+
}
|
|
329
|
+
this.context.hooks?.cache?.onReset?.(repoPath, "branches", "tags");
|
|
330
|
+
if (changes != null && moved != null) this.context.hooks?.repository?.onChanged?.(repoPath, changes, moved);
|
|
331
|
+
else this.context.hooks?.repository?.onChanged?.(repoPath, changes ?? fallback());
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Each ref under `patterns` (for-each-ref patterns) with its object and, for a symbolic ref, its target (a remote's
|
|
335
|
+
* `HEAD` can move to another branch at the same commit), or `undefined` when git couldn't answer. A read, so it
|
|
336
|
+
* announces nothing.
|
|
337
|
+
*/
|
|
338
|
+
async snapshotRefs(repoPath, patterns) {
|
|
339
|
+
try {
|
|
340
|
+
const result = await this.git.run({
|
|
341
|
+
cwd: repoPath,
|
|
342
|
+
errors: "ignore"
|
|
343
|
+
}, "for-each-ref", "--format=%(refname)%00%(objectname)%00%(symref)", ...patterns);
|
|
344
|
+
if (result.completion.status !== "exited" || result.exitCode !== 0) return void 0;
|
|
345
|
+
const refs = /* @__PURE__ */ new Map();
|
|
346
|
+
for (const line of result.stdout.split("\n")) {
|
|
347
|
+
const index = line.indexOf("\0");
|
|
348
|
+
if (index === -1) continue;
|
|
349
|
+
refs.set(line.substring(0, index), line.substring(index + 1).trim());
|
|
350
|
+
}
|
|
351
|
+
return refs;
|
|
352
|
+
} catch {
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
216
356
|
/** `remotes`, plus `heads`/`tags` for any local branch or tag the fetch writes — a `pull` fetch writes `<upstream>:<branch>` */
|
|
217
357
|
getFetchChanges(branch, options) {
|
|
218
358
|
if (isBranchReference(branch)) return options?.pull ? ["heads", "remotes"] : ["remotes"];
|
|
219
359
|
if (!options?.refspecs?.length) return ["remotes"];
|
|
220
360
|
const changes = ["remotes"];
|
|
221
361
|
for (const refspec of options.refspecs) {
|
|
222
|
-
const
|
|
223
|
-
|
|
224
|
-
if (colonIndex === -1) continue;
|
|
225
|
-
let destination = stripped.slice(colonIndex + 1);
|
|
226
|
-
if (!destination) continue;
|
|
227
|
-
if (!destination.startsWith("refs/")) destination = /^(?:heads|tags|remotes)\//.test(destination) ? `refs/${destination}` : `refs/heads/${destination}`;
|
|
362
|
+
const destination = getRefspecDestination(refspec);
|
|
363
|
+
if (destination == null) continue;
|
|
228
364
|
if (destination.startsWith("refs/tags/")) {
|
|
229
365
|
if (!changes.includes("tags")) changes.push("tags");
|
|
230
366
|
} else if (destination.startsWith("refs/heads/")) {
|
|
@@ -772,10 +908,14 @@ var OperationsGitSubProvider = class {
|
|
|
772
908
|
}
|
|
773
909
|
}, ex instanceof Error ? ex : void 0);
|
|
774
910
|
}
|
|
775
|
-
/**
|
|
776
|
-
|
|
911
|
+
/**
|
|
912
|
+
* Called once git has run, success or not — a rejected write can still have moved HEAD or left state behind.
|
|
913
|
+
* `branchRef` is the full name of the one branch the write could have moved, when it knows it; `wroteTracking`
|
|
914
|
+
* says it wrote that branch's tracking, to its own config section.
|
|
915
|
+
*/
|
|
916
|
+
announceHeadChanged(repoPath, branchRef, wroteTracking) {
|
|
777
917
|
this.context.hooks?.cache?.onReset?.(repoPath, "branches", "status");
|
|
778
|
-
|
|
918
|
+
const changes = wroteTracking ? [
|
|
779
919
|
"config",
|
|
780
920
|
"head",
|
|
781
921
|
"heads",
|
|
@@ -784,7 +924,26 @@ var OperationsGitSubProvider = class {
|
|
|
784
924
|
"head",
|
|
785
925
|
"heads",
|
|
786
926
|
"index"
|
|
787
|
-
]
|
|
927
|
+
];
|
|
928
|
+
if (branchRef == null) this.context.hooks?.repository?.onChanged?.(repoPath, changes);
|
|
929
|
+
else if (wroteTracking) this.context.hooks?.repository?.onChanged?.(repoPath, changes, [branchRef], { configConfinedToRefs: true });
|
|
930
|
+
else this.context.hooks?.repository?.onChanged?.(repoPath, changes, [branchRef]);
|
|
931
|
+
}
|
|
932
|
+
/**
|
|
933
|
+
* The full name of the branch HEAD is on, from the worktree's own `HEAD` file (`ref: refs/heads/main`): read around
|
|
934
|
+
* a write, so it names the branch that write moved, whatever a switch outside core left in the caches; no git
|
|
935
|
+
* runs. `undefined` when HEAD is detached, unreadable, or not a branch name git allows — a reftable repository's
|
|
936
|
+
* `HEAD` file holds the placeholder `refs/heads/.invalid`, and its real HEAD is in the tables.
|
|
937
|
+
*/
|
|
938
|
+
async readHeadBranchRef(repoPath) {
|
|
939
|
+
try {
|
|
940
|
+
const gitDir = await this.provider.config.getGitDir(repoPath);
|
|
941
|
+
const head = new TextDecoder().decode(await this.context.fs.readFile(joinUriPath(gitDir.uri, "HEAD")));
|
|
942
|
+
const ref = /^ref:\s*(refs\/heads\/\S+)\s*$/.exec(head)?.[1];
|
|
943
|
+
return ref != null && !ref.split("/").some((part) => part.startsWith(".")) ? ref : void 0;
|
|
944
|
+
} catch {
|
|
945
|
+
return;
|
|
946
|
+
}
|
|
788
947
|
}
|
|
789
948
|
/** The caller has already announced the change — the conflict is what the failed run left behind */
|
|
790
949
|
async createConflictResult(repoPath, command) {
|