@gitkraken/core-gitlens 0.8.0 → 0.9.0
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 +32 -1
- package/dist/git/cache.d.ts +11 -0
- package/dist/git/cache.js +26 -3
- package/dist/git/cache.js.map +1 -1
- package/dist/git/context.d.ts +3 -2
- package/dist/git/context.js.map +1 -1
- package/dist/git/features.d.ts +1 -1
- package/dist/git/features.js +1 -0
- package/dist/git/features.js.map +1 -1
- package/dist/git/models/reflog.d.ts +6 -0
- package/dist/git/models/reflog.js.map +1 -1
- package/dist/git/models/revision.d.ts +0 -1
- package/dist/git/models/revision.js +1 -2
- package/dist/git/models/revision.js.map +1 -1
- package/dist/git/providers/commits.d.ts +20 -1
- package/dist/git/providers/operations.d.ts +13 -0
- package/dist/git/providers/provider.d.ts +14 -4
- package/dist/git/providers/refs.d.ts +10 -0
- package/dist/git/providers/revision.d.ts +2 -0
- package/dist/git/providers/staging.d.ts +2 -1
- package/dist/git/providers/stash.d.ts +3 -2
- package/dist/git/providers/status.d.ts +4 -0
- package/dist/git/run.types.d.ts +16 -0
- package/dist/git-cli/cliGitProvider.d.ts +24 -3
- package/dist/git-cli/cliGitProvider.js +79 -17
- package/dist/git-cli/cliGitProvider.js.map +1 -1
- package/dist/git-cli/exec/commandClassifier.d.ts +31 -0
- package/dist/git-cli/exec/commandClassifier.js +391 -0
- package/dist/git-cli/exec/commandClassifier.js.map +1 -0
- package/dist/git-cli/exec/git.d.ts +24 -3
- package/dist/git-cli/exec/git.js +116 -12
- package/dist/git-cli/exec/git.js.map +1 -1
- package/dist/git-cli/parsers/reflogParser.d.ts +7 -0
- package/dist/git-cli/parsers/reflogParser.js +11 -1
- package/dist/git-cli/parsers/reflogParser.js.map +1 -1
- package/dist/git-cli/providers/branches.js +16 -14
- package/dist/git-cli/providers/branches.js.map +1 -1
- package/dist/git-cli/providers/commits.d.ts +4 -2
- package/dist/git-cli/providers/commits.js +55 -4
- package/dist/git-cli/providers/commits.js.map +1 -1
- package/dist/git-cli/providers/diff.js +4 -4
- package/dist/git-cli/providers/diff.js.map +1 -1
- package/dist/git-cli/providers/operations.d.ts +12 -0
- package/dist/git-cli/providers/operations.js +26 -3
- package/dist/git-cli/providers/operations.js.map +1 -1
- package/dist/git-cli/providers/patch.js +2 -5
- package/dist/git-cli/providers/patch.js.map +1 -1
- package/dist/git-cli/providers/refs.d.ts +5 -0
- package/dist/git-cli/providers/refs.js +26 -1
- package/dist/git-cli/providers/refs.js.map +1 -1
- package/dist/git-cli/providers/remotes.js +3 -2
- package/dist/git-cli/providers/remotes.js.map +1 -1
- package/dist/git-cli/providers/revision.d.ts +2 -0
- package/dist/git-cli/providers/revision.js +11 -0
- package/dist/git-cli/providers/revision.js.map +1 -1
- package/dist/git-cli/providers/staging.d.ts +2 -1
- package/dist/git-cli/providers/staging.js +12 -7
- package/dist/git-cli/providers/staging.js.map +1 -1
- package/dist/git-cli/providers/stash.d.ts +3 -2
- package/dist/git-cli/providers/stash.js +34 -22
- package/dist/git-cli/providers/stash.js.map +1 -1
- package/dist/git-cli/providers/status.d.ts +2 -0
- package/dist/git-cli/providers/status.js +27 -9
- package/dist/git-cli/providers/status.js.map +1 -1
- package/dist/plus/git-github/providers/github/commits.d.ts +4 -2
- package/dist/plus/git-github/providers/github/commits.js +3 -1
- package/dist/plus/git-github/providers/github/commits.js.map +1 -1
- package/dist/plus/git-github/providers/github/revision.d.ts +1 -0
- package/dist/plus/git-github/providers/github/revision.js +5 -0
- package/dist/plus/git-github/providers/github/revision.js.map +1 -1
- package/docs/kepler-git-write-api-parity.md +140 -14
- package/package.json +1 -1
package/dist/git-cli/exec/git.js
CHANGED
|
@@ -4,13 +4,15 @@ import { getDurationMilliseconds, hrtime } from "../../utils/hrtime.js";
|
|
|
4
4
|
import { Logger as _logger } from "../../utils/logger.js";
|
|
5
5
|
import { formatLoggableScopeBlock } from "../../utils/logger.scoped.js";
|
|
6
6
|
import { defer } from "../../utils/promise.js";
|
|
7
|
-
import { dirname, isAbsolute, joinPaths, normalizePath } from "../../utils/path.js";
|
|
7
|
+
import { arePathsEqual, dirname as dirname$1, isAbsolute as isAbsolute$1, isDescendant, joinPaths, normalizePath } from "../../utils/path.js";
|
|
8
8
|
import { GitWarnings, WorkspaceUntrustedError } from "../../git/errors.js";
|
|
9
9
|
import { gitFeaturesByVersion } from "../../git/features.js";
|
|
10
10
|
import { CancelledRunError, RunError, fsExists, runSpawn } from "../../utils/env/node/exec.js";
|
|
11
11
|
import { compare, fromString } from "../../utils/version.js";
|
|
12
|
+
import { getChangesForCommand, leadingCommand } from "./commandClassifier.js";
|
|
12
13
|
import { EventLoopMonitor } from "./eventLoopMonitor.js";
|
|
13
14
|
import { GitQueue, getPrimaryGitCommand, inferGitCommandPriority } from "./gitQueue.js";
|
|
15
|
+
import { resolve } from "path";
|
|
14
16
|
import { spawn } from "child_process";
|
|
15
17
|
import * as process from "process";
|
|
16
18
|
//#region ../git-cli/src/exec/git.ts
|
|
@@ -364,6 +366,46 @@ function classifySearchError(ex) {
|
|
|
364
366
|
};
|
|
365
367
|
if (/unknown revision/i.test(stderr)) return { reason: "invalidRef" };
|
|
366
368
|
}
|
|
369
|
+
/**
|
|
370
|
+
* Keys dropped from the INHERITED `process.env` before it seeds the base git environment. git hands these
|
|
371
|
+
* to anything it launches (a hook, `rebase -x`, an editor invoked as `GIT_EDITOR`) to describe the command
|
|
372
|
+
* it is running; a host started that way would otherwise run every command against THAT repository with
|
|
373
|
+
* THAT command's settings, whatever `cwd` we pass. None is worth keeping when set deliberately either: a
|
|
374
|
+
* `GIT_DIR` would point every repository the host opens at one. `options.env`, `options.getEnvironment()`
|
|
375
|
+
* and a per-call `env` are merged in afterwards, so any of them can still set these keys (e.g. a temporary
|
|
376
|
+
* `GIT_INDEX_FILE` for a call).
|
|
377
|
+
*/
|
|
378
|
+
const inheritedEnvKeysToDrop = /* @__PURE__ */ new Set([
|
|
379
|
+
"GIT_DIR",
|
|
380
|
+
"GIT_WORK_TREE",
|
|
381
|
+
"GIT_INDEX_FILE",
|
|
382
|
+
"GIT_COMMON_DIR",
|
|
383
|
+
"GIT_OBJECT_DIRECTORY",
|
|
384
|
+
"GIT_ALTERNATE_OBJECT_DIRECTORIES",
|
|
385
|
+
"GIT_NAMESPACE",
|
|
386
|
+
"GIT_CONFIG_PARAMETERS",
|
|
387
|
+
"GIT_EXEC_PATH",
|
|
388
|
+
"GIT_PREFIX",
|
|
389
|
+
"GIT_REFLOG_ACTION"
|
|
390
|
+
]);
|
|
391
|
+
/**
|
|
392
|
+
* Dropped only when git launched the host, which it always marks by exporting `GIT_EXEC_PATH`: an editor
|
|
393
|
+
* opened for `commit --amend` gets that commit's author and date, while an identity set deliberately (e.g.
|
|
394
|
+
* by direnv) must still reach our commits.
|
|
395
|
+
*/
|
|
396
|
+
const inheritedIdentityKeysToDrop = /* @__PURE__ */ new Set([
|
|
397
|
+
"GIT_AUTHOR_NAME",
|
|
398
|
+
"GIT_AUTHOR_EMAIL",
|
|
399
|
+
"GIT_AUTHOR_DATE",
|
|
400
|
+
"GIT_COMMITTER_NAME",
|
|
401
|
+
"GIT_COMMITTER_EMAIL",
|
|
402
|
+
"GIT_COMMITTER_DATE"
|
|
403
|
+
]);
|
|
404
|
+
/** `process.env` with {@link inheritedEnvKeysToDrop} removed, and {@link inheritedIdentityKeysToDrop} when git launched us. */
|
|
405
|
+
function getInheritedEnv() {
|
|
406
|
+
const launchedByGit = process.env.GIT_EXEC_PATH != null;
|
|
407
|
+
return Object.fromEntries(Object.entries(process.env).filter(([key]) => !inheritedEnvKeysToDrop.has(key) && !(launchedByGit && inheritedIdentityKeysToDrop.has(key))));
|
|
408
|
+
}
|
|
367
409
|
const emptyArray = Object.freeze([]);
|
|
368
410
|
const emptyObj = Object.freeze({});
|
|
369
411
|
const trailingNewlineRegex = /[\r|\n]+$/;
|
|
@@ -380,25 +422,37 @@ var Git = class {
|
|
|
380
422
|
_eventLoopMonitor = new EventLoopMonitor();
|
|
381
423
|
/** Count of git commands currently in flight, across both the exec and streaming paths */
|
|
382
424
|
_activeCommandCount = 0;
|
|
383
|
-
/** Cached base environment: process.env + static options.env + GCM/LC_ALL vars */
|
|
425
|
+
/** Cached base environment: process.env (minus {@link inheritedEnvKeysToDrop}) + static options.env + GCM/LC_ALL vars */
|
|
384
426
|
_baseEnv;
|
|
385
427
|
/** Cached full environment: base + dynamic getEnvironment() result */
|
|
386
428
|
_fullEnv;
|
|
387
429
|
/** Last dynamic env reference, used to detect when getEnvironment() returns a new object */
|
|
388
430
|
_lastDynamicEnv;
|
|
431
|
+
/** Bound via {@link bindChangeNotifier}; announces a `notify`-flagged run's changes. No-op until bound. */
|
|
432
|
+
_changeNotifier;
|
|
389
433
|
constructor(_locator, options = {}) {
|
|
390
434
|
this._locator = _locator;
|
|
391
435
|
this.options = options;
|
|
392
436
|
this._queue = new GitQueue(options.queue, { onSlowQueue: options.hooks?.onSlowQueue });
|
|
393
437
|
}
|
|
394
438
|
/**
|
|
439
|
+
* Binds the callback a `notify`-flagged {@link run} calls once it settles. `CliGitProvider` wires this
|
|
440
|
+
* to its own `notifyChanged` from its constructor — including when it's handed a pre-built `Git` via
|
|
441
|
+
* `options.git`, so a host-supplied instance gets bound too. With nothing bound, `notify` is a no-op.
|
|
442
|
+
* `repoPaths` holds more than one path only for a `-C`-scoped shared-state verb: the `-C` target, then the
|
|
443
|
+
* caller's own `cwd`.
|
|
444
|
+
*/
|
|
445
|
+
bindChangeNotifier(fn) {
|
|
446
|
+
this._changeNotifier = fn;
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
395
449
|
* Returns the base environment for git commands. Cached to avoid spreading
|
|
396
450
|
* process.env (30-100+ keys) on every call. Includes static options.env and
|
|
397
451
|
* GCM/LC_ALL vars but NOT dynamic getEnvironment() or per-call env overrides.
|
|
398
452
|
*/
|
|
399
453
|
getBaseEnv() {
|
|
400
454
|
return this._baseEnv ??= {
|
|
401
|
-
...
|
|
455
|
+
...getInheritedEnv(),
|
|
402
456
|
...this.options.env ?? emptyObj,
|
|
403
457
|
GCM_INTERACTIVE: "NEVER",
|
|
404
458
|
GCM_PRESERVE_CREDS: "TRUE",
|
|
@@ -435,9 +489,20 @@ var Git = class {
|
|
|
435
489
|
this._queue.dispose();
|
|
436
490
|
this._eventLoopMonitor.dispose();
|
|
437
491
|
}
|
|
438
|
-
/**
|
|
439
|
-
|
|
440
|
-
|
|
492
|
+
/**
|
|
493
|
+
* Drops in-flight commands so a later identical call spawns its own run instead of joining one that
|
|
494
|
+
* started before a change. With `repoPaths`, drops only runs whose `cwd` is one of them or inside one;
|
|
495
|
+
* without, drops every run.
|
|
496
|
+
*/
|
|
497
|
+
clearPendingCommands(repoPaths) {
|
|
498
|
+
if (repoPaths == null) {
|
|
499
|
+
this.pendingCommands.clear();
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
for (const [key, { cwd }] of this.pendingCommands) {
|
|
503
|
+
if (cwd == null) continue;
|
|
504
|
+
if (repoPaths.some((p) => arePathsEqual(cwd, p) || isDescendant(cwd, p))) this.pendingCommands.delete(key);
|
|
505
|
+
}
|
|
441
506
|
}
|
|
442
507
|
/** Marks one more git command as in flight; starts the event-loop monitor on the first. */
|
|
443
508
|
beginActiveCommand() {
|
|
@@ -492,6 +557,14 @@ var Git = class {
|
|
|
492
557
|
async run(options, ...args) {
|
|
493
558
|
if (this.options.isTrusted?.() === false) throw new WorkspaceUntrustedError();
|
|
494
559
|
const runArgs = args.filter((a) => a != null);
|
|
560
|
+
if (options.notify != null) try {
|
|
561
|
+
return await this.run({
|
|
562
|
+
...options,
|
|
563
|
+
notify: void 0
|
|
564
|
+
}, ...args);
|
|
565
|
+
} finally {
|
|
566
|
+
this.applyNotify(options, runArgs);
|
|
567
|
+
}
|
|
495
568
|
const gitCommand = `git ${runArgs.join(" ")}`;
|
|
496
569
|
if (options.caching != null) {
|
|
497
570
|
const cachePath = options.caching.commonPath ?? options.cwd;
|
|
@@ -511,6 +584,34 @@ var Git = class {
|
|
|
511
584
|
}
|
|
512
585
|
return this.runCore(options, runArgs, gitCommand);
|
|
513
586
|
}
|
|
587
|
+
/**
|
|
588
|
+
* Applies `options.notify` once a {@link run} has settled — a no-op unless both `notify` and a
|
|
589
|
+
* {@link bindChangeNotifier bound} notifier are present, so an unflagged caller pays nothing.
|
|
590
|
+
*/
|
|
591
|
+
applyNotify(options, args) {
|
|
592
|
+
const notify = options.notify;
|
|
593
|
+
if (notify == null || this._changeNotifier == null || options.cwd == null) return;
|
|
594
|
+
if (notify !== "infer") {
|
|
595
|
+
this._changeNotifier([this.resolveNotifyPath(options.cwd, leadingCommand(args).pathOverride)], notify);
|
|
596
|
+
return;
|
|
597
|
+
}
|
|
598
|
+
const command = getChangesForCommand(args);
|
|
599
|
+
if (command == null) return;
|
|
600
|
+
const ranIn = this.resolveNotifyPath(options.cwd, command.pathOverride);
|
|
601
|
+
const cwd = normalizePath(options.cwd);
|
|
602
|
+
if (command.pathOverride != null && cwd !== ranIn && (command.sharedChanges.length || !command.changes.length)) {
|
|
603
|
+
if (command.sharedChanges.length === command.changes.length) this._changeNotifier([ranIn, cwd], command.changes);
|
|
604
|
+
else {
|
|
605
|
+
this._changeNotifier([ranIn], command.changes);
|
|
606
|
+
this._changeNotifier([cwd], command.sharedChanges);
|
|
607
|
+
}
|
|
608
|
+
return;
|
|
609
|
+
}
|
|
610
|
+
this._changeNotifier([ranIn], command.changes);
|
|
611
|
+
}
|
|
612
|
+
resolveNotifyPath(cwd, pathOverride) {
|
|
613
|
+
return normalizePath(pathOverride != null ? resolve(cwd, pathOverride) : cwd);
|
|
614
|
+
}
|
|
514
615
|
async runCore(options, args, gitCommand) {
|
|
515
616
|
const start = hrtime();
|
|
516
617
|
const startEpochMs = Date.now();
|
|
@@ -529,12 +630,15 @@ var Git = class {
|
|
|
529
630
|
const cacheKey = `${correlationKey !== void 0 ? `${correlationKey}:` : ""}${unshared ? `${unsharedRunCounter.next()}:` : ""}${cancellation != null ? `${getAbortSignalId(cancellation)}:` : ""}${gitCommand}`;
|
|
530
631
|
let execStart;
|
|
531
632
|
let waiting;
|
|
532
|
-
let promise = this.pendingCommands.get(cacheKey);
|
|
633
|
+
let promise = this.pendingCommands.get(cacheKey)?.promise;
|
|
533
634
|
if (promise == null) {
|
|
534
635
|
waiting = false;
|
|
535
636
|
const deferred = defer();
|
|
536
637
|
promise = deferred.promise;
|
|
537
|
-
this.pendingCommands.set(cacheKey,
|
|
638
|
+
this.pendingCommands.set(cacheKey, {
|
|
639
|
+
cwd: options.cwd,
|
|
640
|
+
promise
|
|
641
|
+
});
|
|
538
642
|
args.unshift("-c", "core.quotepath=false", "-c", "color.ui=false", ...configs ?? emptyArray);
|
|
539
643
|
if (process.platform === "win32") args.unshift("-c", "core.longpaths=true");
|
|
540
644
|
if (cancellation != null) runOpts.cancellation = cancellation;
|
|
@@ -544,7 +648,7 @@ var Git = class {
|
|
|
544
648
|
execStart = hrtime();
|
|
545
649
|
return runSpawn(gitPath, args, encoding ?? "utf8", runOpts);
|
|
546
650
|
}, cancellation).then(deferred.fulfill, (e) => deferred.cancel(e instanceof Error ? e : new Error(String(e)))).finally(() => {
|
|
547
|
-
this.pendingCommands.delete(cacheKey);
|
|
651
|
+
if (this.pendingCommands.get(cacheKey)?.promise === deferred.promise) this.pendingCommands.delete(cacheKey);
|
|
548
652
|
}).catch(() => {});
|
|
549
653
|
} else {
|
|
550
654
|
waiting = true;
|
|
@@ -750,10 +854,10 @@ var Git = class {
|
|
|
750
854
|
}, "rev-parse", "--git-dir", "--git-common-dir");
|
|
751
855
|
if (!result.stdout) return void 0;
|
|
752
856
|
let [dotGitPath, commonDotGitPath] = result.stdout.split("\n").map((r) => r.trimStart());
|
|
753
|
-
if (!isAbsolute(dotGitPath)) dotGitPath = joinPaths(cwd, dotGitPath);
|
|
857
|
+
if (!isAbsolute$1(dotGitPath)) dotGitPath = joinPaths(cwd, dotGitPath);
|
|
754
858
|
dotGitPath = normalizePath(dotGitPath);
|
|
755
859
|
if (commonDotGitPath) {
|
|
756
|
-
if (!isAbsolute(commonDotGitPath)) commonDotGitPath = joinPaths(cwd, commonDotGitPath);
|
|
860
|
+
if (!isAbsolute$1(commonDotGitPath)) commonDotGitPath = joinPaths(cwd, commonDotGitPath);
|
|
757
861
|
commonDotGitPath = normalizePath(commonDotGitPath);
|
|
758
862
|
return {
|
|
759
863
|
path: dotGitPath,
|
|
@@ -807,7 +911,7 @@ var Git = class {
|
|
|
807
911
|
let exists = inDotGit ? false : await fsExists(cwd);
|
|
808
912
|
if (!exists) {
|
|
809
913
|
do {
|
|
810
|
-
const parent = dirname(cwd);
|
|
914
|
+
const parent = dirname$1(cwd);
|
|
811
915
|
if (parent === cwd || parent.length === 0) return emptyArray;
|
|
812
916
|
cwd = parent;
|
|
813
917
|
exists = await fsExists(cwd);
|