@gitkraken/core-gitlens 0.7.2 → 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.
Files changed (192) hide show
  1. package/CHANGELOG.md +72 -1
  2. package/dist/git/cache.d.ts +29 -5
  3. package/dist/git/cache.js +52 -11
  4. package/dist/git/cache.js.map +1 -1
  5. package/dist/git/context.d.ts +6 -1
  6. package/dist/git/context.js.map +1 -1
  7. package/dist/git/errors.d.ts +28 -1
  8. package/dist/git/errors.js +45 -1
  9. package/dist/git/errors.js.map +1 -1
  10. package/dist/git/features.d.ts +1 -1
  11. package/dist/git/features.js +1 -0
  12. package/dist/git/features.js.map +1 -1
  13. package/dist/git/models/reflog.d.ts +6 -0
  14. package/dist/git/models/reflog.js.map +1 -1
  15. package/dist/git/models/revision.d.ts +0 -1
  16. package/dist/git/models/revision.js +1 -2
  17. package/dist/git/models/revision.js.map +1 -1
  18. package/dist/git/providers/branches.d.ts +5 -1
  19. package/dist/git/providers/commits.d.ts +44 -2
  20. package/dist/git/providers/config.d.ts +7 -1
  21. package/dist/git/providers/operations.d.ts +19 -0
  22. package/dist/git/providers/provider.d.ts +29 -2
  23. package/dist/git/providers/refs.d.ts +48 -3
  24. package/dist/git/providers/revision.d.ts +7 -1
  25. package/dist/git/providers/staging.d.ts +13 -0
  26. package/dist/git/providers/stash.d.ts +3 -2
  27. package/dist/git/providers/status.d.ts +4 -0
  28. package/dist/git/providers/worktrees.d.ts +23 -3
  29. package/dist/git/run.types.d.ts +22 -0
  30. package/dist/git-cli/cliGitProvider.d.ts +39 -2
  31. package/dist/git-cli/cliGitProvider.js +109 -11
  32. package/dist/git-cli/cliGitProvider.js.map +1 -1
  33. package/dist/git-cli/exec/commandClassifier.d.ts +31 -0
  34. package/dist/git-cli/exec/commandClassifier.js +391 -0
  35. package/dist/git-cli/exec/commandClassifier.js.map +1 -0
  36. package/dist/git-cli/exec/git.d.ts +36 -5
  37. package/dist/git-cli/exec/git.js +163 -28
  38. package/dist/git-cli/exec/git.js.map +1 -1
  39. package/dist/git-cli/exec/gitQueue.d.ts +4 -1
  40. package/dist/git-cli/exec/gitQueue.js +1 -1
  41. package/dist/git-cli/exec/gitQueue.js.map +1 -1
  42. package/dist/git-cli/parsers/reflogParser.d.ts +7 -0
  43. package/dist/git-cli/parsers/reflogParser.js +11 -1
  44. package/dist/git-cli/parsers/reflogParser.js.map +1 -1
  45. package/dist/git-cli/providers/branches.d.ts +10 -1
  46. package/dist/git-cli/providers/branches.js +31 -22
  47. package/dist/git-cli/providers/branches.js.map +1 -1
  48. package/dist/git-cli/providers/commits.d.ts +27 -3
  49. package/dist/git-cli/providers/commits.js +112 -12
  50. package/dist/git-cli/providers/commits.js.map +1 -1
  51. package/dist/git-cli/providers/config.js +2 -1
  52. package/dist/git-cli/providers/config.js.map +1 -1
  53. package/dist/git-cli/providers/diff.js +4 -4
  54. package/dist/git-cli/providers/diff.js.map +1 -1
  55. package/dist/git-cli/providers/operations.d.ts +13 -0
  56. package/dist/git-cli/providers/operations.js +64 -5
  57. package/dist/git-cli/providers/operations.js.map +1 -1
  58. package/dist/git-cli/providers/patch.js +21 -45
  59. package/dist/git-cli/providers/patch.js.map +1 -1
  60. package/dist/git-cli/providers/refs.d.ts +20 -3
  61. package/dist/git-cli/providers/refs.js +140 -10
  62. package/dist/git-cli/providers/refs.js.map +1 -1
  63. package/dist/git-cli/providers/remotes.js +3 -2
  64. package/dist/git-cli/providers/remotes.js.map +1 -1
  65. package/dist/git-cli/providers/revision.d.ts +5 -1
  66. package/dist/git-cli/providers/revision.js +20 -5
  67. package/dist/git-cli/providers/revision.js.map +1 -1
  68. package/dist/git-cli/providers/staging.d.ts +9 -0
  69. package/dist/git-cli/providers/staging.js +63 -6
  70. package/dist/git-cli/providers/staging.js.map +1 -1
  71. package/dist/git-cli/providers/stash.d.ts +3 -2
  72. package/dist/git-cli/providers/stash.js +34 -22
  73. package/dist/git-cli/providers/stash.js.map +1 -1
  74. package/dist/git-cli/providers/status.d.ts +2 -0
  75. package/dist/git-cli/providers/status.js +27 -9
  76. package/dist/git-cli/providers/status.js.map +1 -1
  77. package/dist/git-cli/providers/worktrees.d.ts +31 -2
  78. package/dist/git-cli/providers/worktrees.js +75 -7
  79. package/dist/git-cli/providers/worktrees.js.map +1 -1
  80. package/dist/plus/git-github/api/github.d.ts +64 -3
  81. package/dist/plus/git-github/api/github.js +237 -24
  82. package/dist/plus/git-github/api/github.js.map +1 -1
  83. package/dist/plus/git-github/providers/github/branches.d.ts +3 -1
  84. package/dist/plus/git-github/providers/github/branches.js +2 -1
  85. package/dist/plus/git-github/providers/github/branches.js.map +1 -1
  86. package/dist/plus/git-github/providers/github/commits.d.ts +4 -2
  87. package/dist/plus/git-github/providers/github/commits.js +3 -1
  88. package/dist/plus/git-github/providers/github/commits.js.map +1 -1
  89. package/dist/plus/git-github/providers/github/refs.d.ts +10 -3
  90. package/dist/plus/git-github/providers/github/refs.js +4 -4
  91. package/dist/plus/git-github/providers/github/refs.js.map +1 -1
  92. package/dist/plus/git-github/providers/github/revision.d.ts +4 -1
  93. package/dist/plus/git-github/providers/github/revision.js +6 -1
  94. package/dist/plus/git-github/providers/github/revision.js.map +1 -1
  95. package/dist/plus/integrations/index.d.ts +5 -2
  96. package/dist/plus/integrations/index.js.map +1 -1
  97. package/dist/plus/integrations/integrationService.d.ts +35 -9
  98. package/dist/plus/integrations/integrationService.js +16 -3
  99. package/dist/plus/integrations/integrationService.js.map +1 -1
  100. package/dist/plus/integrations/manager.d.ts +107 -37
  101. package/dist/plus/integrations/models/gitHostIntegration.d.ts +128 -13
  102. package/dist/plus/integrations/models/gitHostIntegration.js +130 -17
  103. package/dist/plus/integrations/models/gitHostIntegration.js.map +1 -1
  104. package/dist/plus/integrations/models/integration.d.ts +51 -3
  105. package/dist/plus/integrations/models/integration.js +125 -18
  106. package/dist/plus/integrations/models/integration.js.map +1 -1
  107. package/dist/plus/integrations/models/issuesIntegration.d.ts +18 -5
  108. package/dist/plus/integrations/models/issuesIntegration.js +40 -10
  109. package/dist/plus/integrations/models/issuesIntegration.js.map +1 -1
  110. package/dist/plus/integrations/providers/azure/azure.d.ts +1 -1
  111. package/dist/plus/integrations/providers/azure/azure.js +13 -17
  112. package/dist/plus/integrations/providers/azure/azure.js.map +1 -1
  113. package/dist/plus/integrations/providers/azure/models.d.ts +29 -0
  114. package/dist/plus/integrations/providers/azure/models.js +112 -1
  115. package/dist/plus/integrations/providers/azure/models.js.map +1 -1
  116. package/dist/plus/integrations/providers/azureDevOps.d.ts +54 -2
  117. package/dist/plus/integrations/providers/azureDevOps.js +80 -2
  118. package/dist/plus/integrations/providers/azureDevOps.js.map +1 -1
  119. package/dist/plus/integrations/providers/azureDevOpsServer.js +2 -1
  120. package/dist/plus/integrations/providers/azureDevOpsServer.js.map +1 -1
  121. package/dist/plus/integrations/providers/bitbucket/bitbucket.d.ts +61 -0
  122. package/dist/plus/integrations/providers/bitbucket/bitbucket.js +165 -23
  123. package/dist/plus/integrations/providers/bitbucket/bitbucket.js.map +1 -1
  124. package/dist/plus/integrations/providers/bitbucket/models.d.ts +6 -1
  125. package/dist/plus/integrations/providers/bitbucket/models.js +4 -3
  126. package/dist/plus/integrations/providers/bitbucket/models.js.map +1 -1
  127. package/dist/plus/integrations/providers/bitbucket-server/pullRequestSearch.js +1 -1
  128. package/dist/plus/integrations/providers/bitbucket-server/pullRequestSearch.js.map +1 -1
  129. package/dist/plus/integrations/providers/bitbucket-server.d.ts +38 -1
  130. package/dist/plus/integrations/providers/bitbucket-server.js +33 -1
  131. package/dist/plus/integrations/providers/bitbucket-server.js.map +1 -1
  132. package/dist/plus/integrations/providers/bitbucket.d.ts +36 -1
  133. package/dist/plus/integrations/providers/bitbucket.js +29 -1
  134. package/dist/plus/integrations/providers/bitbucket.js.map +1 -1
  135. package/dist/plus/integrations/providers/github.d.ts +48 -4
  136. package/dist/plus/integrations/providers/github.js +101 -6
  137. package/dist/plus/integrations/providers/github.js.map +1 -1
  138. package/dist/plus/integrations/providers/gitlab/gitlab.d.ts +35 -0
  139. package/dist/plus/integrations/providers/gitlab/gitlab.js +132 -15
  140. package/dist/plus/integrations/providers/gitlab/gitlab.js.map +1 -1
  141. package/dist/plus/integrations/providers/gitlab/models.d.ts +1 -0
  142. package/dist/plus/integrations/providers/gitlab/models.js +1 -1
  143. package/dist/plus/integrations/providers/gitlab/models.js.map +1 -1
  144. package/dist/plus/integrations/providers/gitlab.d.ts +48 -1
  145. package/dist/plus/integrations/providers/gitlab.js +79 -3
  146. package/dist/plus/integrations/providers/gitlab.js.map +1 -1
  147. package/dist/plus/integrations/providers/jira-server.d.ts +3 -3
  148. package/dist/plus/integrations/providers/jira-server.js +3 -3
  149. package/dist/plus/integrations/providers/jira-server.js.map +1 -1
  150. package/dist/plus/integrations/providers/models.d.ts +12 -1
  151. package/dist/plus/integrations/providers/models.js +11 -1
  152. package/dist/plus/integrations/providers/models.js.map +1 -1
  153. package/dist/plus/integrations/providers/providerErrors.d.ts +9 -1
  154. package/dist/plus/integrations/providers/providerErrors.js +10 -1
  155. package/dist/plus/integrations/providers/providerErrors.js.map +1 -1
  156. package/dist/plus/integrations/providers/providersApi.d.ts +59 -0
  157. package/dist/plus/integrations/providers/providersApi.js +136 -1
  158. package/dist/plus/integrations/providers/providersApi.js.map +1 -1
  159. package/dist/plus/integrations/providers/utils/providerPaging.d.ts +42 -0
  160. package/dist/plus/integrations/providers/utils/providerPaging.js +58 -1
  161. package/dist/plus/integrations/providers/utils/providerPaging.js.map +1 -1
  162. package/dist/plus/integrations/providers/utils.d.ts +1 -1
  163. package/dist/plus/integrations/reads/currentAccount.d.ts +35 -0
  164. package/dist/plus/integrations/reads/currentAccount.js +46 -0
  165. package/dist/plus/integrations/reads/currentAccount.js.map +1 -0
  166. package/dist/plus/integrations/reads/drains.d.ts +4 -1
  167. package/dist/plus/integrations/reads/drains.js +7 -3
  168. package/dist/plus/integrations/reads/drains.js.map +1 -1
  169. package/dist/plus/integrations/reads/issueBatch.d.ts +72 -12
  170. package/dist/plus/integrations/reads/issueBatch.js +193 -48
  171. package/dist/plus/integrations/reads/issueBatch.js.map +1 -1
  172. package/dist/plus/integrations/reads/pullRequestBatch.d.ts +57 -0
  173. package/dist/plus/integrations/reads/pullRequestBatch.js +80 -0
  174. package/dist/plus/integrations/reads/pullRequestBatch.js.map +1 -0
  175. package/dist/plus/integrations/reads/pullRequestBranches.d.ts +58 -0
  176. package/dist/plus/integrations/reads/pullRequestBranches.js +111 -0
  177. package/dist/plus/integrations/reads/pullRequestBranches.js.map +1 -0
  178. package/dist/plus/integrations/reads/pullRequests.js +3 -3
  179. package/dist/plus/integrations/reads/pullRequests.js.map +1 -1
  180. package/dist/plus/integrations/reads/sweeps.js +3 -3
  181. package/dist/plus/integrations/reads/sweeps.js.map +1 -1
  182. package/dist/plus/integrations/results.d.ts +5 -2
  183. package/dist/plus/integrations/results.js.map +1 -1
  184. package/dist/utils/env/node/exec.js +1 -1
  185. package/dist/utils/env/node/exec.js.map +1 -1
  186. package/docs/integrations.md +90 -36
  187. package/docs/kepler-git-write-api-parity.md +365 -0
  188. package/docs/kepler-read-api-parity.md +75 -28
  189. package/package.json +1 -1
  190. package/dist/plus/integrations/reads/trackerIssue.d.ts +0 -33
  191. package/dist/plus/integrations/reads/trackerIssue.js +0 -60
  192. package/dist/plus/integrations/reads/trackerIssue.js.map +0 -1
@@ -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
@@ -75,7 +77,9 @@ const GitErrors = {
75
77
  noRemoteReference: /unable to delete '.+?': remote ref does not exist/i,
76
78
  noRemoteRepositorySpecified: /No remote repository specified\./i,
77
79
  noUpstream: /^fatal:\s*The current branch .* has no upstream branch/i,
80
+ noTrackingInformation: /There is no tracking information for the current branch/i,
78
81
  notAValidObjectName: /Not a valid object name/i,
82
+ notPossibleToFastForward: /Not possible to fast-forward/i,
79
83
  notAWorkingTree: /'(.*?)' is not a working tree/i,
80
84
  noUserNameConfigured: /Please tell me who you are\./i,
81
85
  nothingToCommit: /nothing(?: added)? to commit|no changes added to commit/i,
@@ -91,7 +95,13 @@ const GitErrors = {
91
95
  rebaseMultipleBranches: /cannot rebase onto multiple branches/i,
92
96
  revertAborted: /revert.*aborted/i,
93
97
  revertInProgress: /^(error: )?(revert|cherry-pick) is already in progress/i,
98
+ refAlreadyExists: /cannot lock ref '.*?': reference already exists/i,
99
+ refBadName: /refusing to update ref with bad name/i,
94
100
  refLocked: /fatal:\s*cannot lock ref ['"].+['"]: unable to create file/i,
101
+ refNonexistentObject: /trying to write ref '.*?' with nonexistent object/i,
102
+ refNotAValidSha: /not a valid (?:old )?SHA1/i,
103
+ refUnableToResolve: /cannot lock ref '.*?': unable to resolve reference/i,
104
+ refValueMismatch: /cannot lock ref '.*?': is at [0-9a-f]+ but expected/i,
95
105
  remoteAhead: /rejected because the remote contains work/i,
96
106
  remoteConnectionFailed: /Could not read from remote repository/i,
97
107
  remoteRejected: /rejected because the remote contains work/i,
@@ -199,7 +209,9 @@ const errorToReasonMap = /* @__PURE__ */ new Map([
199
209
  [GitErrors.changesWouldBeOverwritten, "wouldOverwriteChanges"],
200
210
  [GitErrors.cantLockRef, "refLocked"],
201
211
  [GitErrors.rebaseMultipleBranches, "rebaseMultipleBranches"],
202
- [GitErrors.tagConflict, "tagConflict"]
212
+ [GitErrors.tagConflict, "tagConflict"],
213
+ [GitErrors.notPossibleToFastForward, "noFastForward"],
214
+ [GitErrors.noTrackingInformation, "noUpstream"]
203
215
  ]],
204
216
  ["push", [
205
217
  [GitErrors.remoteAhead, "remoteAhead"],
@@ -255,6 +267,22 @@ const errorToReasonMap = /* @__PURE__ */ new Map([
255
267
  [GitErrors.remoteRejected, "remoteRejected"],
256
268
  [GitErrors.tagConflict, "tagConflict"]
257
269
  ]],
270
+ ["update-ref", [
271
+ [GitErrors.refBadName, "invalidRef"],
272
+ [GitErrors.refNonexistentObject, "invalidObject"],
273
+ [GitErrors.refNotAValidSha, "invalidObject"],
274
+ [GitErrors.refValueMismatch, "conflict"],
275
+ [GitErrors.refAlreadyExists, "conflict"],
276
+ [GitErrors.refUnableToResolve, "conflict"],
277
+ [GitErrors.cantLockRef, "conflict"]
278
+ ]],
279
+ ["update-ref-delete", [
280
+ [GitErrors.refBadName, "invalidRef"],
281
+ [GitErrors.refNotAValidSha, "invalidObject"],
282
+ [GitErrors.refUnableToResolve, "notFound"],
283
+ [GitErrors.refValueMismatch, "conflict"],
284
+ [GitErrors.cantLockRef, "conflict"]
285
+ ]],
258
286
  ["worktree-create", [[GitErrors.alreadyCheckedOut, "alreadyCheckedOut"], [GitErrors.alreadyExists, "alreadyExists"]]],
259
287
  ["worktree-delete", [
260
288
  [GitErrors.worktreeLocked, "locked"],
@@ -338,10 +366,50 @@ function classifySearchError(ex) {
338
366
  };
339
367
  if (/unknown revision/i.test(stderr)) return { reason: "invalidRef" };
340
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
+ }
341
409
  const emptyArray = Object.freeze([]);
342
410
  const emptyObj = Object.freeze({});
343
411
  const trailingNewlineRegex = /[\r|\n]+$/;
344
- const uniqueCounterForStdin = getScopedCounter();
412
+ const unsharedRunCounter = getScopedCounter();
345
413
  const uniqueCounterForStream = getScopedCounter();
346
414
  var Git = class {
347
415
  _locator;
@@ -354,25 +422,37 @@ var Git = class {
354
422
  _eventLoopMonitor = new EventLoopMonitor();
355
423
  /** Count of git commands currently in flight, across both the exec and streaming paths */
356
424
  _activeCommandCount = 0;
357
- /** 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 */
358
426
  _baseEnv;
359
427
  /** Cached full environment: base + dynamic getEnvironment() result */
360
428
  _fullEnv;
361
429
  /** Last dynamic env reference, used to detect when getEnvironment() returns a new object */
362
430
  _lastDynamicEnv;
431
+ /** Bound via {@link bindChangeNotifier}; announces a `notify`-flagged run's changes. No-op until bound. */
432
+ _changeNotifier;
363
433
  constructor(_locator, options = {}) {
364
434
  this._locator = _locator;
365
435
  this.options = options;
366
436
  this._queue = new GitQueue(options.queue, { onSlowQueue: options.hooks?.onSlowQueue });
367
437
  }
368
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
+ /**
369
449
  * Returns the base environment for git commands. Cached to avoid spreading
370
450
  * process.env (30-100+ keys) on every call. Includes static options.env and
371
451
  * GCM/LC_ALL vars but NOT dynamic getEnvironment() or per-call env overrides.
372
452
  */
373
453
  getBaseEnv() {
374
454
  return this._baseEnv ??= {
375
- ...process.env,
455
+ ...getInheritedEnv(),
376
456
  ...this.options.env ?? emptyObj,
377
457
  GCM_INTERACTIVE: "NEVER",
378
458
  GCM_PRESERVE_CREDS: "TRUE",
@@ -409,9 +489,20 @@ var Git = class {
409
489
  this._queue.dispose();
410
490
  this._eventLoopMonitor.dispose();
411
491
  }
412
- /** Clear pending commands (e.g. on cache reset) */
413
- clearPendingCommands() {
414
- this.pendingCommands.clear();
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
+ }
415
506
  }
416
507
  /** Marks one more git command as in flight; starts the event-loop monitor on the first. */
417
508
  beginActiveCommand() {
@@ -466,21 +557,61 @@ var Git = class {
466
557
  async run(options, ...args) {
467
558
  if (this.options.isTrusted?.() === false) throw new WorkspaceUntrustedError();
468
559
  const runArgs = args.filter((a) => a != null);
469
- const gitCommand = `git ${runArgs.join(" ")}`;
470
- if (options.caching != null) return options.caching.cache.getOrCreate(options.caching.commonPath ?? options.cwd, gitCommand, async (cacheable, signal) => {
471
- const result = await this.runCore({
560
+ if (options.notify != null) try {
561
+ return await this.run({
472
562
  ...options,
473
- caching: void 0,
474
- cancellation: signal ?? options.cancellation
475
- }, runArgs, gitCommand);
476
- if (result.completion.status !== "exited" || result.exitCode !== 0 || signal?.aborted) cacheable.invalidate();
477
- return result;
478
- }, {
479
- ...options.caching.options,
480
- cancellation: options.cancellation
481
- });
563
+ notify: void 0
564
+ }, ...args);
565
+ } finally {
566
+ this.applyNotify(options, runArgs);
567
+ }
568
+ const gitCommand = `git ${runArgs.join(" ")}`;
569
+ if (options.caching != null) {
570
+ const cachePath = options.caching.commonPath ?? options.cwd;
571
+ if (options.caching.force) options.caching.cache.delete(cachePath, gitCommand);
572
+ return options.caching.cache.getOrCreate(cachePath, gitCommand, async (cacheable, signal) => {
573
+ const result = await this.runCore({
574
+ ...options,
575
+ caching: void 0,
576
+ cancellation: signal ?? options.cancellation
577
+ }, runArgs, gitCommand);
578
+ if (result.completion.status !== "exited" || result.exitCode !== 0 || signal?.aborted) cacheable.invalidate();
579
+ return result;
580
+ }, {
581
+ ...options.caching.options,
582
+ cancellation: options.cancellation
583
+ });
584
+ }
482
585
  return this.runCore(options, runArgs, gitCommand);
483
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
+ }
484
615
  async runCore(options, args, gitCommand) {
485
616
  const start = hrtime();
486
617
  const startEpochMs = Date.now();
@@ -495,15 +626,19 @@ var Git = class {
495
626
  env: this.buildEnv(options.env),
496
627
  quiet: errorHandling === "ignore"
497
628
  };
498
- const cacheKey = `${correlationKey !== void 0 ? `${correlationKey}:` : ""}${options?.stdin != null ? `${uniqueCounterForStdin.next()}:` : ""}${cancellation != null ? `${getAbortSignalId(cancellation)}:` : ""}${gitCommand}`;
629
+ const unshared = options?.stdin != null || options?.env != null && Object.keys(options.env).length > 0;
630
+ const cacheKey = `${correlationKey !== void 0 ? `${correlationKey}:` : ""}${unshared ? `${unsharedRunCounter.next()}:` : ""}${cancellation != null ? `${getAbortSignalId(cancellation)}:` : ""}${gitCommand}`;
499
631
  let execStart;
500
632
  let waiting;
501
- let promise = this.pendingCommands.get(cacheKey);
633
+ let promise = this.pendingCommands.get(cacheKey)?.promise;
502
634
  if (promise == null) {
503
635
  waiting = false;
504
636
  const deferred = defer();
505
637
  promise = deferred.promise;
506
- this.pendingCommands.set(cacheKey, promise);
638
+ this.pendingCommands.set(cacheKey, {
639
+ cwd: options.cwd,
640
+ promise
641
+ });
507
642
  args.unshift("-c", "core.quotepath=false", "-c", "color.ui=false", ...configs ?? emptyArray);
508
643
  if (process.platform === "win32") args.unshift("-c", "core.longpaths=true");
509
644
  if (cancellation != null) runOpts.cancellation = cancellation;
@@ -513,7 +648,7 @@ var Git = class {
513
648
  execStart = hrtime();
514
649
  return runSpawn(gitPath, args, encoding ?? "utf8", runOpts);
515
650
  }, cancellation).then(deferred.fulfill, (e) => deferred.cancel(e instanceof Error ? e : new Error(String(e)))).finally(() => {
516
- this.pendingCommands.delete(cacheKey);
651
+ if (this.pendingCommands.get(cacheKey)?.promise === deferred.promise) this.pendingCommands.delete(cacheKey);
517
652
  }).catch(() => {});
518
653
  } else {
519
654
  waiting = true;
@@ -594,7 +729,7 @@ var Git = class {
594
729
  }
595
730
  };
596
731
  }
597
- if (ex instanceof CancelledRunError) exception = new CancellationError(ex);
732
+ if (ex instanceof CancelledRunError || !(ex instanceof RunError) && cancellation?.aborted) exception = new CancellationError(ex instanceof Error ? ex : void 0);
598
733
  else exception = new GitError(ex);
599
734
  if (errorHandling === "throw") throw exception;
600
735
  const swallowed = exception;
@@ -719,10 +854,10 @@ var Git = class {
719
854
  }, "rev-parse", "--git-dir", "--git-common-dir");
720
855
  if (!result.stdout) return void 0;
721
856
  let [dotGitPath, commonDotGitPath] = result.stdout.split("\n").map((r) => r.trimStart());
722
- if (!isAbsolute(dotGitPath)) dotGitPath = joinPaths(cwd, dotGitPath);
857
+ if (!isAbsolute$1(dotGitPath)) dotGitPath = joinPaths(cwd, dotGitPath);
723
858
  dotGitPath = normalizePath(dotGitPath);
724
859
  if (commonDotGitPath) {
725
- if (!isAbsolute(commonDotGitPath)) commonDotGitPath = joinPaths(cwd, commonDotGitPath);
860
+ if (!isAbsolute$1(commonDotGitPath)) commonDotGitPath = joinPaths(cwd, commonDotGitPath);
726
861
  commonDotGitPath = normalizePath(commonDotGitPath);
727
862
  return {
728
863
  path: dotGitPath,
@@ -776,7 +911,7 @@ var Git = class {
776
911
  let exists = inDotGit ? false : await fsExists(cwd);
777
912
  if (!exists) {
778
913
  do {
779
- const parent = dirname(cwd);
914
+ const parent = dirname$1(cwd);
780
915
  if (parent === cwd || parent.length === 0) return emptyArray;
781
916
  cwd = parent;
782
917
  exists = await fsExists(cwd);